summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Readme.pod25
-rw-r--r--doc/doc-docbook/Makefile4
-rw-r--r--doc/doc-docbook/Markup.txt4
-rw-r--r--doc/doc-docbook/spec.xfpt337
-rw-r--r--doc/doc-src/FAQ.src4
-rw-r--r--doc/doc-txt/ChangeLog134
-rw-r--r--doc/doc-txt/NewStuff40
-rw-r--r--doc/doc-txt/OptionLists.txt2
-rw-r--r--doc/doc-txt/experimental-spec.txt4
-rw-r--r--src/Makefile3
-rw-r--r--src/OS/Makefile-Base170
-rw-r--r--src/OS/os.c-FreeBSD24
-rw-r--r--src/OS/os.c-Linux12
-rw-r--r--src/OS/os.h-FreeBSD27
-rw-r--r--src/OS/os.h-Linux15
-rw-r--r--src/OS/unsupported/Makefile-AIX (renamed from src/OS/Makefile-AIX)0
-rw-r--r--src/OS/unsupported/Makefile-BSDI (renamed from src/OS/Makefile-BSDI)0
-rw-r--r--src/OS/unsupported/Makefile-CYGWIN (renamed from src/OS/Makefile-CYGWIN)0
-rw-r--r--src/OS/unsupported/Makefile-DGUX (renamed from src/OS/Makefile-DGUX)0
-rw-r--r--src/OS/unsupported/Makefile-Darwin (renamed from src/OS/Makefile-Darwin)0
-rw-r--r--src/OS/unsupported/Makefile-DragonFly (renamed from src/OS/Makefile-DragonFly)0
-rw-r--r--src/OS/unsupported/Makefile-GNU (renamed from src/OS/Makefile-GNU)0
-rw-r--r--src/OS/unsupported/Makefile-GNUkFreeBSD (renamed from src/OS/Makefile-GNUkFreeBSD)0
-rw-r--r--src/OS/unsupported/Makefile-GNUkNetBSD (renamed from src/OS/Makefile-GNUkNetBSD)0
-rw-r--r--src/OS/unsupported/Makefile-HI-OSF (renamed from src/OS/Makefile-HI-OSF)0
-rw-r--r--src/OS/unsupported/Makefile-HI-UX (renamed from src/OS/Makefile-HI-UX)0
-rw-r--r--src/OS/unsupported/Makefile-HP-UX (renamed from src/OS/Makefile-HP-UX)0
-rw-r--r--src/OS/unsupported/Makefile-HP-UX-9 (renamed from src/OS/Makefile-HP-UX-9)0
-rw-r--r--src/OS/unsupported/Makefile-IRIX (renamed from src/OS/Makefile-IRIX)0
-rw-r--r--src/OS/unsupported/Makefile-IRIX6 (renamed from src/OS/Makefile-IRIX6)0
-rw-r--r--src/OS/unsupported/Makefile-IRIX632 (renamed from src/OS/Makefile-IRIX632)0
-rw-r--r--src/OS/unsupported/Makefile-IRIX65 (renamed from src/OS/Makefile-IRIX65)0
-rw-r--r--src/OS/unsupported/Makefile-NetBSD (renamed from src/OS/Makefile-NetBSD)0
-rw-r--r--src/OS/unsupported/Makefile-NetBSD-a.out (renamed from src/OS/Makefile-NetBSD-a.out)0
-rw-r--r--src/OS/unsupported/Makefile-OSF1 (renamed from src/OS/Makefile-OSF1)0
-rw-r--r--src/OS/unsupported/Makefile-OpenUNIX (renamed from src/OS/Makefile-OpenUNIX)0
-rw-r--r--src/OS/unsupported/Makefile-QNX (renamed from src/OS/Makefile-QNX)0
-rw-r--r--src/OS/unsupported/Makefile-SCO (renamed from src/OS/Makefile-SCO)0
-rw-r--r--src/OS/unsupported/Makefile-SCO_SV (renamed from src/OS/Makefile-SCO_SV)0
-rw-r--r--src/OS/unsupported/Makefile-SunOS4 (renamed from src/OS/Makefile-SunOS4)0
-rw-r--r--src/OS/unsupported/Makefile-SunOS5-hal (renamed from src/OS/Makefile-SunOS5-hal)0
-rw-r--r--src/OS/unsupported/Makefile-ULTRIX (renamed from src/OS/Makefile-ULTRIX)0
-rw-r--r--src/OS/unsupported/Makefile-UNIX_SV (renamed from src/OS/Makefile-UNIX_SV)0
-rw-r--r--src/OS/unsupported/Makefile-USG (renamed from src/OS/Makefile-USG)0
-rw-r--r--src/OS/unsupported/Makefile-Unixware7 (renamed from src/OS/Makefile-Unixware7)0
-rw-r--r--src/OS/unsupported/Makefile-mips (renamed from src/OS/Makefile-mips)0
-rw-r--r--src/OS/unsupported/README14
-rw-r--r--src/OS/unsupported/os.c-BSDI (renamed from src/OS/os.c-BSDI)4
-rw-r--r--src/OS/unsupported/os.c-GNU (renamed from src/OS/os.c-GNU)0
-rw-r--r--src/OS/unsupported/os.c-HI-OSF (renamed from src/OS/os.c-HI-OSF)0
-rw-r--r--src/OS/unsupported/os.c-HP-UX (renamed from src/OS/os.c-HP-UX)0
-rw-r--r--src/OS/unsupported/os.c-IRIX (renamed from src/OS/os.c-IRIX)2
-rw-r--r--src/OS/unsupported/os.c-IRIX6 (renamed from src/OS/os.c-IRIX6)2
-rw-r--r--src/OS/unsupported/os.c-IRIX632 (renamed from src/OS/os.c-IRIX632)2
-rw-r--r--src/OS/unsupported/os.c-IRIX65 (renamed from src/OS/os.c-IRIX65)2
-rw-r--r--src/OS/unsupported/os.c-OSF1 (renamed from src/OS/os.c-OSF1)0
-rw-r--r--src/OS/unsupported/os.c-cygwin (renamed from src/OS/os.c-cygwin)0
-rw-r--r--src/OS/unsupported/os.h-AIX (renamed from src/OS/os.h-AIX)0
-rw-r--r--src/OS/unsupported/os.h-BSDI (renamed from src/OS/os.h-BSDI)0
-rw-r--r--src/OS/unsupported/os.h-DGUX (renamed from src/OS/os.h-DGUX)0
-rw-r--r--src/OS/unsupported/os.h-Darwin (renamed from src/OS/os.h-Darwin)0
-rw-r--r--src/OS/unsupported/os.h-DragonFly (renamed from src/OS/os.h-DragonFly)0
-rw-r--r--src/OS/unsupported/os.h-GNU (renamed from src/OS/os.h-GNU)0
-rw-r--r--src/OS/unsupported/os.h-GNUkFreeBSD (renamed from src/OS/os.h-GNUkFreeBSD)0
-rw-r--r--src/OS/unsupported/os.h-GNUkNetBSD (renamed from src/OS/os.h-GNUkNetBSD)0
-rw-r--r--src/OS/unsupported/os.h-HI-OSF (renamed from src/OS/os.h-HI-OSF)0
-rw-r--r--src/OS/unsupported/os.h-HI-UX (renamed from src/OS/os.h-HI-UX)0
-rw-r--r--src/OS/unsupported/os.h-HP-UX (renamed from src/OS/os.h-HP-UX)0
-rw-r--r--src/OS/unsupported/os.h-HP-UX-9 (renamed from src/OS/os.h-HP-UX-9)0
-rw-r--r--src/OS/unsupported/os.h-IRIX (renamed from src/OS/os.h-IRIX)0
-rw-r--r--src/OS/unsupported/os.h-IRIX6 (renamed from src/OS/os.h-IRIX6)0
-rw-r--r--src/OS/unsupported/os.h-IRIX632 (renamed from src/OS/os.h-IRIX632)0
-rw-r--r--src/OS/unsupported/os.h-IRIX65 (renamed from src/OS/os.h-IRIX65)0
-rw-r--r--src/OS/unsupported/os.h-NetBSD (renamed from src/OS/os.h-NetBSD)0
-rw-r--r--src/OS/unsupported/os.h-NetBSD-a.out (renamed from src/OS/os.h-NetBSD-a.out)0
-rw-r--r--src/OS/unsupported/os.h-OSF1 (renamed from src/OS/os.h-OSF1)0
-rw-r--r--src/OS/unsupported/os.h-OpenUNIX (renamed from src/OS/os.h-OpenUNIX)0
-rw-r--r--src/OS/unsupported/os.h-QNX (renamed from src/OS/os.h-QNX)0
-rw-r--r--src/OS/unsupported/os.h-SCO (renamed from src/OS/os.h-SCO)0
-rw-r--r--src/OS/unsupported/os.h-SCO_SV (renamed from src/OS/os.h-SCO_SV)0
-rw-r--r--src/OS/unsupported/os.h-SunOS4 (renamed from src/OS/os.h-SunOS4)0
-rw-r--r--src/OS/unsupported/os.h-SunOS5-hal (renamed from src/OS/os.h-SunOS5-hal)0
-rw-r--r--src/OS/unsupported/os.h-ULTRIX (renamed from src/OS/os.h-ULTRIX)0
-rw-r--r--src/OS/unsupported/os.h-UNIX_SV (renamed from src/OS/os.h-UNIX_SV)0
-rw-r--r--src/OS/unsupported/os.h-USG (renamed from src/OS/os.h-USG)0
-rw-r--r--src/OS/unsupported/os.h-Unixware7 (renamed from src/OS/os.h-Unixware7)0
-rw-r--r--src/OS/unsupported/os.h-cygwin (renamed from src/OS/os.h-cygwin)0
-rw-r--r--src/OS/unsupported/os.h-mips (renamed from src/OS/os.h-mips)0
-rw-r--r--src/exim_monitor/em_globals.c2
-rw-r--r--src/exim_monitor/em_hdr.h1
-rw-r--r--src/exim_monitor/em_log.c8
-rw-r--r--src/exim_monitor/em_main.c2
-rw-r--r--src/exim_monitor/em_menu.c22
-rw-r--r--src/exim_monitor/em_queue.c16
-rw-r--r--src/exim_monitor/em_version.c2
-rwxr-xr-xsrc/scripts/Configure-Makefile1
-rwxr-xr-xsrc/scripts/MakeLinks8
-rwxr-xr-xsrc/scripts/reversion34
-rw-r--r--src/src/EDITME1
-rw-r--r--src/src/acl.c495
-rw-r--r--src/src/auths/auth-spa.c46
-rw-r--r--src/src/auths/call_pam.c2
-rw-r--r--src/src/auths/cram_md5.c32
-rw-r--r--src/src/auths/cyrus_sasl.c15
-rw-r--r--src/src/auths/dovecot.c18
-rw-r--r--src/src/auths/get_data.c2
-rw-r--r--src/src/auths/get_no64_data.c2
-rw-r--r--src/src/auths/gsasl_exim.c43
-rw-r--r--src/src/auths/heimdal_gssapi.c15
-rw-r--r--src/src/auths/md5.c2
-rw-r--r--src/src/auths/plaintext.c35
-rw-r--r--src/src/auths/pwcheck.c12
-rw-r--r--src/src/auths/spa.c220
-rw-r--r--src/src/auths/tls.c14
-rw-r--r--src/src/auths/xtextencode.c14
-rw-r--r--src/src/base64.c2
-rw-r--r--src/src/bmi_spam.c26
-rw-r--r--src/src/config.h.defaults7
-rw-r--r--src/src/daemon.c204
-rw-r--r--src/src/dane-openssl.c12
-rw-r--r--src/src/dbfn.c62
-rw-r--r--src/src/dbstuff.h199
-rw-r--r--src/src/dcc.c6
-rw-r--r--src/src/debug.c18
-rw-r--r--src/src/deliver.c962
-rw-r--r--src/src/dkim.c354
-rw-r--r--src/src/dkim.h2
-rw-r--r--src/src/dkim_transport.c365
-rw-r--r--src/src/dmarc.c10
-rw-r--r--src/src/dns.c7
-rw-r--r--src/src/drtables.c406
-rw-r--r--src/src/exigrep.src139
-rw-r--r--src/src/exim.c235
-rw-r--r--src/src/exim.h5
-rw-r--r--src/src/exim_dbmbuild.c8
-rw-r--r--src/src/exim_dbutil.c54
-rw-r--r--src/src/eximstats.src36
-rw-r--r--src/src/exipick.src13
-rw-r--r--src/src/expand.c99
-rw-r--r--src/src/filter.c33
-rw-r--r--src/src/functions.h67
-rw-r--r--src/src/globals.c528
-rw-r--r--src/src/globals.h26
-rw-r--r--src/src/hash.c61
-rw-r--r--src/src/hash.h11
-rw-r--r--src/src/host.c31
-rw-r--r--src/src/ip.c59
-rw-r--r--src/src/local_scan.h4
-rw-r--r--src/src/log.c63
-rw-r--r--src/src/lookups/cdb.c4
-rw-r--r--src/src/lookups/dbmdb.c6
-rw-r--r--src/src/lookups/dnsdb.c2
-rw-r--r--src/src/lookups/ibase.c18
-rw-r--r--src/src/lookups/lmdb.c2
-rw-r--r--src/src/lookups/mysql.c1
-rw-r--r--src/src/lookups/sqlite.c4
-rw-r--r--src/src/macro_predef.c279
-rw-r--r--src/src/macro_predef.h18
-rw-r--r--src/src/macros.h46
-rw-r--r--src/src/malware.c155
-rw-r--r--src/src/match.c21
-rw-r--r--src/src/mime.c27
-rw-r--r--src/src/mytypes.h6
-rw-r--r--src/src/os.c27
-rw-r--r--src/src/parse.c15
-rw-r--r--src/src/pdkim/Makefile4
-rw-r--r--src/src/pdkim/crypt_ver.h8
-rw-r--r--src/src/pdkim/pdkim.c676
-rw-r--r--src/src/pdkim/pdkim.h60
-rw-r--r--src/src/pdkim/pdkim_hash.h4
-rw-r--r--src/src/pdkim/signing.c (renamed from src/src/pdkim/rsa.c)253
-rw-r--r--src/src/pdkim/signing.h (renamed from src/src/pdkim/rsa.h)34
-rw-r--r--src/src/perl.c2
-rw-r--r--src/src/queue.c40
-rw-r--r--src/src/rda.c20
-rw-r--r--src/src/readconf.c697
-rw-r--r--src/src/receive.c196
-rw-r--r--src/src/regex.c2
-rw-r--r--src/src/retry.c44
-rw-r--r--src/src/rfc2047.c14
-rw-r--r--src/src/route.c19
-rw-r--r--src/src/routers/accept.c13
-rw-r--r--src/src/routers/dnslookup.c17
-rw-r--r--src/src/routers/ipliteral.c12
-rw-r--r--src/src/routers/iplookup.c19
-rw-r--r--src/src/routers/manualroute.c18
-rw-r--r--src/src/routers/queryprogram.c19
-rw-r--r--src/src/routers/redirect.c29
-rw-r--r--src/src/routers/rf_get_errors_address.c2
-rw-r--r--src/src/routers/rf_get_munge_headers.c6
-rw-r--r--src/src/routers/rf_queue_add.c12
-rw-r--r--src/src/sieve.c30
-rw-r--r--src/src/smtp_in.c464
-rw-r--r--src/src/smtp_out.c110
-rw-r--r--src/src/spam.c53
-rw-r--r--src/src/spf.c29
-rw-r--r--src/src/spool_in.c21
-rw-r--r--src/src/spool_mbox.c90
-rw-r--r--src/src/spool_out.c31
-rw-r--r--src/src/std-crypto.c41
-rw-r--r--src/src/store.c8
-rw-r--r--src/src/string.c127
-rw-r--r--src/src/structs.h113
-rw-r--r--src/src/tls-gnu.c238
-rw-r--r--src/src/tls-openssl.c295
-rw-r--r--src/src/tls.c3
-rw-r--r--src/src/tlscert-gnu.c30
-rw-r--r--src/src/tlscert-openssl.c24
-rw-r--r--src/src/tod.c260
-rw-r--r--src/src/transport.c698
-rw-r--r--src/src/transports/appendfile.c115
-rw-r--r--src/src/transports/appendfile.h2
-rw-r--r--src/src/transports/autoreply.c186
-rw-r--r--src/src/transports/lmtp.c17
-rw-r--r--src/src/transports/pipe.c27
-rw-r--r--src/src/transports/queuefile.c15
-rw-r--r--src/src/transports/smtp.c721
-rw-r--r--src/src/transports/smtp.h1
-rw-r--r--src/src/transports/smtp_socks.c18
-rw-r--r--src/src/transports/tf_maildir.c10
-rw-r--r--src/src/utf8.c5
-rw-r--r--src/src/verify.c257
-rw-r--r--src/src/version.c11
-rw-r--r--test/confs/00212
-rw-r--r--test/confs/02117
-rw-r--r--test/confs/02272
-rw-r--r--test/confs/05473
-rw-r--r--test/confs/058046
l---------test/confs/05811
l---------test/confs/05821
-rw-r--r--test/confs/090697
-rw-r--r--test/confs/09073
-rw-r--r--test/confs/09081
-rw-r--r--test/confs/199048
-rw-r--r--test/confs/20071
-rw-r--r--test/confs/201311
-rw-r--r--test/confs/203577
l---------test/confs/20361
l---------test/confs/20371
-rw-r--r--test/confs/203863
-rw-r--r--test/confs/205267
-rw-r--r--test/confs/21071
-rw-r--r--test/confs/211310
-rw-r--r--test/confs/213577
l---------test/confs/21361
l---------test/confs/21371
-rw-r--r--test/confs/213864
-rw-r--r--test/confs/215268
-rw-r--r--test/confs/401229
-rw-r--r--test/confs/402011
l---------test/confs/40271
l---------test/confs/45031
-rw-r--r--test/confs/452012
l---------test/confs/45231
l---------test/confs/45241
l---------test/confs/45301
-rw-r--r--test/confs/501035
-rw-r--r--test/confs/501135
-rw-r--r--test/confs/501235
-rw-r--r--test/confs/56012
-rw-r--r--test/confs/57404
-rw-r--r--test/confs/58404
-rw-r--r--test/dnszones-src/db.test.ex22
-rw-r--r--test/lib/Exim/Runtest.pm2
-rw-r--r--test/log/02118
-rw-r--r--test/log/02273
-rw-r--r--test/log/03764
-rw-r--r--test/log/04291
-rw-r--r--test/log/05062
-rw-r--r--test/log/05479
-rw-r--r--test/log/055110
-rw-r--r--test/log/05784
-rw-r--r--test/log/058015
-rw-r--r--test/log/058123
-rw-r--r--test/log/05823
-rw-r--r--test/log/06092
-rw-r--r--test/log/09012
-rw-r--r--test/log/090612
-rw-r--r--test/log/199015
-rw-r--r--test/log/201329
-rw-r--r--test/log/203511
-rw-r--r--test/log/203614
-rw-r--r--test/log/20378
-rw-r--r--test/log/203842
-rw-r--r--test/log/205212
-rw-r--r--test/log/20912
-rw-r--r--test/log/211329
-rw-r--r--test/log/213511
-rw-r--r--test/log/213614
-rw-r--r--test/log/21378
-rw-r--r--test/log/213842
-rw-r--r--test/log/21529
-rw-r--r--test/log/21912
-rw-r--r--test/log/34544
-rw-r--r--test/log/34644
-rw-r--r--test/log/40276
-rw-r--r--test/log/42031
-rw-r--r--test/log/42131
-rw-r--r--test/log/42231
-rw-r--r--test/log/45003
-rw-r--r--test/log/45036
-rw-r--r--test/log/45063
-rw-r--r--test/log/45205
-rw-r--r--test/log/45214
-rw-r--r--test/log/452312
-rw-r--r--test/log/452412
-rw-r--r--test/log/453021
-rw-r--r--test/log/47002
-rw-r--r--test/log/50022
-rw-r--r--test/log/501012
-rw-r--r--test/log/501118
-rw-r--r--test/log/50126
-rw-r--r--test/log/560118
-rw-r--r--test/log/574030
-rw-r--r--test/log/584023
-rw-r--r--test/mail/0906.a109
-rw-r--r--test/mail/2013.usera18
-rw-r--r--test/mail/2013.userb18
-rw-r--r--test/mail/2013.userc18
-rw-r--r--test/mail/2038.userx017
-rw-r--r--test/mail/2038.userx117
-rw-r--r--test/mail/2038.usery017
-rw-r--r--test/mail/2038.usery117
-rw-r--r--test/mail/2038.userz017
-rw-r--r--test/mail/2038.userz117
-rw-r--r--test/mail/2113.usera18
-rw-r--r--test/mail/2113.userb18
-rw-r--r--test/mail/2113.userc18
-rw-r--r--test/mail/2138.userx017
-rw-r--r--test/mail/2138.userx117
-rw-r--r--test/mail/2138.usery017
-rw-r--r--test/mail/2138.usery117
-rw-r--r--test/mail/2138.userz017
-rw-r--r--test/mail/2138.userz117
-rw-r--r--test/mail/4530.y26
-rw-r--r--test/mail/4530.z26
-rw-r--r--test/mail/5010.maildirsize2
-rw-r--r--test/mail/5010.new/1.myhost.test.ex17
-rw-r--r--test/mail/5011.maildirsize2
-rw-r--r--test/mail/5012.maildirsize3
-rw-r--r--test/mail/5012.new/1.myhost.test.ex17
-rw-r--r--test/mail/5012.new/2.myhost.test.ex28
-rw-r--r--test/paniclog/00218
-rw-r--r--test/rejectlog/02273
-rw-r--r--test/rejectlog/03764
-rw-r--r--test/rejectlog/05784
-rw-r--r--test/rejectlog/05821
-rw-r--r--test/rejectlog/09012
-rw-r--r--test/rejectlog/203720
-rw-r--r--test/rejectlog/213720
-rwxr-xr-xtest/runtest31
-rw-r--r--test/scripts/0000-Basic/00023
-rw-r--r--test/scripts/0000-Basic/021119
-rw-r--r--test/scripts/0000-Basic/022784
-rw-r--r--test/scripts/0000-Basic/05475
-rw-r--r--test/scripts/0000-Basic/05517
-rw-r--r--test/scripts/0000-Basic/0580156
-rw-r--r--test/scripts/0000-Basic/0581264
-rw-r--r--test/scripts/0000-Basic/058256
-rw-r--r--test/scripts/0000-Basic/09018
-rw-r--r--test/scripts/0000-Basic/0906124
-rw-r--r--test/scripts/0000-Basic/09074
l---------test/scripts/0000-Basic/09081
-rw-r--r--test/scripts/1990-TCP-Fast-Open/199045
-rw-r--r--test/scripts/1990-TCP-Fast-Open/REQUIRES1
-rw-r--r--test/scripts/2000-GnuTLS/201319
-rw-r--r--test/scripts/2000-GnuTLS/20314
-rw-r--r--test/scripts/2000-GnuTLS/203529
-rw-r--r--test/scripts/2000-GnuTLS/203676
-rw-r--r--test/scripts/2000-GnuTLS/203731
-rw-r--r--test/scripts/2000-GnuTLS/203819
-rw-r--r--test/scripts/2000-GnuTLS/205222
-rw-r--r--test/scripts/2000-GnuTLS/20908
-rw-r--r--test/scripts/2100-OpenSSL/211319
-rw-r--r--test/scripts/2100-OpenSSL/213528
-rw-r--r--test/scripts/2100-OpenSSL/213675
-rw-r--r--test/scripts/2100-OpenSSL/213730
-rw-r--r--test/scripts/2100-OpenSSL/213818
-rw-r--r--test/scripts/2100-OpenSSL/215221
-rw-r--r--test/scripts/2100-OpenSSL/21908
-rw-r--r--test/scripts/4000-scanning/401245
-rw-r--r--test/scripts/4020-socks/40203
-rw-r--r--test/scripts/4027-TFO-socks/402783
-rw-r--r--test/scripts/4027-TFO-socks/REQUIRES2
-rw-r--r--test/scripts/4500-DKIM/450034
-rw-r--r--test/scripts/4500-DKIM/450345
-rw-r--r--test/scripts/4500-DKIM/450635
-rw-r--r--test/scripts/4500-DKIM/45202
-rw-r--r--test/scripts/4500-DKIM/452315
-rw-r--r--test/scripts/4500-DKIM/452414
-rw-r--r--test/scripts/4500-DKIM/453068
-rw-r--r--test/scripts/4700-dsn-info/47006
-rw-r--r--test/scripts/5000-maildir/501035
l---------test/scripts/5000-maildir/50111
l---------test/scripts/5000-maildir/50121
-rw-r--r--test/scripts/5600-OCSP-OpenSSL/56012
-rw-r--r--test/scripts/5730-OCSP-GnuTLS-events/57304
-rw-r--r--test/scripts/5740-OCSP-OpenSSL-events/57408
-rw-r--r--test/scripts/5840-DANE-OpenSSL/584016
-rw-r--r--test/src/fakens.c26
-rw-r--r--test/src/server.c24
-rw-r--r--test/stderr/00042
-rw-r--r--test/stderr/002117
-rw-r--r--test/stderr/01431
-rw-r--r--test/stderr/01691
-rw-r--r--test/stderr/022767
-rw-r--r--test/stderr/027510
-rw-r--r--test/stderr/027810
-rw-r--r--test/stderr/036120
-rw-r--r--test/stderr/03768
-rw-r--r--test/stderr/038622
-rw-r--r--test/stderr/038825
-rw-r--r--test/stderr/03933
-rw-r--r--test/stderr/039815
-rw-r--r--test/stderr/040237
-rw-r--r--test/stderr/040315
-rw-r--r--test/stderr/040426
-rw-r--r--test/stderr/040811
-rw-r--r--test/stderr/043215
-rw-r--r--test/stderr/04761
-rw-r--r--test/stderr/048711
-rw-r--r--test/stderr/05122
-rw-r--r--test/stderr/05474
-rw-r--r--test/stderr/0551305
-rw-r--r--test/stderr/05788
-rw-r--r--test/stderr/06092
-rw-r--r--test/stderr/09072
-rw-r--r--test/stderr/09082
-rw-r--r--test/stderr/201383
-rw-r--r--test/stderr/203574
-rw-r--r--test/stderr/211383
-rw-r--r--test/stderr/213574
-rw-r--r--test/stderr/260011
-rw-r--r--test/stderr/34007
-rw-r--r--test/stderr/452019
-rw-r--r--test/stderr/500416
-rw-r--r--test/stderr/500552
-rw-r--r--test/stderr/500611
-rw-r--r--test/stderr/50082
-rw-r--r--test/stderr/54106
-rw-r--r--test/stderr/54206
-rw-r--r--test/stderr/584025
-rw-r--r--test/stdout/00023
-rw-r--r--test/stdout/00357
-rw-r--r--test/stdout/021110
-rw-r--r--test/stdout/022779
-rw-r--r--test/stdout/02451
-rw-r--r--test/stdout/02503
-rw-r--r--test/stdout/02543
-rw-r--r--test/stdout/03112
-rw-r--r--test/stdout/03381
-rw-r--r--test/stdout/03764
-rw-r--r--test/stdout/03771
-rw-r--r--test/stdout/03781
-rw-r--r--test/stdout/03791
-rw-r--r--test/stdout/03891
-rw-r--r--test/stdout/04881
-rw-r--r--test/stdout/04901
-rw-r--r--test/stdout/05141
-rw-r--r--test/stdout/055110
-rw-r--r--test/stdout/05784
-rw-r--r--test/stdout/09018
-rw-r--r--test/stdout/0906123
-rw-r--r--test/stdout/20908
-rw-r--r--test/stdout/21908
-rw-r--r--test/stdout/34155
-rw-r--r--test/stdout/402766
-rw-r--r--test/stdout/453075
-rw-r--r--test/stdout/584014
-rw-r--r--test/t/00-basic.t3
470 files changed, 12518 insertions, 5625 deletions
diff --git a/Readme.pod b/Readme.pod
index b82161e93..df75f8958 100644
--- a/Readme.pod
+++ b/Readme.pod
@@ -19,26 +19,25 @@ wiki document.
=head2 Development Repositories
-Exim development is kept within a git (L<http://git-scm.com/>)
+Exim development is kept within a git (L<https://git-scm.com/>)
repository. The master repository is at L<git://git.exim.org/exim.git>
with a web interface giving change and source visibility at
-L<http://git.exim.org/exim.git>
+L<https://git.exim.org/exim.git>
There is a secondary repository on github at
L<https://github.com/Exim/exim> managed by the Exim Organisation
-L<https://github.com/Exim> - however this may currently fall out of
-synchronisation with the main one. We intend to manage this better in
-the future, but it is currently early days for our github repo.
+- however this may currently fall out of synchronisation with the
+main one.
=head2 Bug Tracking
-Currently this is all done using Bugzilla at L<http://bugs.exim.org/>
+Currently this is all done using Bugzilla at L<https://bugs.exim.org/>
- please do not use github issue tracking.
=head2 Mailing List
Development issues are normally discussed on the exim-dev mailing list
-- see L<http://www.exim.org/maillist.html>
+- see L<https://www.exim.org/maillist.html>
=head2 Exim Release Process
@@ -48,19 +47,19 @@ L<http://wiki.exim.org/EximRelease>.
=head2 General Exim Information
The best place to get general information is on the website at
-L<http://www.exim.org/>.
+L<https://www.exim.org/>.
-You can find Download locations L<http://www.exim.org/mirrors.html>,
-Mailing list info L<http://www.exim.org/maillist.html> and Full
-Documentation L<http://www.exim.org/docs.html> on that website.
+You can find Download locations L<https://www.exim.org/mirrors.html>,
+Mailing list info L<https://www.exim.org/maillist.html> and Full
+Documentation L<https://www.exim.org/docs.html> on that website.
If you are using a Linux or other freely available Unix like operating
system it is very likely that your system will have Exim packaged for
it already. In this case it is probably prudent to use these packages
unless you have specialised requirements.
-In any case you can always ask on the
-Exim Users mailing list L<https://lists.exim.org/mailman/listinfo/exim-users>
+In any case you can always ask on the
+Exim Users mailing list L<https://lists.exim.org/mailman/listinfo/exim-users>
for further information.
[End]
diff --git a/doc/doc-docbook/Makefile b/doc/doc-docbook/Makefile
index d835db9ed..ee97257b6 100644
--- a/doc/doc-docbook/Makefile
+++ b/doc/doc-docbook/Makefile
@@ -96,6 +96,7 @@ filter.txt: filter-txt.xml Tidytxt MyStyle-txt-html.xsl MyStyle-html.xsl \
MyStyle.xsl
/bin/rm -rf filter-txt.html
xmlto -x MyStyle-txt-html.xsl html-nochunks filter-txt.xml
+ command -v w3m >/dev/null
LC_ALL=C w3m -dump filter-txt.html | ./Tidytxt >filter.txt
./SanityTestText filter.txt
@@ -181,9 +182,11 @@ spec.utf8: spec-txt.html Tidytxt
@grep -iq 'LC_CTYPE=.*utf-\?8' local_params || { \
echo 'your current locale does not support UTF-8' >&2; \
false; }
+ command -v w3m >/dev/null
w3m -dump $< | ./Tidytxt -utf8 >$@
spec.txt: spec-txt.html Tidytxt
+ command -v w3m >/dev/null
LC_ALL=C w3m -dump $< | ./Tidytxt >$@
./SanityTestText spec.txt
@@ -270,6 +273,7 @@ test.txt: test-txt.xml Tidytxt MyStyle-txt-html.xsl MyStyle-html.xsl \
MyStyle.xsl
/bin/rm -rf test-txt.html
xmlto -x MyStyle-txt-html.xsl html-nochunks test-txt.xml
+ command -v w3m >/dev/null
w3m -dump test-txt.html | Tidytxt >test.txt
# I have not found a way of making docbook2texi write its output anywhere
diff --git a/doc/doc-docbook/Markup.txt b/doc/doc-docbook/Markup.txt
index 9f591955f..58116a792 100644
--- a/doc/doc-docbook/Markup.txt
+++ b/doc/doc-docbook/Markup.txt
@@ -139,9 +139,9 @@ To refer to a URL, use &url, followed by parentheses that can enclose one or
two arguments, comma separated. The second, if present, is used as the
displayed text. If there is only one argument, it is used both as the displayed
text and as the URL. For example, here is a reference to
-&url(http://www.exim.org/,the exim home page). In HTML output, all you see is
+&url(https://www.exim.org/,the exim home page). In HTML output, all you see is
the display text; in printed output you see something like "the exim home page
-[http://www.exim.org/]". The URL is printed in a bold font.
+[https://www.exim.org/]". The URL is printed in a bold font.
CHAPTERS AND SECTIONS
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index be93cf670..4a8e1d06e 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -464,7 +464,7 @@ which contains what used to be a separate FAQ, as well as various other
examples, tips, and know-how that have been contributed by Exim users.
.cindex Bugzilla
-An Exim Bugzilla exists at &url(http://bugs.exim.org). You can use
+An Exim Bugzilla exists at &url(https://bugs.exim.org). You can use
this to report bugs, and also to add items to the wish list. Please search
first to check that you are not duplicating a previous entry.
@@ -493,18 +493,11 @@ via this web page:
Please ask Debian-specific questions on this list and not on the general Exim
lists.
-.section "Exim training" "SECID4"
-.cindex "training courses"
-Training courses in Cambridge (UK) used to be run annually by the author of
-Exim, before he retired. At the time of writing, there are no plans to run
-further Exim courses in Cambridge. However, if that changes, relevant
-information will be posted at &url(http://www-tus.csx.cam.ac.uk/courses/exim/).
-
.section "Bug reports" "SECID5"
.cindex "bug reports"
.cindex "reporting bugs"
Reports of obvious bugs can be emailed to &'bugs@exim.org'& or reported
-via the Bugzilla (&url(http://bugs.exim.org)). However, if you are unsure
+via the Bugzilla (&url(https://bugs.exim.org)). However, if you are unsure
whether some behaviour is a bug or not, the best thing to do is to post a
message to the &'exim-dev'& mailing list and have it discussed.
@@ -515,10 +508,6 @@ message to the &'exim-dev'& mailing list and have it discussed.
.cindex "distribution" "ftp site"
The master ftp site for the Exim distribution is
.display
-&*ftp://ftp.csx.cam.ac.uk/pub/software/email/exim*&
-.endd
-This is mirrored by
-.display
&*ftp://ftp.exim.org/pub/exim*&
.endd
The file references that follow are relative to the &_exim_& directories at
@@ -1678,6 +1667,9 @@ Symbolic links to the sources are installed in this directory, which is where
the actual building takes place. In most cases, Exim can discover the machine
architecture and operating system for itself, but the defaults can be
overridden if necessary.
+.cindex compiler requirements
+.cindex compiler version
+A C99-capable compiler will be required for the build.
.section "PCRE library" "SECTpcre"
@@ -3869,12 +3861,12 @@ by Exim in conjunction with the &%-MC%& option, and passes on the fact that the
host to which Exim is connected supports TLS encryption.
.new
-.vitem &%-MCt%&&~<&'IP&~address'&>&~<&'port'&>
+.vitem &%-MCt%&&~<&'IP&~address'&>&~<&'port'&>&~<&'cipher'&>
.oindex "&%-MCt%&"
This option is not intended for use by external callers. It is used internally
by Exim in conjunction with the &%-MC%& option, and passes on the fact that the
connection is being proxied by a parent process for handling TLS encryption.
-The pair of arguments give the local address and port being proxied.
+The arguments give the local address and port being proxied, and the TLS cipher.
.wen
.vitem &%-Mc%&&~<&'message&~id'&>&~<&'message&~id'&>&~...
@@ -4285,7 +4277,7 @@ or &%-bs%& is used. For &%-bh%&, the protocol is forced to one of the standard
SMTP protocol names (see the description of &$received_protocol$& in section
&<<SECTexpvar>>&). For &%-bs%&, the protocol is always &"local-"& followed by
one of those same names. For &%-bS%& (batched SMTP) however, the protocol can
-be set by &%-oMr%&.
+be set by &%-oMr%&. Repeated use of this option is not supported.
.vitem &%-oMs%&&~<&'host&~name'&>
.oindex "&%-oMs%&"
@@ -4385,6 +4377,7 @@ host name and its colon can be omitted when only the protocol is to be set.
Note the Exim already has two private options, &%-pd%& and &%-ps%&, that refer
to embedded Perl. It is therefore impossible to set a protocol value of &`d`&
or &`s`& using this option (but that does not seem a real limitation).
+Repeated use of this option is not supported.
.vitem &%-q%&
.oindex "&%-q%&"
@@ -11042,9 +11035,14 @@ colon-separated components are permitted, each containing from one to four
hexadecimal digits. There may be fewer than eight components if an empty
component (adjacent colons) is present. Only one empty component is permitted.
-&*Note*&: The checks are just on the form of the address; actual numerical
-values are not considered. Thus, for example, 999.999.999.999 passes the IPv4
-check. The main use of these tests is to distinguish between IP addresses and
+.new
+&*Note*&: The checks used to be just on the form of the address; actual numerical
+values were not considered. Thus, for example, 999.999.999.999 passed the IPv4
+check.
+This is no longer the case.
+.wen
+
+The main use of these tests is to distinguish between IP addresses and
host names, or between IPv4 and IPv6 addresses. For example, you could use
.code
${if isip4{$sender_host_address}...
@@ -11201,8 +11199,8 @@ example is:
${if match_domain{a.b.c}{x.y.z:a.b.c:p.q.r}{yes}{no}}
.endd
In each case, the second argument may contain any of the allowable items for a
-list of the appropriate type. Also, because the second argument (after
-expansion) is a standard form of list, it is possible to refer to a named list.
+list of the appropriate type. Also, because the second argument
+is a standard form of list, it is possible to refer to a named list.
Thus, you can use conditions like this:
.code
${if match_domain{$domain}{+local_domains}{...
@@ -12073,6 +12071,9 @@ when the ACL &%malware%& condition is true (see section &<<SECTscanvirus>>&).
This variable contains the number of bytes in the longest line that was
received as part of the message, not counting the line termination
character(s).
+.new
+It is not valid if the &%spool_files_wireformat%& option is used.
+.wen
.vitem &$message_age$&
.cindex "message" "age of"
@@ -12115,6 +12116,12 @@ in bytes. The count starts from the character after the blank line that
separates the body from the header. Newlines are included in the count. See
also &$message_size$&, &$body_linecount$&, and &$body_zerocount$&.
+.new
+If the spool file is wireformat
+(see the &%spool_files_wireformat%& main option)
+the CRLF line-terminators are included in the count.
+.wen
+
.vitem &$message_exim_id$&
.vindex "&$message_exim_id$&"
When a message is being received or delivered, this variable contains the
@@ -12165,6 +12172,10 @@ deny message = Too many lines in message header
In the MAIL and RCPT ACLs, the value is zero because at that stage the
message has not yet been received.
+.new
+This variable is not valid if the &%spool_files_wireformat%& option is used.
+.wen
+
.vitem &$message_size$&
.cindex "size" "of message"
.cindex "message" "size"
@@ -12785,6 +12796,15 @@ argument, that is, the text that follows the command name, with leading white
space removed. Following the introduction of &$smtp_command$&, this variable is
somewhat redundant, but is retained for backwards compatibility.
+.new
+.vitem &$smtp_command_history$&
+.cindex SMTP "command history"
+.vindex "&$smtp_command_history$&"
+A comma-separated list (with no whitespace) of the most-recent SMTP commands
+received, in time-order left to right. Only a limited number of commands
+are remembered.
+.wen
+
.vitem &$smtp_count_at_connection_start$&
.vindex "&$smtp_count_at_connection_start$&"
This variable is set greater than zero only in processes spawned by the Exim
@@ -13572,6 +13592,7 @@ listed in more than one group.
.row &%message_body_visible%& "how much to show in &$message_body$&"
.row &%mua_wrapper%& "run in &""MUA wrapper""& mode"
.row &%print_topbitchars%& "top-bit characters are printing"
+.row &%spool_wireformat%& "use wire-format spool data files when possible"
.row &%timezone%& "force time zone"
.endtable
@@ -13591,6 +13612,7 @@ listed in more than one group.
.section "Privilege controls" "SECID98"
.table2
.row &%admin_groups%& "groups that are Exim admin users"
+.row &%commandline_checks_require_admin%& "require admin for various checks"
.row &%deliver_drop_privilege%& "drop root for delivery processes"
.row &%local_from_check%& "insert &'Sender:'& if necessary"
.row &%local_from_prefix%& "for testing &'From:'& for local sender"
@@ -14453,6 +14475,14 @@ The CHUNKING extension (RFC3030) will be advertised in the EHLO message to
these hosts.
Hosts may use the BDAT command as an alternate to DATA.
+.new
+.option commandline_checks_require_admin main boolean &`false`&
+.cindex "restricting access to features"
+This option restricts various basic checking features to require an
+administrative user.
+This affects most of the &%-b*%& options, such as &%-be%&.
+.wen
+
.option debug_store main boolean &`false`&
.cindex debugging "memory corruption"
.cindex memory debugging
@@ -15685,7 +15715,7 @@ harm. This option overrides the &%pipe_as_creator%& option of the &(pipe)&
transport driver.
-.option openssl_options main "string list" "+no_sslv2 +single_dh_use"
+.option openssl_options main "string list" "+no_sslv2 +single_dh_use +no_ticket"
.cindex "OpenSSL "compatibility options"
This option allows an administrator to adjust the SSL options applied
by OpenSSL to connections. It is given as a space-separated list of items,
@@ -15934,12 +15964,13 @@ different spool directories.
.option prod_requires_admin main boolean true
+.cindex "restricting access to features"
.oindex "&%-M%&"
.oindex "&%-R%&"
.oindex "&%-q%&"
The &%-M%&, &%-R%&, and &%-q%& command-line options require the caller to be an
admin user unless &%prod_requires_admin%& is set false. See also
-&%queue_list_requires_admin%&.
+&%queue_list_requires_admin%& and &%commandline_checks_require_admin%&.
.option qualify_domain main string "see below"
@@ -15978,10 +16009,12 @@ next queue run. See also &%hold_domains%& and &%queue_smtp_domains%&.
.option queue_list_requires_admin main boolean true
+.cindex "restricting access to features"
.oindex "&%-bp%&"
The &%-bp%& command-line option, which lists the messages that are on the
queue, requires the caller to be an admin user unless
-&%queue_list_requires_admin%& is set false. See also &%prod_requires_admin%&.
+&%queue_list_requires_admin%& is set false.
+See also &%prod_requires_admin%& and &%commandline_checks_require_admin%&.
.option queue_only main boolean false
@@ -16827,6 +16860,32 @@ as failures in the configuration file.
By using this option to override the compiled-in path, it is possible to run
tests of Exim without using the standard spool.
+.new
+.option spool_wireformat main boolean false
+.cindex "spool directory" "file formats"
+If this option is set, Exim may for some messages use an alternate format
+for data-files in the spool which matches the wire format.
+Doing this permits more efficient message reception and transmission.
+Currently it is only done for messages received using the EMSTP CHUNKING
+option.
+
+The following variables will not have useful values:
+.code
+$max_received_linelength
+$body_linecount
+$body_zerocount
+.endd
+
+Users of the local_scan() API (see &<<CHAPlocalscan>>&),
+and any external programs which are passed a reference to a message data file
+(except via the &"regex"&, &"malware"& or &"spam"&) ACL conditions)
+will need to be aware of the potential different format.
+
+Using any of the ACL conditions noted will negate the reception benefit
+(as a Unix-mbox-format file is contructed for them).
+The transimssion benefit is maintained.
+.wen
+
.option sqlite_lock_timeout main time 5s
.cindex "sqlite lookup type" "lock timeout"
This option controls the timeout that the &(sqlite)& lookup uses when trying to
@@ -19422,6 +19481,10 @@ instead of TRY_AGAIN. That is why the default action is to try a DNS
lookup first. Only if that gives a definite &"no such host"& is the local
function called.
+&*Compatibility*&: From Exim 4.85 until fixed for 4.90, there was an
+inadvertent constraint that a transport name as an option had to be the last
+option specified.
+
If no IP address for a host can be found, what happens is controlled by the
@@ -20299,11 +20362,15 @@ relative path is then passed to the transport unmodified.
.option forbid_blackhole redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, the &':blackhole:'& item may not appear in a
redirection list.
.option forbid_exim_filter redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is set true, only Sieve filters are permitted when
&%allow_filter%& is true.
@@ -20311,7 +20378,9 @@ If this option is set true, only Sieve filters are permitted when
.option forbid_file redirect boolean false
+.cindex "restricting access to features"
.cindex "delivery" "to file; forbidding"
+.cindex "filter" "locking out certain features"
.cindex "Sieve filter" "forbidding delivery to a file"
.cindex "Sieve filter" "&""keep""& facility; disabling"
If this option is true, this router may not generate a new address that
@@ -20322,17 +20391,22 @@ locks out the Sieve's &"keep"& facility.
.option forbid_filter_dlfunc redirect boolean false
+.cindex "restricting access to features"
.cindex "filter" "locking out certain features"
If this option is true, string expansions in Exim filters are not allowed to
make use of the &%dlfunc%& expansion facility to run dynamically loaded
functions.
.option forbid_filter_existstest redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
.cindex "expansion" "statting a file"
If this option is true, string expansions in Exim filters are not allowed to
make use of the &%exists%& condition or the &%stat%& expansion item.
.option forbid_filter_logwrite redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, use of the logging facility in Exim filters is not
permitted. Logging is in any case available only if the filter is being run
under some unprivileged uid (which is normally the case for ordinary users'
@@ -20340,27 +20414,37 @@ under some unprivileged uid (which is normally the case for ordinary users'
.option forbid_filter_lookup redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, string expansions in Exim filter files are not allowed
to make use of &%lookup%& items.
.option forbid_filter_perl redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
This option has an effect only if Exim is built with embedded Perl support. If
it is true, string expansions in Exim filter files are not allowed to make use
of the embedded Perl support.
.option forbid_filter_readfile redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, string expansions in Exim filter files are not allowed
to make use of &%readfile%& items.
.option forbid_filter_readsocket redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, string expansions in Exim filter files are not allowed
to make use of &%readsocket%& items.
.option forbid_filter_reply redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, this router may not generate an automatic reply
message. Automatic replies can be generated only from Exim or Sieve filter
files, not from traditional forward files. This option is forced to be true if
@@ -20368,11 +20452,15 @@ files, not from traditional forward files. This option is forced to be true if
.option forbid_filter_run redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, string expansions in Exim filter files are not allowed
to make use of &%run%& items.
.option forbid_include redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is true, items of the form
.code
:include:<path name>
@@ -20381,6 +20469,8 @@ are not permitted in non-filter redirection lists.
.option forbid_pipe redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
.cindex "delivery" "to pipe; forbidding"
If this option is true, this router may not generate a new address which
specifies delivery to a pipe, either from an Exim filter or from a conventional
@@ -20388,6 +20478,8 @@ forward file. This option is forced to be true if &%one_time%& is set.
.option forbid_sieve_filter redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
If this option is set true, only Exim filters are permitted when
&%allow_filter%& is true.
@@ -22052,10 +22144,14 @@ the obvious value which users understand most easily.
The value of the option is expanded, and must then be a numerical value
(decimal point allowed), optionally followed by one of the letters K, M, or G,
-for kilobytes, megabytes, or gigabytes. If Exim is running on a system with
+for kilobytes, megabytes, or gigabytes, optionally followed by a slash
+and further option modifiers. If Exim is running on a system with
large file support (Linux and FreeBSD have this), mailboxes larger than 2G can
be handled.
+The option modifier &%no_check%& can be used to force delivery even if the over
+quota condition is met. The quota gets updated as usual.
+
&*Note*&: A value of zero is interpreted as &"no quota"&.
The expansion happens while Exim is running as root, before it changes uid for
@@ -22090,6 +22186,8 @@ can only be used if &%quota%& is also set. The value is expanded; an expansion
failure causes delivery to be deferred. A value of zero is interpreted as
&"no quota"&.
+The option modifier &%no_check%& can be used to force delivery even if the over
+quota condition is met. The quota gets updated as usual.
.option quota_is_inclusive appendfile boolean true
See &%quota%& above.
@@ -23695,12 +23793,14 @@ the message. As a result, the overall timeout for a message depends on the size
of the message. Its value must not be zero. See also &%final_timeout%&.
-.option dkim_domain smtp string&!! unset
+.option dkim_domain smtp string list&!! unset
.option dkim_selector smtp string&!! unset
.option dkim_private_key smtp string&!! unset
.option dkim_canon smtp string&!! unset
.option dkim_strict smtp string&!! unset
.option dkim_sign_headers smtp string&!! unset
+.option dkim_hash smtp string&!! sha256
+.option dkim_identity smtp string&!! unset
DKIM signing options. For details see section &<<SECDKIMSIGN>>&.
@@ -27637,13 +27737,22 @@ built, then you have SNI support).
"SECTmulmessam"
.cindex "multiple SMTP deliveries with TLS"
.cindex "TLS" "multiple message deliveries"
+.new
Exim sends multiple messages down the same TCP/IP connection by starting up
an entirely new delivery process for each message, passing the socket from
one process to the next. This implementation does not fit well with the use
of TLS, because there is quite a lot of state information associated with a TLS
connection, not just a socket identification. Passing all the state information
-to a new process is not feasible. Consequently, Exim shuts down an existing TLS
-session before passing the socket to a new process. The new process may then
+to a new process is not feasible. Consequently, for sending using TLS Exim
+starts an additional proxy process for handling the encryption, piping the
+unencrypted data stream from and to the delivery processes.
+
+An older mode of operation can be enabled on a per-host basis by the
+&%hosts_noproxy_tls%& option on the &(smtp)& transport. If the host matches
+this list the proxy process descibed above is not used; instead Exim
+.wen
+shuts down an existing TLS session being run by the delivery process
+before passing the socket to a new process. The new process may then
try to start a new TLS session, and if successful, may try to re-authenticate
if AUTH is in use, before sending the next message.
@@ -28971,6 +29080,11 @@ and cannot depend on content of received headers.
Note also that headers cannot be
modified by any of the post-data ACLs (DATA, MIME and DKIM).
Headers may be modified by routers (subject to the above) and transports.
+.new
+The Received-By: header is generated as soon as the body reception starts,
+rather than the traditional time after the full message is received;
+this will affect the timestamp.
+.wen
All the usual ACLs are called; if one results in the message being
rejected, all effort spent in delivery (including the costs on
@@ -29008,12 +29122,14 @@ sender when the destination system is doing content-scan based rejection.
.cindex "&ACL;" "enabling debug logging"
.cindex "debugging" "enabling from an ACL"
This control turns on debug logging, almost as though Exim had been invoked
-with &`-d`&, with the output going to a new logfile, by default called
-&'debuglog'&. The filename can be adjusted with the &'tag'& option, which
+with &`-d`&, with the output going to a new logfile in the usual logs directory,
+by default called &'debuglog'&.
+The filename can be adjusted with the &'tag'& option, which
may access any variables already defined. The logging may be adjusted with
the &'opts'& option, which takes the same values as the &`-d`& command-line
option.
-Logging may be stopped, and the file removed, with the &'kill'& option.
+Logging started this way may be stopped, and the file removed,
+with the &'kill'& option.
Some examples (which depend on variables that don't exist in all
contexts):
.code
@@ -30903,6 +31019,23 @@ command when performing the callout, instead of an empty address. There is no
need to use this option unless you know that the called hosts make use of the
sender when checking recipients. If used indiscriminately, it reduces the
usefulness of callout caching.
+
+.new
+.vitem &*hold*&
+This option applies to recipient callouts only. For example:
+.code
+require verify = recipient/callout=use_sender,hold
+.endd
+It causes the connection to be helod open and used for any further recipients
+and for eventual delivery (should that be done quickly).
+Doing this saves on TCP and SMTP startup costs, and TLS costs also
+when that is used for the connections.
+The advantage is only gained if there are no callout cache hits
+(which could be enforced by the no_cache option),
+if the use_sender option is used,
+if neither the random nor the use_postmaster option is used,
+and if no other callouts intervene.
+.wen
.endlist
If you use any of the parameters that set a non-empty sender for the MAIL
@@ -31594,14 +31727,18 @@ an address (which may be an IP address and port, or the path of a Unix socket),
a commandline to send (may include a single %s which will be replaced with
the path to the mail file to be scanned),
an RE to trigger on from the returned data,
-an RE to extract malware_name from the returned data.
+and an RE to extract malware_name from the returned data.
For example:
.code
-av_scanner = sock:127.0.0.1 6001:%s:(SPAM|VIRUS):(.*)\$
+av_scanner = sock:127.0.0.1 6001:%s:(SPAM|VIRUS):(.*)$
.endd
-Default for the socket specifier is &_/tmp/malware.sock_&.
-Default for the commandline is &_%s\n_&.
-Both regular-expressions are required.
+.new
+Note that surrounding whitespace is stripped from each option, meaning
+there is no way to specify a trailing newline.
+The socket specifier and both regular-expressions are required.
+Default for the commandline is &_%s\n_& (note this does have a trailing newline);
+specify an empty element to get this.
+.wen
.vitem &%sophie%&
.cindex "virus scanners" "Sophos and Sophie"
@@ -32441,9 +32578,15 @@ C variables are as follows:
.vlist
.vitem &*int&~body_linecount*&
This variable contains the number of lines in the message's body.
+.new
+It is not valid if the &%spool_files_wireformat%& option is used.
+.wen
.vitem &*int&~body_zerocount*&
This variable contains the number of binary zero bytes in the message's body.
+.new
+It is not valid if the &%spool_files_wireformat%& option is used.
+.wen
.vitem &*unsigned&~int&~debug_selector*&
This variable is set to zero when no debugging is taking place. Otherwise, it
@@ -35769,9 +35912,9 @@ down a single SMTP connection, an asterisk follows the IP address in the log
lines for the second and subsequent messages.
.new
When two or more messages are delivered down a single TLS connection, the
-TLS-related information logged for the first message delivered
-(which may not be the earliest line in the log)
+DNS and some TLS-related information logged for the first message delivered
will not be present in the log lines for the second and subsequent messages.
+TLS cipher information is still available.
.wen
.cindex "delivery" "cutthrough; logging"
@@ -35885,6 +36028,7 @@ the following table:
&`I `& local interface used
&`K `& CHUNKING extension used
&`id `& message id for incoming message
+&`M8S `& 8BITMIME status for incoming message
&`P `& on &`<=`& lines: protocol used
&` `& on &`=>`& and &`**`& lines: return path
&`PRDR`& PRDR extension used
@@ -35898,6 +36042,7 @@ the following table:
&`SNI `& server name indication from TLS client hello
&`ST `& shadow transport name
&`T `& on &`<=`& lines: message subject (topic)
+&`TFO `& connection took advantage of TCP Fast Open
&` `& on &`=>`& &`**`& and &`==`& lines: transport name
&`U `& local user or RFC 1413 identity
&`X `& TLS cipher suite
@@ -35979,6 +36124,7 @@ selection marked by asterisks:
&` incoming_interface `& local interface on <= and => lines
&` incoming_port `& remote port on <= lines
&`*lost_incoming_connection `& as it says (includes timeouts)
+&` millisec `& millisecond timestamps and QT,DT,D times
&` outgoing_interface `& local interface on => lines
&` outgoing_port `& add remote port to => lines
&`*queue_run `& start and end queue runs
@@ -36068,6 +36214,8 @@ process is started because &%queue_only%& is set or &%-odq%& was used.
.cindex "log" "delivery duration"
&%deliver_time%&: For each delivery, the amount of real time it has taken to
perform the actual delivery is logged as DT=<&'time'&>, for example, &`DT=1s`&.
+If millisecond logging is enabled, short times will be shown with greater
+precision, eg. &`DT=0.304`&.
.next
.cindex "log" "message size on delivery"
.cindex "size" "of message"
@@ -36143,6 +36291,14 @@ important with the widening use of NAT (see RFC 2505).
&%lost_incoming_connection%&: A log line is written when an incoming SMTP
connection is unexpectedly dropped.
.next
+.new
+.cindex "log" "millisecond timestamps"
+.cindex millisecond logging
+.cindex timstamps "millisecond, in logs"
+&%millisec%&: Timestamps have a period and three decimal places of finer granularity
+appended to the seconds value.
+.wen
+.next
.cindex "log" "outgoing interface"
.cindex "log" "local interface"
.cindex "log" "local address and port"
@@ -36181,6 +36337,8 @@ includes reception time as well as the delivery time for the current address.
This means that it may be longer than the difference between the arrival and
delivery log line times, because the arrival log line is not written until the
message has been successfully received.
+If millisecond logging is enabled, short times will be shown with greater
+precision, eg. &`QT=1.578s`&.
.next
&%queue_time_overall%&: The amount of time the message has been in the queue on
the local host is logged as QT=<&'time'&> on &"Completed"& lines, for
@@ -36633,8 +36791,7 @@ autodetection of some well known compression extensions.
.cindex "&'exipick'&"
John Jetmore's &'exipick'& utility is included in the Exim distribution. It
lists messages from the queue according to a variety of criteria. For details
-of &'exipick'&'s facilities, visit the web page at
-&url(http://www.exim.org/eximwiki/ToolExipickManPage) or run &'exipick'& with
+of &'exipick'&'s facilities, run &'exipick'& with
the &%--help%& option.
@@ -37884,6 +38041,13 @@ the contents of files on the spool via the Exim monitor (which runs
unprivileged), Exim must be built to allow group read access to its spool
files.
+.new
+By default, regular users are trusted to perform basic testing and
+introspection commands, as themselves. This setting can be tightened by
+setting the &%commandline_checks_require_admin%& option.
+This affects most of the checking options,
+such as &%-be%& and anything else &%-b*%&.
+.wen
.section "Spool files" "SECID275"
@@ -38004,6 +38168,13 @@ file remains in existence. When Exim next processes the message, it notices the
-J file and uses it to update the -H file before starting the next delivery
attempt.
+.new
+Files whose names end with -K or .eml may also be seen in the spool.
+These are temporaries used for DKIM or malware processing, when that is used.
+They should be tidied up by normal operations; any old ones are probably
+relics of crashes and can be removed.
+.wen
+
.section "Format of the -H file" "SECID282"
.cindex "uid (user id)" "in spool file"
.cindex "gid (group id)" "in spool file"
@@ -38081,8 +38252,8 @@ The address of an authenticated sender &-- the value of the
&$authenticated_sender$& variable.
.vitem "&%-body_linecount%&&~<&'number'&>"
-This records the number of lines in the body of the message, and is always
-present.
+This records the number of lines in the body of the message, and is
+present unless &%-spool_file_wireformat%& is.
.vitem "&%-body_zerocount%&&~<&'number'&>"
This records the number of binary zero bytes in the body of the message, and is
@@ -38164,6 +38335,14 @@ to ensure that the caller is displayed in queue listings).
If a message was scanned by SpamAssassin, this is present. It records the value
of &$spam_score_int$&.
+.new
+.vitem &%-spool_file_wireformat%&
+The -D file for this message is in wire-format (for ESMTP CHUNKING)
+rather than Unix-format.
+The line-ending is CRLF rather than newline.
+There is still, however, no leading-dot-stuffing.
+.wen
+
.vitem &%-tls_certificate_verified%&
A TLS certificate was received from the client that sent this message, and the
certificate was verified by the server.
@@ -38271,6 +38450,20 @@ unqualified domain &'foundation'&.
.ecindex IIDforspo2
.ecindex IIDforspo3
+.new
+.section "Format of the -D file" "SECID282a"
+The data file is traditionally in Unix-standard format: lines are ended with
+an ASCII newline character.
+However, when the &%spool_wireformat%& main option is used some -D files
+can have an alternate format.
+This is flagged by a &%-spool_file_wireformat%& line in the corresponding -H file.
+The -D file lines (not including the first name-component line) are
+suitable for direct copying to the wire when transmitting using the
+ESMTP CHUNKING option, meaning lower processing overhead.
+Lines are terminated with an ASCII CRLF pair.
+There is no dot-stuffing (and no dot-termination).
+.wen
+
. ////////////////////////////////////////////////////////////////////////////
. ////////////////////////////////////////////////////////////////////////////
@@ -38325,22 +38518,28 @@ senders).
Signing is enabled by setting private options on the SMTP transport.
These options take (expandable) strings as arguments.
-.option dkim_domain smtp string&!! unset
-MANDATORY:
-The domain you want to sign with. The result of this expanded
-option is put into the &%$dkim_domain%& expansion variable.
+.option dkim_domain smtp string list&!! unset
+The domain(s) you want to sign with.
+.new
+After expansion, this can be a list.
+Each element in turn is put into the &%$dkim_domain%& expansion variable
+while expanding the remaining signing options.
+.wen
If it is empty after expansion, DKIM signing is not done.
-.option dkim_selector smtp string&!! unset
-MANDATORY:
-This sets the key selector string. You can use the &%$dkim_domain%& expansion
-variable to look up a matching selector. The result is put in the expansion
+.option dkim_selector smtp string list&!! unset
+This sets the key selector string.
+.new
+After expansion, which can use &$dkim_domain$&, this can be a list.
+Each element in turn is put in the expansion
variable &%$dkim_selector%& which may be used in the &%dkim_private_key%&
option along with &%$dkim_domain%&.
+If the option is empty after expansion, DKIM signing is not done for this domain.
+.wen
.option dkim_private_key smtp string&!! unset
-MANDATORY:
-This sets the private key to use. You can use the &%$dkim_domain%& and
+This sets the private key to use.
+You can use the &%$dkim_domain%& and
&%$dkim_selector%& expansion variables to determine the private key to use.
The result can either
.ilist
@@ -38353,16 +38552,28 @@ be "0", "false" or the empty string, in which case the message will not
be signed. This case will not result in an error, even if &%dkim_strict%&
is set.
.endlist
+If the option is empty after expansion, DKIM signing is not done.
+
+.new
+.option dkim_hash smtp string&!! sha256
+Can be set alternatively to &"sha1"& to use an alternate hash
+method. Note that sha1 is now condidered insecure, and deprecated.
+
+.option dkim_identity smtp string&!! unset
+If set after expansion, the value is used to set an "i=" tag in
+the signing header. The DKIM standards restrict the permissible
+syntax of this optional tag to a mail address, with possibly-empty
+local part, an @, and a domain identical to or subdomain of the "d="
+tag value. Note that Exim does not check the value.
+.wen
.option dkim_canon smtp string&!! unset
-OPTIONAL:
This option sets the canonicalization method used when signing a message.
The DKIM RFC currently supports two methods: "simple" and "relaxed".
The option defaults to "relaxed" when unset. Note: the current implementation
only supports using the same canonicalization method for both headers and body.
.option dkim_strict smtp string&!! unset
-OPTIONAL:
This option defines how Exim behaves when signing a message that
should be signed fails for some reason. When the expansion evaluates to
either "1" or "true", Exim will defer. Otherwise Exim will send the message
@@ -38370,11 +38581,10 @@ unsigned. You can use the &%$dkim_domain%& and &%$dkim_selector%& expansion
variables here.
.option dkim_sign_headers smtp string&!! unset
-OPTIONAL:
-When set, this option must expand to (or be specified as) a colon-separated
+If set, this option must expand to (or be specified as) a colon-separated
list of header names. Headers with these names will be included in the message
-signature. When unspecified, the header names recommended in RFC4871 will be
-used.
+signature.
+When unspecified, the header names recommended in RFC4871 will be used.
.section "Verifying DKIM signatures in incoming mail" "SECID514"
@@ -38385,7 +38595,7 @@ Verification of DKIM signatures in SMTP incoming email is implemented via the
syntactically(!) correct signature in the incoming message.
A missing ACL definition defaults to accept.
If any ACL call does not accept, the message is not accepted.
-If a cutthrough delivery was in progress for the message it is
+If a cutthrough delivery was in progress for the message, that is
summarily dropped (having wasted the transmission effort).
To evaluate the signature in the ACL a large number of expansion variables
@@ -38488,7 +38698,7 @@ The algorithm used. One of 'rsa-sha1' or 'rsa-sha256'.
.vitem &%$dkim_canon_body%&
The body canonicalization method. One of 'relaxed' or 'simple'.
-.vitem &%dkim_canon_headers%&
+.vitem &%$dkim_canon_headers%&
The header canonicalization method. One of 'relaxed' or 'simple'.
.vitem &%$dkim_copiedheaders%&
@@ -38897,7 +39107,7 @@ The current list of events is:
&`msg:rcpt:host:defer after transport `& per recipient per host
&`msg:rcpt:defer after transport `& per recipient
&`msg:host:defer after transport `& per attempt
-&`msg:fail:delivery after main `& per recipient
+&`msg:fail:delivery after transport `& per recipient
&`msg:fail:internal after main `& per recipient
&`tcp:connect before transport `& per connection
&`tcp:close after transport `& per connection
@@ -38914,6 +39124,11 @@ The second column in the table above describes whether the event fires
before or after the action is associates with. Those which fire before
can be used to affect that action (more on this below).
+.new
+The third column in the table above says what section of the configumration
+should define the event action.
+.wen
+
An additional variable, &$event_data$&, is filled with information varying
with the event type:
.display
diff --git a/doc/doc-src/FAQ.src b/doc/doc-src/FAQ.src
index 1d43cbcd2..1ff867b62 100644
--- a/doc/doc-src/FAQ.src
+++ b/doc/doc-src/FAQ.src
@@ -1861,7 +1861,7 @@ A0117: Here! This is a contribution from a RedHat user, somewhat edited. On
==> adduser exim
- (3) Now you can prepare to build Exim. Go to \?http://www.exim.org?\ or
+ (3) Now you can prepare to build Exim. Go to \?https://www.exim.org?\ or
one of its mirrors, or the master ftp site
\?ftp://ftp.csx.cam.ac.uk/pub/software/email/exim/exim4?\, and download
\(exim-4.20.tar.gz)\ or whatever the current release is. Then:
@@ -7122,7 +7122,7 @@ C037: An elegant way of using ETRN, which does immediate delivery if the host
C042: ``Since the Exim 4 configuration needed to get Mailman to work differs a
little bit from Exim 3 and since I still haven't seen a recipe for
Mailman with Exim 4, I'm providing my configuration (based heavily on
- \?http://www.exim.org/howto/mailman.html?\).''
+ \?https://www.exim.org/howto/mailman21.html?\).''
C043: ``Attached is an Exim 4 config file which is designed for an Exim server
that is put in front of an Exchange 5.5 system but which verifies the
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 5b5dcbd7f..8f1b6b7ad 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -24,7 +24,7 @@ JH/03 Rework the transport continued-connection mechanism: when TLS is active,
the passed-on TCP connection. Instead, proxy the child (and any
subsequent ones) for TLS via a unix-domain socket channel. Logging is
affected: the continued delivery log lines do not have any DNSSEC, TLS
- cipher, Certificate or OCSP information.
+ Certificate or OCSP information. TLS cipher information is still logged.
JH/04 Shorten the log line for daemon startup by collapsing adjacent sets of
identical IP addresses on different listening ports. Will also affect
@@ -34,6 +34,138 @@ PP/02 Bug 2070: uClibc defines __GLIBC__ without providing glibc headers;
add noisy ifdef guards to special-case this sillyness.
Patch from Bernd Kuhls.
+JH/05 Tighten up the checking in isip4 (et al): dotted-quad components larger
+ than 255 are no longer allowed.
+
+JH/06 Default openssl_options to include +no_ticket, to reduce load on peers.
+ Disable the session-cache too, which might reduce our load. Since we
+ currrectly use a new context for every connection, both as server and
+ client, there is no benefit for these.
+ GnuTLS appears to not support tickets server-side by default (we don't
+ call gnutls_session_ticket_enable_server()) but client side is enabled
+ by default on recent versions (3.1.3 +) unless the PFS priority string
+ is used (3.2.4 +).
+
+PP/03 Add $SOURCE_DATE_EPOCH support for reproducible builds, per spec at
+ <https://reproducible-builds.org/specs/source-date-epoch/>.
+
+JH/07 Fix smtp transport use of limited max_rcpt under mua_wrapper. Previously
+ the check for any unsuccessful recipients did not notice the limit, and
+ erroneously found still-pending ones.
+
+JH/08 Pipeline CHUNKING command and data together, on kernels that support
+ MSG_MORE. Only in-clear (not on TLS connections).
+
+JH/09 Avoid using a temporary file during transport using dkim. Unless a
+ transport-filter is involved we can buffer the headers in memory for
+ creating the signature, and read the spool data file once for the
+ signature and again for transmission.
+
+JH/10 Enable use of sendfile in Linux builds as default. It was disabled in
+ 4.77 as the kernel support then wasn't solid, having issues in 64bit
+ mode. Now, it's been long enough. Add support for FreeBSD also.
+
+JH/11 Bug 2104: Fix continued use of a transport connection with TLS. In the
+ case where the routing stage had gathered several addresses to send to
+ a host before calling the transport for the first, we previously failed
+ to close down TLS in the old transport process before passing the TCP
+ connection to the new process. The new one sent a STARTTLS command
+ which naturally failed, giving a failed delivery and bloating the retry
+ database. Investigation and fix prototype from Wolfgang Breyha.
+
+JH/12 Fix check on SMTP command input synchronisation. Previously there were
+ false-negatives in the check that the sender had not preempted a response
+ or prompt from Exim (running as a server), due to that code's lack of
+ awareness of the SMTP input buffering.
+
+PP/04 Add commandline_checks_require_admin option.
+ Exim drops privileges sanely, various checks such as -be aren't a
+ security problem, as long as you trust local users with access to their
+ own account. When invoked by services which pass untrusted data to
+ Exim, this might be an issue. Set this option in main configuration
+ AND make fixes to the calling application, such as using `--` to stop
+ processing options.
+
+JH/13 Do pipelining under TLS. Previously, although safe, no advantage was
+ taken. Now take care to pack both (client) MAIL,RCPT,DATA, and (server)
+ responses to those, into a single TLS record each way (this usually means
+ a single packet). As a side issue, smtp_enforce_sync now works on TLS
+ connections.
+
+PP/05 OpenSSL/1.1: use DH_bits() for more accurate DH param sizes. This
+ affects you only if you're dancing at the edge of the param size limits.
+ If you are, and this message makes sense to you, then: raise the
+ configured limit or use OpenSSL 1.1. Nothing we can do for older
+ versions.
+
+JH/14 For the "sock" variant of the malware scanner interface, accept an empty
+ cmdline element to get the documented default one. Previously it was
+ inaccessible.
+
+JH/15 Fix a crash in the smtp transport caused when two hosts in succession
+ are unsuable for non-message-specific reasons - eg. connection timeout,
+ banner-time rejection.
+
+JH/16 Fix logging of delivery remote port, when specified by router, under
+ callout/hold.
+
+PP/06 Repair manualroute's ability to take options in any order, even if one
+ is the name of a transport.
+ Fixes bug 2140.
+
+HS/01 Cleanup, prevent repeated use of -p/-oMr (CVE-2017-1000369)
+
+JH/17 Change the list-building routines interface to use the expanding-string
+ triplet model, for better allocation and copying behaviour.
+
+JH/18 Prebuild the data-structure for "builtin" macros, for faster startup.
+ Previously it was constructed the first time a possibly-matching string
+ was met in the configuration file input during startup; now it is done
+ during compilation.
+
+JH/19 Bug 2141: Use the full-complex API for Berkeley DB rather than the legacy-
+ compatible one, to avoid the (poorly documented) possibility of a config
+ file in the working directory redirecting the DB files, possibly correpting
+ some existing file. CVE-2017-10140 assigned for BDB.
+
+JH/20 Bug 2147: Do not defer for a verify-with-callout-and-random which is not
+ cache-hot. Previously, although the result was properly cached, the
+ initial verify call returned a defer.
+
+JH/21 Bug 2151: Avoid using SIZE on the MAIL for a callout verify, on any but
+ the main verify for receipient in uncached-mode.
+
+JH/22 Retire historical build files to an "unsupported" subdir. These are
+ defined as "ones for which we have no current evidence of testing".
+
+JH/23 DKIM: enforce the DNS pubkey record "h" permitted-hashes optional field,
+ if present. Previously it was ignored.
+
+JH/24 Start using specified-initialisers in C structure init coding. This is
+ a C99 feature (it's 2017, so now considered safe).
+
+JH/25 Use one-bit bitfields for flags in the "addr" data structure. Previously
+ if was a fixed-sized field and bitmask ops via macros; it is now more
+ extensible.
+
+PP/07 GitHub PR 56: Apply MariaDB build fix.
+ Patch provided by Jaroslav Škarvada.
+
+PP/08 Bug 2161: Fix regression in sieve quoted-printable handling introduced
+ during Coverity cleanups [4.87 JH/47]
+ Diagnosis and fix provided by Michael Fischer v. Mollard.
+
+JH/26 Fix DKIM bug: when the pseudoheader generated for signing was exactly
+ the right size to place the terminating semicolon on its own folded
+ line, the header hash was calculated to an incorrect value thanks to
+ the (relaxed) space the fold became.
+
+HS/02 Fix Bug 2130: large writes from the transport subprocess where chunked
+ and confused the parent.
+
+JH/27 Fix SOCKS bug: an unitialized pointer was deref'd by the transport process
+ which could crash as a result. This could lead to undeliverable messages.
+
Exim version 4.89
-----------------
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 872371fcb..39fce1eab 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -23,6 +23,43 @@ Version 4.90
4. A malware connection type for the FPSCAND protocol.
+ 5. An option for recipient verify callouts to hold the connection open for
+ further recipients and for delivery.
+
+ 6. The reproducible build $SOURCE_DATE_EPOCH environment variable is now
+ supported.
+
+ 7. Optionally, an alternate format for spool data-files which matches the
+ wire format - meaning more efficient reception and transmission (at the
+ cost of difficulty with standard Unix tools). Only used for messages
+ received using the ESMTP CHUNKING option, and when a new main-section
+ option "spool_wireformat" (false by default) is set.
+
+ 8. New main configuration option "commandline_checks_require_admin" to
+ restrict who can use various introspection options.
+
+ 9. New option modifier "no_check" for quota and quota_filecount
+ appendfile transport.
+
+10. Variable $smtp_command_history returning a comma-sep list of recent
+ SMTP commands.
+
+11. Millisecond timetamps in logs, on log_selector "millisec". Also affects
+ log elements QT, DT and D, and timstamps in debug output.
+
+12. TCP Fast Open logging. As a server, logs when the SMTP banner was sent
+ while still in SYN_RECV state; as a client logs when the connection
+ is opened with a TFO cookie.
+
+13. DKIM support for multiple signing, by domain and/or key-selector.
+ DKIM support for multiple hashes, and for alternate-identity tags.
+
+14. Exipick understands -C|--config for an alternative Exim
+ configuration file.
+
+15. TCP Fast Open used, with data-on-SYN, for client SMTP via SOCKS5 proxy,
+ for ${readsocket } expansions, and for ClamAV.
+
Version 4.89
------------
@@ -382,7 +419,8 @@ Version 4.82
It adds new expansion variables $dmarc_ar_header, $dmarc_status,
$dmarc_status_text, and $dmarc_used_domain. It adds a new acl modifier
dmarc_status. It adds new control flags dmarc_disable_verify and
- dmarc_enable_forensic.
+ dmarc_enable_forensic. The default for the dmarc_tld_file option is
+ "/etc/exim/opendmarc.tlds" and can be changed via EDITME.
22. Add expansion variable $authenticated_fail_id, which is the username
provided to the authentication method which failed. It is available
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index b6439e6ed..5728643a8 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -137,6 +137,7 @@ command string* unset lmtp
command_group string unset queryprogram 4.00
command_timeout time 5m smtp
command_user string unset queryprogram 4.00
+commandline_checks_require_admin boolean false main 4.90
condition string* unset routers 4.00
connect_timeout time 0s smtp 1.60
connection_max_messages integer 500 smtp 4.00 replaces batch_max
@@ -529,6 +530,7 @@ socket string* unset lmtp
spamd_address string* + main 4.50 with content scan
split_spool_directory boolean false main 1.70
spool_directory string ++ main
+spool_wireformat boolean false main 4.90
sqlite_lock_timeout time 5s main 4.53
strict_acl_vars boolean false main 4.64
srv_fail_domains domain list unset dnslookup 4.43
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index 0b1afb247..1e826aee1 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -595,12 +595,14 @@ package controlled locations (/usr/include and /usr/lib).
2. Use the following global settings to configure DMARC:
-Required:
+Optional:
dmarc_tld_file Defines the location of a text file of valid
top level domains the opendmarc library uses
during domain parsing. Maintained by Mozilla,
the most current version can be downloaded
from a link at http://publicsuffix.org/list/.
+ If unset, "/etc/exim/opendmarc.tlds" (hardcoded)
+ is used.
Optional:
dmarc_history_file Defines the location of a file to log results
diff --git a/src/Makefile b/src/Makefile
index 2a100bbdd..b262a7b53 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -105,11 +105,10 @@ cscope.files: FRC
echo "-q" > $@
echo "-p3" >> $@
find src Local OS exim_monitor -name "*.[cshyl]" -print \
- -o -name "os.h*" -print \
+ -o -name "os.[ch]*" -print \
-o -name "*akefile*" -print \
-o -name config.h.defaults -print \
-o -name EDITME -print >> $@
- ls OS/* >> $@
FRC:
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index f6b42f353..67ac082ba 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -36,7 +36,7 @@ FE = $(FULLECHO)
# are set up, and finally it goes to the main Exim target.
all: utils exim
-config: $(EDITME) checklocalmake Makefile os.c config.h version.h
+config: $(EDITME) checklocalmake Makefile os.c config.h version.h macro.c
checklocalmake:
@if $(SHELL) $(SCRIPTS)/newer $(EDITME)-$(OSTYPE) $(EDITME) || \
@@ -79,29 +79,41 @@ Makefile: ../OS/Makefile-Base ../OS/Makefile-Default \
# Build (link) the os.h file
+#os.h: $(SCRIPTS)/Configure-os.h \
+# $(O)/os.h-AIX $(O)/os.h-BSDI $(O)/os.h-cygwin \
+# $(O)/os.h-Darwin $(O)/os.h-DGUX $(O)/os.h-DragonFly \
+# $(O)/os.h-FreeBSD $(O)/os.h-GNU $(O)/os.h-GNUkFreeBSD \
+# $(O)/os.h-GNUkNetBSD $(O)/os.h-HI-OSF \
+# $(O)/os.h-HI-UX $(O)/os.h-HP-UX $(O)/os.h-HP-UX-9 \
+# $(O)/os.h-IRIX $(O)/os.h-IRIX6 $(O)/os.h-IRIX632 \
+# $(O)/os.h-IRIX65 $(O)/os.h-Linux $(O)/os.h-mips \
+# $(O)/os.h-NetBSD $(O)/os.h-NetBSD-a.out \
+# $(O)/os.h-OpenBSD $(O)/os.h-OpenUNIX $(O)/os.h-OSF1 \
+# $(O)/os.h-QNX $(O)/os.h-SCO $(O)/os.h-SCO_SV \
+# $(O)/os.h-SunOS4 $(O)/os.h-SunOS5 $(O)/os.h-SunOS5-hal \
+# $(O)/os.h-ULTRIX $(O)/os.h-UNIX_SV \
+# $(O)/os.h-Unixware7 $(O)/os.h-USG
+# $(SHELL) $(SCRIPTS)/Configure-os.h
+
os.h: $(SCRIPTS)/Configure-os.h \
- $(O)/os.h-AIX $(O)/os.h-BSDI $(O)/os.h-cygwin \
- $(O)/os.h-Darwin $(O)/os.h-DGUX $(O)/os.h-DragonFly \
- $(O)/os.h-FreeBSD $(O)/os.h-GNU $(O)/os.h-GNUkFreeBSD \
- $(O)/os.h-GNUkNetBSD $(O)/os.h-HI-OSF \
- $(O)/os.h-HI-UX $(O)/os.h-HP-UX $(O)/os.h-HP-UX-9 \
- $(O)/os.h-IRIX $(O)/os.h-IRIX6 $(O)/os.h-IRIX632 \
- $(O)/os.h-IRIX65 $(O)/os.h-Linux $(O)/os.h-mips \
- $(O)/os.h-NetBSD $(O)/os.h-NetBSD-a.out \
- $(O)/os.h-OpenBSD $(O)/os.h-OpenUNIX $(O)/os.h-OSF1 \
- $(O)/os.h-QNX $(O)/os.h-SCO $(O)/os.h-SCO_SV \
- $(O)/os.h-SunOS4 $(O)/os.h-SunOS5 $(O)/os.h-SunOS5-hal \
- $(O)/os.h-ULTRIX $(O)/os.h-UNIX_SV \
- $(O)/os.h-Unixware7 $(O)/os.h-USG
+ $(O)/os.h-FreeBSD \
+ $(O)/os.h-Linux \
+ $(O)/os.h-OpenBSD \
+ $(O)/os.h-SunOS5
$(SHELL) $(SCRIPTS)/Configure-os.h
# Build the os.c file
+#os.c: ../src/os.c \
+# $(SCRIPTS)/Configure-os.c \
+# $(O)/os.c-cygwin $(O)/os.c-GNU $(O)/os.c-HI-OSF \
+# $(O)/os.c-IRIX $(O)/os.c-IRIX6 $(O)/os.c-IRIX632 \
+# $(O)/os.c-IRIX65 $(O)/os.c-Linux $(O)/os.c-OSF1
+# $(SHELL) $(SCRIPTS)/Configure-os.c
+
os.c: ../src/os.c \
$(SCRIPTS)/Configure-os.c \
- $(O)/os.c-cygwin $(O)/os.c-GNU $(O)/os.c-HI-OSF \
- $(O)/os.c-IRIX $(O)/os.c-IRIX6 $(O)/os.c-IRIX632 \
- $(O)/os.c-IRIX65 $(O)/os.c-Linux $(O)/os.c-OSF1
+ $(O)/os.c-Linux
$(SHELL) $(SCRIPTS)/Configure-os.c
# Build the config.h file.
@@ -109,6 +121,114 @@ os.c: ../src/os.c \
config.h: Makefile buildconfig ../src/config.h.defaults $(EDITME)
$(SHELL) $(SCRIPTS)/Configure-config.h "$(MAKE)"
+# Build the builtin-macros data struct
+
+MACRO_HSRC = macro_predef.h os.h globals.h config.h \
+ routers/accept.h routers/dnslookup.h routers/ipliteral.h \
+ routers/iplookup.h routers/manualroute.h routers/queryprogram.h \
+ routers/redirect.h
+
+OBJ_MACRO = macro_predef.o \
+ macro-globals.o macro-readconf.o macro-route.o macro-transport.o macro-drtables.o \
+ macro-appendfile.o macro-autoreply.o macro-lmtp.o macro-pipe.o macro-queuefile.o \
+ macro-smtp.o macro-accept.o macro-dnslookup.o macro-ipliteral.o macro-iplookup.o \
+ macro-manualroute.o macro-queryprogram.o macro-redirect.o \
+ macro-auth-spa.o macro-cram_md5.o macro-cyrus_sasl.o macro-dovecot.o macro-gsasl_exim.o \
+ macro-heimdal_gssapi.o macro-plaintext.o macro-spa.o macro-tls.o\
+
+$(OBJ_MACRO): $(MACRO_HSRC)
+
+macro_predef.o : macro_predef.c
+ @echo "$(CC) -DMACRO_PREDEF macro_predef.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ macro_predef.c
+macro-globals.o : globals.c
+ @echo "$(CC) -DMACRO_PREDEF globals.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ globals.c
+macro-readconf.o : readconf.c
+ @echo "$(CC) -DMACRO_PREDEF readconf.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ readconf.c
+macro-route.o : route.c
+ @echo "$(CC) -DMACRO_PREDEF route.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ route.c
+macro-transport.o: transport.c
+ @echo "$(CC) -DMACRO_PREDEF transport.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transport.c
+macro-drtables.o : drtables.c
+ @echo "$(CC) -DMACRO_PREDEF drtables.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ drtables.c
+macro-appendfile.o : transports/appendfile.c
+ @echo "$(CC) -DMACRO_PREDEF transports/appendfile.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/appendfile.c
+macro-autoreply.o : transports/autoreply.c
+ @echo "$(CC) -DMACRO_PREDEF transports/autoreply.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/autoreply.c
+macro-lmtp.o: transports/lmtp.c
+ @echo "$(CC) -DMACRO_PREDEF transports/lmtp.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/lmtp.c
+macro-pipe.o : transports/pipe.c
+ @echo "$(CC) -DMACRO_PREDEF transports/pipe.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/pipe.c
+macro-queuefile.o : transports/queuefile.c
+ @echo "$(CC) -DMACRO_PREDEF transports/queuefile.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/queuefile.c
+macro-smtp.o : transports/smtp.c
+ @echo "$(CC) -DMACRO_PREDEF transports/smtp.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/smtp.c
+macro-accept.o : routers/accept.c
+ @echo "$(CC) -DMACRO_PREDEF routers/accept.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/accept.c
+macro-dnslookup.o : routers/dnslookup.c
+ @echo "$(CC) -DMACRO_PREDEF routers/dnslookup.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/dnslookup.c
+macro-ipliteral.o : routers/ipliteral.c
+ @echo "$(CC) -DMACRO_PREDEF routers/ipliteral.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/ipliteral.c
+macro-iplookup.o : routers/iplookup.c
+ @echo "$(CC) -DMACRO_PREDEF routers/iplookup.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/iplookup.c
+macro-manualroute.o : routers/manualroute.c
+ @echo "$(CC) -DMACRO_PREDEF routers/manualroute.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/manualroute.c
+macro-queryprogram.o : routers/queryprogram.c
+ @echo "$(CC) -DMACRO_PREDEF routers/queryprogram.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/queryprogram.c
+macro-redirect.o : routers/redirect.c
+ @echo "$(CC) -DMACRO_PREDEF routers/redirect.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/redirect.c
+macro-auth-spa.o : auths/auth-spa.c
+ @echo "$(CC) -DMACRO_PREDEF auths/auth-spa.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/auth-spa.c
+macro-cram_md5.o : auths/cram_md5.c
+ @echo "$(CC) -DMACRO_PREDEF auths/cram_md5.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/cram_md5.c
+macro-cyrus_sasl.o : auths/cyrus_sasl.c
+ @echo "$(CC) -DMACRO_PREDEF auths/cyrus_sasl.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/cyrus_sasl.c
+macro-dovecot.o: auths/dovecot.c
+ @echo "$(CC) -DMACRO_PREDEF auths/dovecot.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/dovecot.c
+macro-gsasl_exim.o : auths/gsasl_exim.c
+ @echo "$(CC) -DMACRO_PREDEF auths/gsasl_exim.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/gsasl_exim.c
+macro-heimdal_gssapi.o: auths/heimdal_gssapi.c
+ @echo "$(CC) -DMACRO_PREDEF auths/heimdal_gssapi.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/heimdal_gssapi.c
+macro-plaintext.o : auths/plaintext.c
+ @echo "$(CC) -DMACRO_PREDEF auths/plaintext.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/plaintext.c
+macro-spa.o : auths/spa.c
+ @echo "$(CC) -DMACRO_PREDEF auths/spa.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/spa.c
+macro-tls.o: auths/tls.c
+ @echo "$(CC) -DMACRO_PREDEF auths/tls.c"
+ $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/tls.c
+
+macro_predef: $(OBJ_MACRO)
+ @echo "$(LNCC) -o $@"
+ $(FE)$(LNCC) -o $@ $(LFLAGS) $(OBJ_MACRO)
+
+macro.c: macro_predef
+ ./macro_predef > macro.c
# This target is recognized specially by GNU make. It records those targets
# that do not correspond to files that are being built and which should
@@ -331,13 +451,13 @@ OBJ_LOOKUPS = lookups/lf_quote.o lookups/lf_check_file.o lookups/lf_sqlperform.o
OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
- filtertest.o globals.o dkim.o hash.o \
+ filtertest.o globals.o dkim.o dkim_transport.o hash.o \
header.o host.o ip.o log.o lss.o match.o moan.o \
os.o parse.o queue.o \
rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \
- environment.o \
+ environment.o macro.o \
$(OBJ_LOOKUPS) \
local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN) \
$(OBJ_EXPERIMENTAL)
@@ -452,7 +572,7 @@ OBJ_MONBIN = util-spool_in.o \
util-store.o \
util-string.o \
util-queue.o \
- tod.o \
+ util-tod.o \
tree.o \
$(MONBIN)
@@ -557,7 +677,8 @@ exim_tidydb.o: $(HDRS) exim_dbutil.c
exim_dbmbuild.o: $(HDRS) exim_dbmbuild.c
@echo "$(CC) exim_dbmbuild.c"
- $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -o exim_dbmbuild.o exim_dbmbuild.c
+ $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY \
+ -o exim_dbmbuild.o exim_dbmbuild.c
# Utilities use special versions of some modules - typically with debugging
# calls cut out.
@@ -578,6 +699,10 @@ util-queue.o: $(HDRS) queue.c
@echo "$(CC) -DCOMPILE_UTILITY queue.c"
$(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY -o util-queue.o queue.c
+util-tod.o: $(HDRS) tod.c
+ @echo "$(CC) -DCOMPILE_UTILITY tod.c"
+ $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY -o util-tod.o tod.c
+
util-os.o: $(HDRS) os.c
@echo "$(CC) -DCOMPILE_UTILITY os.c"
$(FE)$(CC) -c $(CFLAGS) $(INCLUDE) \
@@ -602,7 +727,7 @@ crypt16.o: $(HDRS) crypt16.c
daemon.o: $(HDRS) daemon.c
dbfn.o: $(HDRS) dbfn.c
debug.o: $(HDRS) debug.c
-deliver.o: $(HDRS) deliver.c
+deliver.o: $(HDRS) transports/smtp.h deliver.c
directory.o: $(HDRS) directory.c
dns.o: $(HDRS) dns.c
enq.o: $(HDRS) enq.c
@@ -647,6 +772,7 @@ transport.o: $(HDRS) transport.c
tree.o: $(HDRS) tree.c
verify.o: $(HDRS) transports/smtp.h verify.c
dkim.o: $(HDRS) pdkim/pdkim.h dkim.c
+dkim_transport.o: $(HDRS) dkim_transport.c
# Dependencies for WITH_CONTENT_SCAN modules
diff --git a/src/OS/os.c-FreeBSD b/src/OS/os.c-FreeBSD
new file mode 100644
index 000000000..715a9ed42
--- /dev/null
+++ b/src/OS/os.c-FreeBSD
@@ -0,0 +1,24 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2017 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* FreeBSD-specific code. This is concatenated onto the generic
+src/os.c file. */
+
+
+/*************
+* Sendfile *
+*************/
+
+ssize_t
+os_sendfile(int out, int in, off_t * off, size_t cnt)
+{
+off_t written;
+return sendfile(in, out, *off, cnt, NULL, &written, 0) < 0
+ ? (ssize_t) -1 : (ssize_t) written;
+}
+
+/* End of os.c-Linux */
diff --git a/src/OS/os.c-Linux b/src/OS/os.c-Linux
index 4bca77615..dd65c8b39 100644
--- a/src/OS/os.c-Linux
+++ b/src/OS/os.c-Linux
@@ -150,4 +150,16 @@ return yield;
#endif /* FIND_RUNNING_INTERFACES */
+
+/*************
+* Sendfile *
+*************/
+#include <sys/sendfile.h>
+
+ssize_t
+os_sendfile(int out, int in, off_t * off, size_t cnt)
+{
+return sendfile(out, in, off, cnt);
+}
+
/* End of os.c-Linux */
diff --git a/src/OS/os.h-FreeBSD b/src/OS/os.h-FreeBSD
index bf43e0a3c..3a06e766e 100644
--- a/src/OS/os.h-FreeBSD
+++ b/src/OS/os.h-FreeBSD
@@ -1,5 +1,7 @@
/* Exim: OS-specific C header file for FreeBSD */
+#include <sys/types.h>
+
#define HAVE_BSD_GETLOADAVG
#define HAVE_SETCLASSRESOURCES
#define HAVE_MMAP
@@ -34,4 +36,29 @@ typedef struct flock flock_t;
/* for more specific version constraints, include <sys/param.h> and look at
* __FreeBSD_version */
+
+/* When using DKIM, setting OS_SENDFILE can increase
+performance on outgoing mail a bit. */
+
+#define OS_SENDFILE
+extern ssize_t os_sendfile(int, int, off_t *, size_t);
+
+
+/*******************/
+
+/* TCP_FASTOPEN support. There does not seems to be a
+MSG_FASTOPEN defined yet... */
+
+#include <netinet/tcp.h> /* for TCP_FASTOPEN */
+#include <sys/socket.h> /* for MSG_FASTOPEN */
+#if defined(TCP_FASTOPEN) && !defined(MSG_FASTOPEN)
+# define MSG_FASTOPEN 0x20000000
+#endif
+
+/* for TCP state-variable values, for TFO logging */
+#include <netinet/tcp_fsm.h>
+#define TCP_SYN_RECV TCPS_SYN_RECEIVED
+
+/*******************/
+
/* End */
diff --git a/src/OS/os.h-Linux b/src/OS/os.h-Linux
index cc1cef99b..cc1f3cab2 100644
--- a/src/OS/os.h-Linux
+++ b/src/OS/os.h-Linux
@@ -5,6 +5,7 @@ does not pull in <features.h>. Best to just pull it in now and have done
with the issue. */
#include <features.h>
+#include <sys/types.h>
#define CRYPT_H
@@ -15,12 +16,14 @@ with the issue. */
#define NO_IP_VAR_H
#define SIG_IGN_WORKS
-/* When using the DKIM, setting HAVE_LINUX_SENDFILE can increase
+/* When using DKIM, setting OS_SENDFILE can increase
performance on outgoing mail a bit. Note: With older glibc versions
this setting will conflict with the _FILE_OFFSET_BITS=64 setting
-defined as part of the Linux CFLAGS. */
+defined as part of the Linux CFLAGS. As of 2017 those are declared
+to be too old to build by default. */
-/* #define HAVE_LINUX_SENDFILE */
+#define OS_SENDFILE
+extern ssize_t os_sendfile(int, int, off_t *, size_t);
#define F_FREESP O_TRUNC
typedef struct flock flock_t;
@@ -29,8 +32,8 @@ typedef struct flock flock_t;
#define OS_STRSIGNAL
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD_kernel__)
-#define SIOCGIFCONF_GIVES_ADDR
-#define HAVE_SYS_MOUNT_H
+# define SIOCGIFCONF_GIVES_ADDR
+# define HAVE_SYS_MOUNT_H
#endif
#if defined(__linux__)
@@ -69,6 +72,8 @@ then change the 0 to 1 in the next block. */
# define EXIM_HAVE_OPENAT
#endif
+/* TCP Fast Open support */
+
#include <netinet/tcp.h> /* for TCP_FASTOPEN */
#include <sys/socket.h> /* for MSG_FASTOPEN */
#if defined(TCP_FASTOPEN) && !defined(MSG_FASTOPEN)
diff --git a/src/OS/Makefile-AIX b/src/OS/unsupported/Makefile-AIX
index fc32aa286..fc32aa286 100644
--- a/src/OS/Makefile-AIX
+++ b/src/OS/unsupported/Makefile-AIX
diff --git a/src/OS/Makefile-BSDI b/src/OS/unsupported/Makefile-BSDI
index d56aa9b57..d56aa9b57 100644
--- a/src/OS/Makefile-BSDI
+++ b/src/OS/unsupported/Makefile-BSDI
diff --git a/src/OS/Makefile-CYGWIN b/src/OS/unsupported/Makefile-CYGWIN
index 006e9feff..006e9feff 100644
--- a/src/OS/Makefile-CYGWIN
+++ b/src/OS/unsupported/Makefile-CYGWIN
diff --git a/src/OS/Makefile-DGUX b/src/OS/unsupported/Makefile-DGUX
index 667c63f49..667c63f49 100644
--- a/src/OS/Makefile-DGUX
+++ b/src/OS/unsupported/Makefile-DGUX
diff --git a/src/OS/Makefile-Darwin b/src/OS/unsupported/Makefile-Darwin
index be0d9520b..be0d9520b 100644
--- a/src/OS/Makefile-Darwin
+++ b/src/OS/unsupported/Makefile-Darwin
diff --git a/src/OS/Makefile-DragonFly b/src/OS/unsupported/Makefile-DragonFly
index c49c59ffc..c49c59ffc 100644
--- a/src/OS/Makefile-DragonFly
+++ b/src/OS/unsupported/Makefile-DragonFly
diff --git a/src/OS/Makefile-GNU b/src/OS/unsupported/Makefile-GNU
index e46434187..e46434187 100644
--- a/src/OS/Makefile-GNU
+++ b/src/OS/unsupported/Makefile-GNU
diff --git a/src/OS/Makefile-GNUkFreeBSD b/src/OS/unsupported/Makefile-GNUkFreeBSD
index 801928143..801928143 100644
--- a/src/OS/Makefile-GNUkFreeBSD
+++ b/src/OS/unsupported/Makefile-GNUkFreeBSD
diff --git a/src/OS/Makefile-GNUkNetBSD b/src/OS/unsupported/Makefile-GNUkNetBSD
index 801928143..801928143 100644
--- a/src/OS/Makefile-GNUkNetBSD
+++ b/src/OS/unsupported/Makefile-GNUkNetBSD
diff --git a/src/OS/Makefile-HI-OSF b/src/OS/unsupported/Makefile-HI-OSF
index da3d487a4..da3d487a4 100644
--- a/src/OS/Makefile-HI-OSF
+++ b/src/OS/unsupported/Makefile-HI-OSF
diff --git a/src/OS/Makefile-HI-UX b/src/OS/unsupported/Makefile-HI-UX
index 870ee8460..870ee8460 100644
--- a/src/OS/Makefile-HI-UX
+++ b/src/OS/unsupported/Makefile-HI-UX
diff --git a/src/OS/Makefile-HP-UX b/src/OS/unsupported/Makefile-HP-UX
index ea35144bb..ea35144bb 100644
--- a/src/OS/Makefile-HP-UX
+++ b/src/OS/unsupported/Makefile-HP-UX
diff --git a/src/OS/Makefile-HP-UX-9 b/src/OS/unsupported/Makefile-HP-UX-9
index 153000944..153000944 100644
--- a/src/OS/Makefile-HP-UX-9
+++ b/src/OS/unsupported/Makefile-HP-UX-9
diff --git a/src/OS/Makefile-IRIX b/src/OS/unsupported/Makefile-IRIX
index 7b9578339..7b9578339 100644
--- a/src/OS/Makefile-IRIX
+++ b/src/OS/unsupported/Makefile-IRIX
diff --git a/src/OS/Makefile-IRIX6 b/src/OS/unsupported/Makefile-IRIX6
index be0113846..be0113846 100644
--- a/src/OS/Makefile-IRIX6
+++ b/src/OS/unsupported/Makefile-IRIX6
diff --git a/src/OS/Makefile-IRIX632 b/src/OS/unsupported/Makefile-IRIX632
index b567fc64e..b567fc64e 100644
--- a/src/OS/Makefile-IRIX632
+++ b/src/OS/unsupported/Makefile-IRIX632
diff --git a/src/OS/Makefile-IRIX65 b/src/OS/unsupported/Makefile-IRIX65
index 50e77450a..50e77450a 100644
--- a/src/OS/Makefile-IRIX65
+++ b/src/OS/unsupported/Makefile-IRIX65
diff --git a/src/OS/Makefile-NetBSD b/src/OS/unsupported/Makefile-NetBSD
index 35d03a24a..35d03a24a 100644
--- a/src/OS/Makefile-NetBSD
+++ b/src/OS/unsupported/Makefile-NetBSD
diff --git a/src/OS/Makefile-NetBSD-a.out b/src/OS/unsupported/Makefile-NetBSD-a.out
index e210efdda..e210efdda 100644
--- a/src/OS/Makefile-NetBSD-a.out
+++ b/src/OS/unsupported/Makefile-NetBSD-a.out
diff --git a/src/OS/Makefile-OSF1 b/src/OS/unsupported/Makefile-OSF1
index 811ca07a9..811ca07a9 100644
--- a/src/OS/Makefile-OSF1
+++ b/src/OS/unsupported/Makefile-OSF1
diff --git a/src/OS/Makefile-OpenUNIX b/src/OS/unsupported/Makefile-OpenUNIX
index e4d726158..e4d726158 100644
--- a/src/OS/Makefile-OpenUNIX
+++ b/src/OS/unsupported/Makefile-OpenUNIX
diff --git a/src/OS/Makefile-QNX b/src/OS/unsupported/Makefile-QNX
index 3cf81c41b..3cf81c41b 100644
--- a/src/OS/Makefile-QNX
+++ b/src/OS/unsupported/Makefile-QNX
diff --git a/src/OS/Makefile-SCO b/src/OS/unsupported/Makefile-SCO
index baa61d80b..baa61d80b 100644
--- a/src/OS/Makefile-SCO
+++ b/src/OS/unsupported/Makefile-SCO
diff --git a/src/OS/Makefile-SCO_SV b/src/OS/unsupported/Makefile-SCO_SV
index 249b81a0f..249b81a0f 100644
--- a/src/OS/Makefile-SCO_SV
+++ b/src/OS/unsupported/Makefile-SCO_SV
diff --git a/src/OS/Makefile-SunOS4 b/src/OS/unsupported/Makefile-SunOS4
index c876998e5..c876998e5 100644
--- a/src/OS/Makefile-SunOS4
+++ b/src/OS/unsupported/Makefile-SunOS4
diff --git a/src/OS/Makefile-SunOS5-hal b/src/OS/unsupported/Makefile-SunOS5-hal
index 05ea893af..05ea893af 100644
--- a/src/OS/Makefile-SunOS5-hal
+++ b/src/OS/unsupported/Makefile-SunOS5-hal
diff --git a/src/OS/Makefile-ULTRIX b/src/OS/unsupported/Makefile-ULTRIX
index 9e912b3cb..9e912b3cb 100644
--- a/src/OS/Makefile-ULTRIX
+++ b/src/OS/unsupported/Makefile-ULTRIX
diff --git a/src/OS/Makefile-UNIX_SV b/src/OS/unsupported/Makefile-UNIX_SV
index bfcfae1c0..bfcfae1c0 100644
--- a/src/OS/Makefile-UNIX_SV
+++ b/src/OS/unsupported/Makefile-UNIX_SV
diff --git a/src/OS/Makefile-USG b/src/OS/unsupported/Makefile-USG
index 753a2d7e8..753a2d7e8 100644
--- a/src/OS/Makefile-USG
+++ b/src/OS/unsupported/Makefile-USG
diff --git a/src/OS/Makefile-Unixware7 b/src/OS/unsupported/Makefile-Unixware7
index 88a883801..88a883801 100644
--- a/src/OS/Makefile-Unixware7
+++ b/src/OS/unsupported/Makefile-Unixware7
diff --git a/src/OS/Makefile-mips b/src/OS/unsupported/Makefile-mips
index ff3313937..ff3313937 100644
--- a/src/OS/Makefile-mips
+++ b/src/OS/unsupported/Makefile-mips
diff --git a/src/OS/unsupported/README b/src/OS/unsupported/README
new file mode 100644
index 000000000..73790aea2
--- /dev/null
+++ b/src/OS/unsupported/README
@@ -0,0 +1,14 @@
+Files in this directory are historical. They may have worked once but the
+project has no assurance that they still do.
+
+If you need to use one for a build for your platform, copy it up one directory
+level first. We'll reinstate it given a current version and evidence of testing.
+For the latter please look into the project regression testsuite, and please
+consider operating a buildfarm animal in the long term (it runs the testsuite).
+
+The buildfarm status page is:
+ https://buildfarm.exim.org/cgi-bin/show_status.pl
+There's a "register" link there with a link to how-to instructions. Please do
+monitor the status of your animal on an ongoing basis. The exim-users or
+exim-dev mailinglist are good places to ask for help and to discuss any regressions
+seen in test runs. There is also the #exim IRC channel on Freenode.
diff --git a/src/OS/os.c-BSDI b/src/OS/unsupported/os.c-BSDI
index 3cef2ac6d..03a7a1cef 100644
--- a/src/OS/os.c-BSDI
+++ b/src/OS/unsupported/os.c-BSDI
@@ -12,8 +12,8 @@ src/os.c file. */
#define OS_UNSETENV
int
-os_unsetenv(const unsigned char * name)
+os_unsetenv(const uschar * name)
{
-unsetenv((char *)name);
+unsetenv(CS name);
return 0;
}
diff --git a/src/OS/os.c-GNU b/src/OS/unsupported/os.c-GNU
index e5d6ff66c..e5d6ff66c 100644
--- a/src/OS/os.c-GNU
+++ b/src/OS/unsupported/os.c-GNU
diff --git a/src/OS/os.c-HI-OSF b/src/OS/unsupported/os.c-HI-OSF
index 5e3d336f2..5e3d336f2 100644
--- a/src/OS/os.c-HI-OSF
+++ b/src/OS/unsupported/os.c-HI-OSF
diff --git a/src/OS/os.c-HP-UX b/src/OS/unsupported/os.c-HP-UX
index fdd8708a2..fdd8708a2 100644
--- a/src/OS/os.c-HP-UX
+++ b/src/OS/unsupported/os.c-HP-UX
diff --git a/src/OS/os.c-IRIX b/src/OS/unsupported/os.c-IRIX
index 487091aeb..1f6b0e1b1 100644
--- a/src/OS/os.c-IRIX
+++ b/src/OS/unsupported/os.c-IRIX
@@ -82,7 +82,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
if ((ifam->ifam_addrs & RTA_IFA) != 0)
{
- char *cp = (char *)mask;
+ char *cp = CS mask;
struct sockaddr *sa = (struct sockaddr *)mask;
ADVANCE(cp, sa);
addr = (struct sockaddr_in *)cp;
diff --git a/src/OS/os.c-IRIX6 b/src/OS/unsupported/os.c-IRIX6
index 487091aeb..1f6b0e1b1 100644
--- a/src/OS/os.c-IRIX6
+++ b/src/OS/unsupported/os.c-IRIX6
@@ -82,7 +82,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
if ((ifam->ifam_addrs & RTA_IFA) != 0)
{
- char *cp = (char *)mask;
+ char *cp = CS mask;
struct sockaddr *sa = (struct sockaddr *)mask;
ADVANCE(cp, sa);
addr = (struct sockaddr_in *)cp;
diff --git a/src/OS/os.c-IRIX632 b/src/OS/unsupported/os.c-IRIX632
index 487091aeb..1f6b0e1b1 100644
--- a/src/OS/os.c-IRIX632
+++ b/src/OS/unsupported/os.c-IRIX632
@@ -82,7 +82,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
if ((ifam->ifam_addrs & RTA_IFA) != 0)
{
- char *cp = (char *)mask;
+ char *cp = CS mask;
struct sockaddr *sa = (struct sockaddr *)mask;
ADVANCE(cp, sa);
addr = (struct sockaddr_in *)cp;
diff --git a/src/OS/os.c-IRIX65 b/src/OS/unsupported/os.c-IRIX65
index 487091aeb..1f6b0e1b1 100644
--- a/src/OS/os.c-IRIX65
+++ b/src/OS/unsupported/os.c-IRIX65
@@ -82,7 +82,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
if ((ifam->ifam_addrs & RTA_IFA) != 0)
{
- char *cp = (char *)mask;
+ char *cp = CS mask;
struct sockaddr *sa = (struct sockaddr *)mask;
ADVANCE(cp, sa);
addr = (struct sockaddr_in *)cp;
diff --git a/src/OS/os.c-OSF1 b/src/OS/unsupported/os.c-OSF1
index ad91b63d1..ad91b63d1 100644
--- a/src/OS/os.c-OSF1
+++ b/src/OS/unsupported/os.c-OSF1
diff --git a/src/OS/os.c-cygwin b/src/OS/unsupported/os.c-cygwin
index c9464aae2..c9464aae2 100644
--- a/src/OS/os.c-cygwin
+++ b/src/OS/unsupported/os.c-cygwin
diff --git a/src/OS/os.h-AIX b/src/OS/unsupported/os.h-AIX
index 5cd4501a4..5cd4501a4 100644
--- a/src/OS/os.h-AIX
+++ b/src/OS/unsupported/os.h-AIX
diff --git a/src/OS/os.h-BSDI b/src/OS/unsupported/os.h-BSDI
index a1705ec95..a1705ec95 100644
--- a/src/OS/os.h-BSDI
+++ b/src/OS/unsupported/os.h-BSDI
diff --git a/src/OS/os.h-DGUX b/src/OS/unsupported/os.h-DGUX
index 9040f0e72..9040f0e72 100644
--- a/src/OS/os.h-DGUX
+++ b/src/OS/unsupported/os.h-DGUX
diff --git a/src/OS/os.h-Darwin b/src/OS/unsupported/os.h-Darwin
index f4087404e..f4087404e 100644
--- a/src/OS/os.h-Darwin
+++ b/src/OS/unsupported/os.h-Darwin
diff --git a/src/OS/os.h-DragonFly b/src/OS/unsupported/os.h-DragonFly
index 4c2f1d508..4c2f1d508 100644
--- a/src/OS/os.h-DragonFly
+++ b/src/OS/unsupported/os.h-DragonFly
diff --git a/src/OS/os.h-GNU b/src/OS/unsupported/os.h-GNU
index 44993163d..44993163d 100644
--- a/src/OS/os.h-GNU
+++ b/src/OS/unsupported/os.h-GNU
diff --git a/src/OS/os.h-GNUkFreeBSD b/src/OS/unsupported/os.h-GNUkFreeBSD
index ab3503131..ab3503131 100644
--- a/src/OS/os.h-GNUkFreeBSD
+++ b/src/OS/unsupported/os.h-GNUkFreeBSD
diff --git a/src/OS/os.h-GNUkNetBSD b/src/OS/unsupported/os.h-GNUkNetBSD
index bc3bc259d..bc3bc259d 100644
--- a/src/OS/os.h-GNUkNetBSD
+++ b/src/OS/unsupported/os.h-GNUkNetBSD
diff --git a/src/OS/os.h-HI-OSF b/src/OS/unsupported/os.h-HI-OSF
index 0f50fb660..0f50fb660 100644
--- a/src/OS/os.h-HI-OSF
+++ b/src/OS/unsupported/os.h-HI-OSF
diff --git a/src/OS/os.h-HI-UX b/src/OS/unsupported/os.h-HI-UX
index f3df9638c..f3df9638c 100644
--- a/src/OS/os.h-HI-UX
+++ b/src/OS/unsupported/os.h-HI-UX
diff --git a/src/OS/os.h-HP-UX b/src/OS/unsupported/os.h-HP-UX
index 4998734f6..4998734f6 100644
--- a/src/OS/os.h-HP-UX
+++ b/src/OS/unsupported/os.h-HP-UX
diff --git a/src/OS/os.h-HP-UX-9 b/src/OS/unsupported/os.h-HP-UX-9
index 5a260d607..5a260d607 100644
--- a/src/OS/os.h-HP-UX-9
+++ b/src/OS/unsupported/os.h-HP-UX-9
diff --git a/src/OS/os.h-IRIX b/src/OS/unsupported/os.h-IRIX
index 1d4bf46ba..1d4bf46ba 100644
--- a/src/OS/os.h-IRIX
+++ b/src/OS/unsupported/os.h-IRIX
diff --git a/src/OS/os.h-IRIX6 b/src/OS/unsupported/os.h-IRIX6
index bf3076713..bf3076713 100644
--- a/src/OS/os.h-IRIX6
+++ b/src/OS/unsupported/os.h-IRIX6
diff --git a/src/OS/os.h-IRIX632 b/src/OS/unsupported/os.h-IRIX632
index 90f1c582c..90f1c582c 100644
--- a/src/OS/os.h-IRIX632
+++ b/src/OS/unsupported/os.h-IRIX632
diff --git a/src/OS/os.h-IRIX65 b/src/OS/unsupported/os.h-IRIX65
index 4b248fe36..4b248fe36 100644
--- a/src/OS/os.h-IRIX65
+++ b/src/OS/unsupported/os.h-IRIX65
diff --git a/src/OS/os.h-NetBSD b/src/OS/unsupported/os.h-NetBSD
index d2d3e0d82..d2d3e0d82 100644
--- a/src/OS/os.h-NetBSD
+++ b/src/OS/unsupported/os.h-NetBSD
diff --git a/src/OS/os.h-NetBSD-a.out b/src/OS/unsupported/os.h-NetBSD-a.out
index 29a8feeff..29a8feeff 100644
--- a/src/OS/os.h-NetBSD-a.out
+++ b/src/OS/unsupported/os.h-NetBSD-a.out
diff --git a/src/OS/os.h-OSF1 b/src/OS/unsupported/os.h-OSF1
index 6b5fa4973..6b5fa4973 100644
--- a/src/OS/os.h-OSF1
+++ b/src/OS/unsupported/os.h-OSF1
diff --git a/src/OS/os.h-OpenUNIX b/src/OS/unsupported/os.h-OpenUNIX
index 67d1063b0..67d1063b0 100644
--- a/src/OS/os.h-OpenUNIX
+++ b/src/OS/unsupported/os.h-OpenUNIX
diff --git a/src/OS/os.h-QNX b/src/OS/unsupported/os.h-QNX
index 798f799ed..798f799ed 100644
--- a/src/OS/os.h-QNX
+++ b/src/OS/unsupported/os.h-QNX
diff --git a/src/OS/os.h-SCO b/src/OS/unsupported/os.h-SCO
index e5e915ed0..e5e915ed0 100644
--- a/src/OS/os.h-SCO
+++ b/src/OS/unsupported/os.h-SCO
diff --git a/src/OS/os.h-SCO_SV b/src/OS/unsupported/os.h-SCO_SV
index 0ca29f74a..0ca29f74a 100644
--- a/src/OS/os.h-SCO_SV
+++ b/src/OS/unsupported/os.h-SCO_SV
diff --git a/src/OS/os.h-SunOS4 b/src/OS/unsupported/os.h-SunOS4
index 65556204c..65556204c 100644
--- a/src/OS/os.h-SunOS4
+++ b/src/OS/unsupported/os.h-SunOS4
diff --git a/src/OS/os.h-SunOS5-hal b/src/OS/unsupported/os.h-SunOS5-hal
index cd9e877a9..cd9e877a9 100644
--- a/src/OS/os.h-SunOS5-hal
+++ b/src/OS/unsupported/os.h-SunOS5-hal
diff --git a/src/OS/os.h-ULTRIX b/src/OS/unsupported/os.h-ULTRIX
index 08db5aec8..08db5aec8 100644
--- a/src/OS/os.h-ULTRIX
+++ b/src/OS/unsupported/os.h-ULTRIX
diff --git a/src/OS/os.h-UNIX_SV b/src/OS/unsupported/os.h-UNIX_SV
index 4943a07de..4943a07de 100644
--- a/src/OS/os.h-UNIX_SV
+++ b/src/OS/unsupported/os.h-UNIX_SV
diff --git a/src/OS/os.h-USG b/src/OS/unsupported/os.h-USG
index e76922067..e76922067 100644
--- a/src/OS/os.h-USG
+++ b/src/OS/unsupported/os.h-USG
diff --git a/src/OS/os.h-Unixware7 b/src/OS/unsupported/os.h-Unixware7
index 4d3ed42f2..4d3ed42f2 100644
--- a/src/OS/os.h-Unixware7
+++ b/src/OS/unsupported/os.h-Unixware7
diff --git a/src/OS/os.h-cygwin b/src/OS/unsupported/os.h-cygwin
index 6ef59e0cc..6ef59e0cc 100644
--- a/src/OS/os.h-cygwin
+++ b/src/OS/unsupported/os.h-cygwin
diff --git a/src/OS/os.h-mips b/src/OS/unsupported/os.h-mips
index 325e3a134..325e3a134 100644
--- a/src/OS/os.h-mips
+++ b/src/OS/unsupported/os.h-mips
diff --git a/src/exim_monitor/em_globals.c b/src/exim_monitor/em_globals.c
index 54032362c..46ad834da 100644
--- a/src/exim_monitor/em_globals.c
+++ b/src/exim_monitor/em_globals.c
@@ -191,7 +191,7 @@ uschar *queue_name = US"";
int received_count = 0;
uschar *received_protocol = NULL;
-int received_time = 0;
+struct timeval received_time = { 0, 0 };
int recipients_count = 0;
recipient_item *recipients_list = NULL;
int recipients_list_max = 0;
diff --git a/src/exim_monitor/em_hdr.h b/src/exim_monitor/em_hdr.h
index a7e874a87..67294368a 100644
--- a/src/exim_monitor/em_hdr.h
+++ b/src/exim_monitor/em_hdr.h
@@ -100,6 +100,7 @@ typedef void hctx;
#include "local_scan.h"
#include "structs.h"
+#include "blob.h"
#include "globals.h"
#include "dbstuff.h"
#include "functions.h"
diff --git a/src/exim_monitor/em_log.c b/src/exim_monitor/em_log.c
index 9ff994ced..73aa0e567 100644
--- a/src/exim_monitor/em_log.c
+++ b/src/exim_monitor/em_log.c
@@ -281,12 +281,8 @@ if (LOG != NULL)
if (strstric(buffer, US"frozen", FALSE) != NULL)
{
queue_item *qq = find_queue(id, queue_noop, 0);
- if (qq != NULL)
- {
- if (strstric(buffer, US"unfrozen", FALSE) != NULL)
- qq->frozen = FALSE;
- else qq->frozen = TRUE;
- }
+ if (qq)
+ qq->frozen = strstric(buffer, US"unfrozen", FALSE) == NULL;
}
/* Notice defer messages, and add the destination if it
diff --git a/src/exim_monitor/em_main.c b/src/exim_monitor/em_main.c
index 3034a041c..00471ce3d 100644
--- a/src/exim_monitor/em_main.c
+++ b/src/exim_monitor/em_main.c
@@ -631,7 +631,7 @@ signal(SIGCHLD, sigchld_handler);
/* Get the buffer for storing the string for the log display. */
-log_display_buffer = (uschar *)store_malloc(log_buffer_size);
+log_display_buffer = US store_malloc(log_buffer_size);
log_display_buffer[0] = 0;
/* Initialize the data structures for the stripcharts */
diff --git a/src/exim_monitor/em_menu.c b/src/exim_monitor/em_menu.c
index 6deb909da..935e82687 100644
--- a/src/exim_monitor/em_menu.c
+++ b/src/exim_monitor/em_menu.c
@@ -174,7 +174,7 @@ static void
bodyAction(Widget w, XtPointer client_data, XtPointer call_data)
{
int i;
-Widget text = text_create((uschar *)client_data, text_depth);
+Widget text = text_create(US client_data, text_depth);
FILE *f = NULL;
w = w; /* Keep picky compilers happy */
@@ -183,7 +183,7 @@ call_data = call_data;
for (i = 0; i < (spool_is_split? 2:1); i++)
{
uschar * fname;
- message_subdir[0] = i != 0 ? ((uschar *)client_data)[5] : 0;
+ message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
fname = spool_fname(US"input", message_subdir, US client_data, US"-D");
if ((f = fopen(CS fname, "r")))
break;
@@ -334,9 +334,9 @@ if (!delivery)
if (rc == 0 && Ustrcmp(action + Ustrlen(action) - 4, "-Mes") == 0)
{
queue_item *q = find_queue(id, queue_noop, 0);
- if (q != NULL)
+ if (q)
{
- if (q->sender != NULL) store_free(q->sender);
+ if (q->sender) store_free(q->sender);
q->sender = store_malloc(Ustrlen(address_arg) + 1);
Ustrcpy(q->sender, address_arg);
}
@@ -411,7 +411,7 @@ static void deliverAction(Widget w, XtPointer client_data, XtPointer call_data)
{
w = w; /* Keep picky compilers happy */
call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-v -M", US"");
+ActOnMessage(US client_data, US"-v -M", US"");
}
@@ -424,7 +424,7 @@ static void freezeAction(Widget w, XtPointer client_data, XtPointer call_data)
{
w = w; /* Keep picky compilers happy */
call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mf", US"");
+ActOnMessage(US client_data, US"-Mf", US"");
}
@@ -437,7 +437,7 @@ static void thawAction(Widget w, XtPointer client_data, XtPointer call_data)
{
w = w; /* Keep picky compilers happy */
call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mt", US"");
+ActOnMessage(US client_data, US"-Mt", US"");
}
@@ -624,7 +624,7 @@ static void giveupAction(Widget w, XtPointer client_data, XtPointer call_data)
{
w = w; /* Keep picky compilers happy */
call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-v -Mg", US"");
+ActOnMessage(US client_data, US"-v -Mg", US"");
}
@@ -637,7 +637,7 @@ static void removeAction(Widget w, XtPointer client_data, XtPointer call_data)
{
w = w; /* Keep picky compilers happy */
call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mrm", US"");
+ActOnMessage(US client_data, US"-Mrm", US"");
}
@@ -650,7 +650,7 @@ static void headersAction(Widget w, XtPointer client_data, XtPointer call_data)
{
uschar buffer[256];
header_line *h, *next;
-Widget text = text_create((uschar *)client_data, text_depth);
+Widget text = text_create(US client_data, text_depth);
void *reset_point;
w = w; /* Keep picky compilers happy */
@@ -661,7 +661,7 @@ Then use Exim's function to read the header. */
reset_point = store_get(0);
-sprintf(CS buffer, "%s-H", (uschar *)client_data);
+sprintf(CS buffer, "%s-H", US client_data);
if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
{
if (errno == ERRNO_SPOOLFORMAT)
diff --git a/src/exim_monitor/em_queue.c b/src/exim_monitor/em_queue.c
index 4bdc57ab9..e6b1e91d9 100644
--- a/src/exim_monitor/em_queue.c
+++ b/src/exim_monitor/em_queue.c
@@ -63,7 +63,8 @@ if it is dest_remove, remove if present and return NULL. The
address is lowercased to start with, unless it begins with
"*", which it does for error messages. */
-dest_item *find_dest(queue_item *q, uschar *name, int action, BOOL caseless)
+dest_item *
+find_dest(queue_item *q, uschar *name, int action, BOOL caseless)
{
dest_item *dd;
dest_item **d = &(q->destinations);
@@ -108,7 +109,8 @@ return dd;
* Clean up a dead queue item *
*************************************************/
-static void clean_up(queue_item *p)
+static void
+clean_up(queue_item *p)
{
dest_item *dd = p->destinations;
while (dd != NULL)
@@ -149,7 +151,8 @@ return node;
* Set up new queue item *
*************************************************/
-static queue_item *set_up(uschar *name, int dir_char)
+static queue_item *
+set_up(uschar *name, int dir_char)
{
int i, rc, save_errno;
struct stat statdata;
@@ -162,7 +165,7 @@ uschar buffer[256];
q->next = q->prev = NULL;
q->destinations = NULL;
-Ustrcpy(q->name, name);
+Ustrncpy(q->name, name, sizeof(q->name));
q->seen = TRUE;
q->frozen = FALSE;
q->dir_char = dir_char;
@@ -201,7 +204,7 @@ if it's there. */
else
{
- q->update_time = q->input_time = received_time;
+ q->update_time = q->input_time = received_time.tv_sec;
if ((p = strstric(sender_address+1, qualify_domain, FALSE)) != NULL &&
*(--p) == '@') *p = 0;
}
@@ -331,7 +334,8 @@ while (p != NULL)
-queue_item *find_queue(uschar *name, int action, int dir_char)
+queue_item *
+find_queue(uschar *name, int action, int dir_char)
{
int first = 0;
int last = queue_index_size - 1;
diff --git a/src/exim_monitor/em_version.c b/src/exim_monitor/em_version.c
index a10aac4fb..0279654ac 100644
--- a/src/exim_monitor/em_version.c
+++ b/src/exim_monitor/em_version.c
@@ -25,7 +25,7 @@ Ustrcpy(today, __DATE__);
if (today[4] == ' ') i = 1;
today[3] = today[6] = '-';
-version_date = (uschar *)malloc(32);
+version_date = US malloc(32);
version_date[0] = 0;
Ustrncat(version_date, today+4+i, 3-i);
Ustrncat(version_date, today, 4);
diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile
index b6f2e2e09..648960e44 100755
--- a/src/scripts/Configure-Makefile
+++ b/src/scripts/Configure-Makefile
@@ -1,4 +1,5 @@
#! /bin/sh
+export LC_ALL=C
# Shell script to build Makefile in a build directory. It must be called
# from inside the directory. It does its own checking of when to rebuild; it
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index b710c2fd8..22e5a4bd7 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -85,7 +85,7 @@ cd ..
mkdir pdkim
cd pdkim
for f in README Makefile crypt_ver.h pdkim.c \
- pdkim.h hash.c hash.h rsa.c rsa.h blob.h
+ pdkim.h hash.c hash.h signing.c signing.h blob.h
do
ln -s ../../src/pdkim/$f $f
done
@@ -107,8 +107,10 @@ for f in blob.h dbfunctions.h dbstuff.h exim.h functions.h globals.h \
setenv.c environment.c \
sieve.c smtp_in.c smtp_out.c spool_in.c spool_out.c std-crypto.c store.c \
string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-gnu.c tls-openssl.c \
- tod.c transport.c tree.c verify.c version.c dkim.c dkim.h dmarc.c dmarc.h \
- valgrind.h memcheck.h
+ tod.c transport.c tree.c verify.c version.c \
+ dkim.c dkim.h dkim_transport.c dmarc.c dmarc.h \
+ valgrind.h memcheck.h \
+ macro_predef.c macro_predef.h
do
ln -s ../src/$f $f
done
diff --git a/src/scripts/reversion b/src/scripts/reversion
index 9707b9c1c..45755c084 100755
--- a/src/scripts/reversion
+++ b/src/scripts/reversion
@@ -71,10 +71,41 @@ EXIM_COMPILE_NUMBER=$(expr "${EXIM_COMPILE_NUMBER:-0}" + 1)
echo "$EXIM_COMPILE_NUMBER" >cnumber.h
+# Reproducible builds, accept a build timestamp override from environ per
+# <https://reproducible-builds.org/specs/source-date-epoch/>.
+# We require a fairly modern date(1) command here, which is not portable
+# to some of the systems Exim is built on. That's okay, because the scenarios
+# are:
+# 1) Local postmaster building, not using $SOURCE_DATE_EPOCH, doesn't matter
+# 2) Packaging folks who don't care about reproducible builds
+# 3) Packaging folks who care but are using systems where date Just Works
+# 3) Packaging folks who care and can put a modern date(1) in $PATH
+# 4) Packaging folks who care and can supply us with a clean patch to support
+# their requirements
+# 5) Packaging folks who care but won't do any work to support their strange
+# old systems and want us to do the work for them. We don't care either,
+# they're SOL and have to live without reproducible builds.
+#
+exim_build_date_override=''
+if [ ".${SOURCE_DATE_EPOCH:-}" != "." ]; then
+ fmt='+%d-%b-%Y %H:%M:%S'
+ # Non-reproducible, we use __DATE__ and __TIME__ in C, which respect timezone
+ # (think localtime, not gmtime); for reproduction between systems, UTC makes
+ # more sense and the examples available use UTC without explicitly mandating
+ # it. I think that we can switch behavior and use UTC for reproducible
+ # builds without it causing any problems: nothing really cares about timezone.
+ # GNU date: "date -d @TS"
+ # BSD date: "date -r TS"
+ exim_build_date_override="$(date -u -d "@${SOURCE_DATE_EPOCH}" "$fmt" 2>/dev/null | date -u -r "${SOURCE_DATE_EPOCH}" "$fmt" 2>/dev/null)"
+fi
+
( echo '# automatically generated file - see ../scripts/reversion'
echo EXIM_RELEASE_VERSION='"'"$EXIM_RELEASE_VERSION"'"'
echo EXIM_VARIANT_VERSION='"'"$EXIM_VARIANT_VERSION"'"'
echo EXIM_COMPILE_NUMBER='"'"$EXIM_COMPILE_NUMBER"'"'
+ if [ ".${exim_build_date_override:-}" != "." ]; then
+ echo EXIM_BUILD_DATE_OVERRIDE='"'"${exim_build_date_override}"'"'
+ fi
) >version.sh
if [ ! -f version.h ]
@@ -83,6 +114,9 @@ then
echo '#define EXIM_RELEASE_VERSION "'"$EXIM_RELEASE_VERSION"'"'
echo '#define EXIM_VARIANT_VERSION "'"$EXIM_VARIANT_VERSION"'"'
echo '#define EXIM_VERSION_STR EXIM_RELEASE_VERSION EXIM_VARIANT_VERSION'
+ if [ ".${exim_build_date_override:-}" != "." ]; then
+ echo '#define EXIM_BUILD_DATE_OVERRIDE "'"${exim_build_date_override}"'"'
+ fi
) >version.h
fi
diff --git a/src/src/EDITME b/src/src/EDITME
index 5ac5a55dc..e604acd8b 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -473,6 +473,7 @@ EXIM_MONITOR=eximon.bin
# Uncomment the following line to add DMARC checking capability, implemented
# using libopendmarc libraries. You must have SPF support enabled also.
# EXPERIMENTAL_DMARC=yes
+# DMARC_TLD_FILE= /etc/exim/opendmarc.tlds
# CFLAGS += -I/usr/local/include
# LDFLAGS += -lopendmarc
diff --git a/src/src/acl.c b/src/src/acl.c
index efab1d31e..b5ffa0193 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -22,13 +22,14 @@ enum { ACL_ACCEPT, ACL_DEFER, ACL_DENY, ACL_DISCARD, ACL_DROP, ACL_REQUIRE,
/* ACL verbs */
static uschar *verbs[] = {
- US"accept",
- US"defer",
- US"deny",
- US"discard",
- US"drop",
- US"require",
- US"warn" };
+ [ACL_ACCEPT] = US"accept",
+ [ACL_DEFER] = US"defer",
+ [ACL_DENY] = US"deny",
+ [ACL_DISCARD] = US"discard",
+ [ACL_DROP] = US"drop",
+ [ACL_REQUIRE] = US"require",
+ [ACL_WARN] = US"warn"
+};
/* For each verb, the conditions for which "message" or "log_message" are used
are held as a bitmap. This is to avoid expanding the strings unnecessarily. For
@@ -36,13 +37,13 @@ are held as a bitmap. This is to avoid expanding the strings unnecessarily. For
the code. */
static int msgcond[] = {
- (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP), /* accept */
- (1<<OK), /* defer */
- (1<<OK), /* deny */
- (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP), /* discard */
- (1<<OK), /* drop */
- (1<<FAIL) | (1<<FAIL_DROP), /* require */
- (1<<OK) /* warn */
+ [ACL_ACCEPT] = (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),
+ [ACL_DEFER] = (1<<OK),
+ [ACL_DENY] = (1<<OK),
+ [ACL_DISCARD] = (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),
+ [ACL_DROP] = (1<<OK),
+ [ACL_REQUIRE] = (1<<FAIL) | (1<<FAIL_DROP),
+ [ACL_WARN] = (1<<OK)
};
/* ACL condition and modifier codes - keep in step with the table that
@@ -132,213 +133,210 @@ times. */
} condition_def;
static condition_def conditions[] = {
- { US"acl", FALSE, FALSE, 0 },
+ [ACLC_ACL] = { US"acl", FALSE, FALSE, 0 },
- { US"add_header", TRUE, TRUE,
- (unsigned int)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ [ACLC_ADD_HEADER] = { US"add_header", TRUE, TRUE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_DKIM)|
- (1<<ACL_WHERE_NOTSMTP_START)),
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_DKIM)|
+ (1<<ACL_WHERE_NOTSMTP_START)),
},
- { US"authenticated", FALSE, FALSE,
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START)|
- (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO),
+ [ACLC_AUTHENTICATED] = { US"authenticated", FALSE, FALSE,
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START)|
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO),
},
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { US"bmi_optin", TRUE, TRUE,
- (1<<ACL_WHERE_AUTH)|
- (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
+ [ACLC_BMI_OPTIN] = { US"bmi_optin", TRUE, TRUE,
+ (1<<ACL_WHERE_AUTH)|
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_MAILAUTH)|
- (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
- (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_MAILAUTH)|
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+ (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
#endif
- { US"condition", TRUE, FALSE, 0 },
- { US"continue", TRUE, TRUE, 0 },
+ [ACLC_CONDITION] = { US"condition", TRUE, FALSE, 0 },
+ [ACLC_CONTINUE] = { US"continue", TRUE, TRUE, 0 },
/* Certain types of control are always allowed, so we let it through
always and check in the control processing itself. */
- { US"control", TRUE, TRUE, 0 },
+ [ACLC_CONTROL] = { US"control", TRUE, TRUE, 0 },
#ifdef EXPERIMENTAL_DCC
- { US"dcc", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_DCC] = { US"dcc", TRUE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)),
+ (1<<ACL_WHERE_NOTSMTP)),
},
#endif
#ifdef WITH_CONTENT_SCAN
- { US"decode", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
+ [ACLC_DECODE] = { US"decode", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
#endif
- { US"delay", TRUE, TRUE, (1<<ACL_WHERE_NOTQUIT) },
+ [ACLC_DELAY] = { US"delay", TRUE, TRUE, (1<<ACL_WHERE_NOTQUIT) },
#ifndef DISABLE_DKIM
- { US"dkim_signers", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
- { US"dkim_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
+ [ACLC_DKIM_SIGNER] = { US"dkim_signers", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
+ [ACLC_DKIM_STATUS] = { US"dkim_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
#endif
#ifdef EXPERIMENTAL_DMARC
- { US"dmarc_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DATA) },
+ [ACLC_DMARC_STATUS] = { US"dmarc_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DATA) },
#endif
/* Explicit key lookups can be made in non-smtp ACLs so pass
always and check in the verify processing itself. */
- { US"dnslists", TRUE, FALSE, 0 },
+ [ACLC_DNSLISTS] = { US"dnslists", TRUE, FALSE, 0 },
- { US"domains", FALSE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_RCPT)
- |(1<<ACL_WHERE_VRFY)
+ [ACLC_DOMAINS] = { US"domains", FALSE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_RCPT)
+ |(1<<ACL_WHERE_VRFY)
#ifndef DISABLE_PRDR
- |(1<<ACL_WHERE_PRDR)
+ |(1<<ACL_WHERE_PRDR)
#endif
),
},
- { US"encrypted", FALSE, FALSE,
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_NOTSMTP_START)|
- (1<<ACL_WHERE_HELO),
+ [ACLC_ENCRYPTED] = { US"encrypted", FALSE, FALSE,
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_NOTSMTP_START)|
+ (1<<ACL_WHERE_HELO),
},
- { US"endpass", TRUE, TRUE, 0 },
+ [ACLC_ENDPASS] = { US"endpass", TRUE, TRUE, 0 },
- { US"hosts", FALSE, FALSE,
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ [ACLC_HOSTS] = { US"hosts", FALSE, FALSE,
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
- { US"local_parts", FALSE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_RCPT)
- |(1<<ACL_WHERE_VRFY)
- #ifndef DISABLE_PRDR
- |(1<<ACL_WHERE_PRDR)
- #endif
+ [ACLC_LOCAL_PARTS] = { US"local_parts", FALSE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_RCPT)
+ |(1<<ACL_WHERE_VRFY)
+#ifndef DISABLE_PRDR
+ |(1<<ACL_WHERE_PRDR)
+#endif
),
},
- { US"log_message", TRUE, TRUE, 0 },
- { US"log_reject_target", TRUE, TRUE, 0 },
- { US"logwrite", TRUE, TRUE, 0 },
+ [ACLC_LOG_MESSAGE] = { US"log_message", TRUE, TRUE, 0 },
+ [ACLC_LOG_REJECT_TARGET] = { US"log_reject_target", TRUE, TRUE, 0 },
+ [ACLC_LOGWRITE] = { US"logwrite", TRUE, TRUE, 0 },
#ifdef WITH_CONTENT_SCAN
- { US"malware", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_MALWARE] = { US"malware", TRUE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)),
+ (1<<ACL_WHERE_NOTSMTP)),
},
#endif
- { US"message", TRUE, TRUE, 0 },
+ [ACLC_MESSAGE] = { US"message", TRUE, TRUE, 0 },
#ifdef WITH_CONTENT_SCAN
- { US"mime_regex", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
+ [ACLC_MIME_REGEX] = { US"mime_regex", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
#endif
- { US"queue", TRUE, TRUE,
- (1<<ACL_WHERE_NOTSMTP)|
+ [ACLC_QUEUE] = { US"queue", TRUE, TRUE,
+ (1<<ACL_WHERE_NOTSMTP)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_DATA),
+ (1<<ACL_WHERE_DATA),
},
- { US"ratelimit", TRUE, FALSE, 0 },
- { US"recipients", FALSE, FALSE, (unsigned int) ~(1<<ACL_WHERE_RCPT) },
+ [ACLC_RATELIMIT] = { US"ratelimit", TRUE, FALSE, 0 },
+ [ACLC_RECIPIENTS] = { US"recipients", FALSE, FALSE, (unsigned int) ~(1<<ACL_WHERE_RCPT) },
#ifdef WITH_CONTENT_SCAN
- { US"regex", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_REGEX] = { US"regex", TRUE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_MIME)),
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_MIME)),
},
#endif
- { US"remove_header", TRUE, TRUE,
- (unsigned int)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ [ACLC_REMOVE_HEADER] = { US"remove_header", TRUE, TRUE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START)),
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START)),
},
- { US"sender_domains", FALSE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+ [ACLC_SENDER_DOMAINS] = { US"sender_domains", FALSE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
},
- { US"senders", FALSE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+ [ACLC_SENDERS] = { US"senders", FALSE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
},
- { US"set", TRUE, TRUE, 0 },
+ [ACLC_SET] = { US"set", TRUE, TRUE, 0 },
#ifdef WITH_CONTENT_SCAN
- { US"spam", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_SPAM] = { US"spam", TRUE, FALSE,
+ (unsigned int) ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)),
+ (1<<ACL_WHERE_NOTSMTP)),
},
#endif
#ifdef EXPERIMENTAL_SPF
- { US"spf", TRUE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ [ACLC_SPF] = { US"spf", TRUE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
- { US"spf_guess", TRUE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ [ACLC_SPF_GUESS] = { US"spf_guess", TRUE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
#endif
- { US"udpsend", TRUE, TRUE, 0 },
+ [ACLC_UDPSEND] = { US"udpsend", TRUE, TRUE, 0 },
/* Certain types of verify are always allowed, so we let it through
always and check in the verify function itself */
- { US"verify", TRUE, FALSE,
- 0
- },
+ [ACLC_VERIFY] = { US"verify", TRUE, FALSE, 0 },
};
@@ -399,116 +397,142 @@ typedef struct control_def {
} control_def;
static control_def controls_list[] = {
+ /* name has_option forbids */
+[CONTROL_AUTH_UNADVERTISED] =
{ US"allow_auth_unadvertised", FALSE,
- (unsigned)
- ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO))
+ (unsigned)
+ ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO))
},
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { US"bmi_run", FALSE, 0 },
+[CONTROL_BMI_RUN] =
+ { US"bmi_run", FALSE, 0 },
#endif
+[CONTROL_CASEFUL_LOCAL_PART] =
{ US"caseful_local_part", FALSE, (unsigned) ~(1<<ACL_WHERE_RCPT) },
+[CONTROL_CASELOWER_LOCAL_PART] =
{ US"caselower_local_part", FALSE, (unsigned) ~(1<<ACL_WHERE_RCPT) },
- { US"cutthrough_delivery", TRUE, 0 },
- { US"debug", TRUE, 0 },
+[CONTROL_CUTTHROUGH_DELIVERY] =
+ { US"cutthrough_delivery", TRUE, 0 },
+[CONTROL_DEBUG] =
+ { US"debug", TRUE, 0 },
#ifndef DISABLE_DKIM
+[CONTROL_DKIM_VERIFY] =
{ US"dkim_disable_verify", FALSE,
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP_START)
},
#endif
#ifdef EXPERIMENTAL_DMARC
+[CONTROL_DMARC_VERIFY] =
{ US"dmarc_disable_verify", FALSE,
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_DMARC_FORENSIC] =
{ US"dmarc_enable_forensic", FALSE,
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
#endif
+[CONTROL_DSCP] =
{ US"dscp", TRUE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)|(1<<ACL_WHERE_NOTQUIT)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)|(1<<ACL_WHERE_NOTQUIT)
},
+[CONTROL_ENFORCE_SYNC] =
{ US"enforce_sync", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
/* Pseudo-value for decode errors */
+[CONTROL_ERROR] =
{ US"error", FALSE, 0 },
+[CONTROL_FAKEDEFER] =
{ US"fakedefer", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME))
+ (1<<ACL_WHERE_MIME))
},
+[CONTROL_FAKEREJECT] =
{ US"fakereject", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME))
+ (1<<ACL_WHERE_MIME))
},
+[CONTROL_FREEZE] =
{ US"freeze", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
},
+[CONTROL_NO_CALLOUT_FLUSH] =
{ US"no_callout_flush", FALSE,
- (1<<ACL_WHERE_NOTSMTP)| (1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)| (1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_NO_DELAY_FLUSH] =
{ US"no_delay_flush", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_NO_ENFORCE_SYNC] =
{ US"no_enforce_sync", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
#ifdef WITH_CONTENT_SCAN
+[CONTROL_NO_MBOX_UNSPOOL] =
{ US"no_mbox_unspool", FALSE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
- (1<<ACL_WHERE_MIME))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
+ (1<<ACL_WHERE_MIME))
},
#endif
+[CONTROL_NO_MULTILINE] =
{ US"no_multiline_responses", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_NO_PIPELINING] =
{ US"no_pipelining", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_QUEUE_ONLY] =
{ US"queue_only", FALSE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
},
+[CONTROL_SUBMISSION] =
{ US"submission", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA))
},
+[CONTROL_SUPPRESS_LOCAL_FIXUPS] =
{ US"suppress_local_fixups", FALSE,
(unsigned)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
(1<<ACL_WHERE_NOTSMTP_START))
},
#ifdef SUPPORT_I18N
+[CONTROL_UTF8_DOWNCONVERT] =
{ US"utf8_downconvert", TRUE, 0 }
#endif
};
@@ -532,24 +556,36 @@ further ACL conditions to distinguish ok, unknown, and defer if required, but
the aim is to make the usual configuration simple. */
static int csa_return_code[] = {
- OK, OK, OK, OK,
- FAIL, FAIL, FAIL, FAIL
+ [CSA_UNKNOWN] = OK,
+ [CSA_OK] = OK,
+ [CSA_DEFER_SRV] = OK,
+ [CSA_DEFER_ADDR] = OK,
+ [CSA_FAIL_EXPLICIT] = FAIL,
+ [CSA_FAIL_DOMAIN] = FAIL,
+ [CSA_FAIL_NOADDR] = FAIL,
+ [CSA_FAIL_MISMATCH] = FAIL
};
static uschar *csa_status_string[] = {
- US"unknown", US"ok", US"defer", US"defer",
- US"fail", US"fail", US"fail", US"fail"
+ [CSA_UNKNOWN] = US"unknown",
+ [CSA_OK] = US"ok",
+ [CSA_DEFER_SRV] = US"defer",
+ [CSA_DEFER_ADDR] = US"defer",
+ [CSA_FAIL_EXPLICIT] = US"fail",
+ [CSA_FAIL_DOMAIN] = US"fail",
+ [CSA_FAIL_NOADDR] = US"fail",
+ [CSA_FAIL_MISMATCH] = US"fail"
};
static uschar *csa_reason_string[] = {
- US"unknown",
- US"ok",
- US"deferred (SRV lookup failed)",
- US"deferred (target address lookup failed)",
- US"failed (explicit authorization required)",
- US"failed (host name not authorized)",
- US"failed (no authorized addresses)",
- US"failed (client address mismatch)"
+ [CSA_UNKNOWN] = US"unknown",
+ [CSA_OK] = US"ok",
+ [CSA_DEFER_SRV] = US"deferred (SRV lookup failed)",
+ [CSA_DEFER_ADDR] = US"deferred (target address lookup failed)",
+ [CSA_FAIL_EXPLICIT] = US"failed (explicit authorization required)",
+ [CSA_FAIL_DOMAIN] = US"failed (host name not authorized)",
+ [CSA_FAIL_NOADDR] = US"failed (no authorized addresses)",
+ [CSA_FAIL_MISMATCH] = US"failed (client address mismatch)"
};
/* Options for the ratelimit condition. Note that there are two variants of
@@ -567,8 +603,15 @@ enum {
(((var) == RATE_PER_WHAT) ? ((var) = RATE_##new) : ((var) = RATE_PER_CLASH))
static uschar *ratelimit_option_string[] = {
- US"?", US"!", US"per_addr", US"per_byte", US"per_cmd",
- US"per_conn", US"per_mail", US"per_rcpt", US"per_rcpt"
+ [RATE_PER_WHAT] = US"?",
+ [RATE_PER_CLASH] = US"!",
+ [RATE_PER_ADDR] = US"per_addr",
+ [RATE_PER_BYTE] = US"per_byte",
+ [RATE_PER_CMD] = US"per_cmd",
+ [RATE_PER_CONN] = US"per_conn",
+ [RATE_PER_MAIL] = US"per_mail",
+ [RATE_PER_RCPT] = US"per_rcpt",
+ [RATE_PER_ALLRCPTS] = US"per_rcpt"
};
/* Enable recursion between acl_check_internal() and acl_check_condition() */
@@ -1097,7 +1140,7 @@ if (log_message != NULL && log_message != user_message)
int length = Ustrlen(text) + 1;
log_write(0, LOG_MAIN, "%s", text);
logged = store_malloc(sizeof(string_item) + length);
- logged->text = (uschar *)logged + sizeof(string_item);
+ logged->text = US logged + sizeof(string_item);
memcpy(logged->text, text, length);
logged->next = acl_warn_logged;
acl_warn_logged = logged;
@@ -1482,6 +1525,7 @@ typedef struct {
unsigned alt_opt_sep; /* >0 Non-/ option separator (custom parser) */
} verify_type_t;
static verify_type_t verify_type_list[] = {
+ /* name value where no-opt opt-sep */
{ US"reverse_host_lookup", VERIFY_REV_HOST_LKUP, ~0, FALSE, 0 },
{ US"certificate", VERIFY_CERT, ~0, TRUE, 0 },
{ US"helo", VERIFY_HELO, ~0, TRUE, 0 },
@@ -1500,7 +1544,7 @@ static verify_type_t verify_type_list[] = {
enum { CALLOUT_DEFER_OK, CALLOUT_NOCACHE, CALLOUT_RANDOM, CALLOUT_USE_SENDER,
CALLOUT_USE_POSTMASTER, CALLOUT_POSTMASTER, CALLOUT_FULLPOSTMASTER,
CALLOUT_MAILFROM, CALLOUT_POSTMASTER_MAILFROM, CALLOUT_MAXWAIT, CALLOUT_CONNECT,
- CALLOUT_TIME
+ CALLOUT_HOLD, CALLOUT_TIME /* TIME must be last */
};
typedef struct {
uschar * name;
@@ -1510,6 +1554,7 @@ typedef struct {
BOOL timeval; /* Has a time value */
} callout_opt_t;
static callout_opt_t callout_opt_list[] = {
+ /* name value flag has-opt has-time */
{ US"defer_ok", CALLOUT_DEFER_OK, 0, FALSE, FALSE },
{ US"no_cache", CALLOUT_NOCACHE, vopt_callout_no_cache, FALSE, FALSE },
{ US"random", CALLOUT_RANDOM, vopt_callout_random, FALSE, FALSE },
@@ -1521,6 +1566,7 @@ static callout_opt_t callout_opt_list[] = {
{ US"mailfrom", CALLOUT_MAILFROM, 0, TRUE, FALSE },
{ US"maxwait", CALLOUT_MAXWAIT, 0, TRUE, TRUE },
{ US"connect", CALLOUT_CONNECT, 0, TRUE, TRUE },
+ { US"hold", CALLOUT_HOLD, vopt_callout_hold, FALSE, FALSE },
{ NULL, CALLOUT_TIME, 0, FALSE, TRUE }
};
@@ -1579,13 +1625,13 @@ if (ss == NULL) goto BAD_VERIFY;
/* Handle name/address consistency verification in a separate function. */
for (vp= verify_type_list;
- (char *)vp < (char *)verify_type_list + sizeof(verify_type_list);
+ CS vp < CS verify_type_list + sizeof(verify_type_list);
vp++
)
if (vp->alt_opt_sep ? strncmpic(ss, vp->name, vp->alt_opt_sep) == 0
: strcmpic (ss, vp->name) == 0)
break;
-if ((char *)vp >= (char *)verify_type_list + sizeof(verify_type_list))
+if (CS vp >= CS verify_type_list + sizeof(verify_type_list))
goto BAD_VERIFY;
if (vp->no_options && slash != NULL)
@@ -1744,8 +1790,7 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
uschar buffer[256];
while (isspace(*sublist)) sublist++;
- while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer)))
- != NULL)
+ while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer))))
{
callout_opt_t * op;
double period = 1.0F;
@@ -1767,15 +1812,11 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
}
while (isspace(*opt)) opt++;
}
- if (op->timeval)
+ if (op->timeval && (period = readconf_readtime(opt, 0, FALSE)) < 0)
{
- period = readconf_readtime(opt, 0, FALSE);
- if (period < 0)
- {
- *log_msgptr = string_sprintf("bad time value in ACL condition "
- "\"verify %s\"", arg);
- return ERROR;
- }
+ *log_msgptr = string_sprintf("bad time value in ACL condition "
+ "\"verify %s\"", arg);
+ return ERROR;
}
switch(op->value)
@@ -2356,8 +2397,7 @@ if (t != NULL)
/* We aren't using a pre-computed rate, so get a previously recorded rate
from the database, which will be updated and written back if required. */
-dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE);
-if (dbm == NULL)
+if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE)))
{
store_pool = old_pool;
sender_rate = NULL;
@@ -2731,8 +2771,9 @@ if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN)
HDEBUG(D_acl)
debug_printf_indent("udpsend [%s]:%d %s\n", h->address, portnum, arg);
+/*XXX this could better use sendto */
r = s = ip_connectedsocket(SOCK_DGRAM, h->address, portnum, portnum,
- 1, NULL, &errstr);
+ 1, NULL, &errstr, NULL);
if (r < 0) goto defer;
len = Ustrlen(arg);
r = send(s, arg, len, 0);
@@ -3069,7 +3110,7 @@ for (; cb != NULL; cb = cb->next)
break;
case CONTROL_FAKEREJECT:
- cancel_cutthrough_connection("fakereject");
+ cancel_cutthrough_connection(TRUE, US"fakereject");
case CONTROL_FAKEDEFER:
fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
if (*p == '/')
@@ -3100,12 +3141,12 @@ for (; cb != NULL; cb = cb->next)
*log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
return ERROR;
}
- cancel_cutthrough_connection("item frozen");
+ cancel_cutthrough_connection(TRUE, US"item frozen");
break;
case CONTROL_QUEUE_ONLY:
queue_only_policy = TRUE;
- cancel_cutthrough_connection("queueing forced");
+ cancel_cutthrough_connection(TRUE, US"queueing forced");
break;
case CONTROL_SUBMISSION:
@@ -3534,7 +3575,7 @@ for (; cb != NULL; cb = cb->next)
break;
case ACLC_RECIPIENTS:
- rc = match_address_list((const uschar *)addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
+ rc = match_address_list(CUS addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
CUSS &recipient_data);
break;
@@ -3552,14 +3593,14 @@ for (; cb != NULL; cb = cb->next)
{
uschar *sdomain;
sdomain = Ustrrchr(sender_address, '@');
- sdomain = (sdomain == NULL)? US"" : sdomain + 1;
+ sdomain = sdomain ? sdomain + 1 : US"";
rc = match_isinlist(sdomain, &arg, 0, &domainlist_anchor,
sender_domain_cache, MCL_DOMAIN, TRUE, NULL);
}
break;
case ACLC_SENDERS:
- rc = match_address_list((const uschar *)sender_address, TRUE, TRUE, &arg,
+ rc = match_address_list(CUS sender_address, TRUE, TRUE, &arg,
sender_address_cache, -1, 0, CUSS &sender_data);
break;
@@ -4334,8 +4375,9 @@ switch (where)
#ifndef DISABLE_PRDR
case ACL_WHERE_PRDR:
#endif
+
if (host_checking_callout) /* -bhc mode */
- cancel_cutthrough_connection("host-checking mode");
+ cancel_cutthrough_connection(TRUE, US"host-checking mode");
else if ( rc == OK
&& cutthrough.delivery
@@ -4362,13 +4404,20 @@ switch (where)
if (rc == OK)
cutthrough_predata();
else
- cancel_cutthrough_connection("predata acl not ok");
+ cancel_cutthrough_connection(TRUE, US"predata acl not ok");
break;
case ACL_WHERE_QUIT:
case ACL_WHERE_NOTQUIT:
- cancel_cutthrough_connection("quit or notquit");
+ /* Drop cutthrough conns, and drop heldopen verify conns if
+ the previous was not DATA */
+ {
+ uschar prev = smtp_connection_had[smtp_ch_index-2];
+ BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT);
+
+ cancel_cutthrough_connection(dropverify, US"quit or conndrop");
break;
+ }
default:
break;
diff --git a/src/src/auths/auth-spa.c b/src/src/auths/auth-spa.c
index d1df7f2cb..6bc3d1f63 100644
--- a/src/src/auths/auth-spa.c
+++ b/src/src/auths/auth-spa.c
@@ -83,8 +83,8 @@ int main (int argc, char ** argv)
challenge_str = argv [3];
- if (spa_base64_to_bits ((char *)&challenge, sizeof(challenge),
- (const char *)(challenge_str))<0)
+ if (spa_base64_to_bits (CS &challenge, sizeof(challenge),
+ CCS (challenge_str))<0)
{
printf("bad base64 data in challenge: %s\n", challenge_str);
exit (1);
@@ -229,10 +229,10 @@ extern int DEBUGLEVEL;
*/
/* get single value from an SMB buffer */
-# define SVAL(buf,pos) (*(uint16x *)((char *)(buf) + (pos)))
-# define IVAL(buf,pos) (*(uint32x *)((char *)(buf) + (pos)))
-# define SVALS(buf,pos) (*(int16x *)((char *)(buf) + (pos)))
-# define IVALS(buf,pos) (*(int32x *)((char *)(buf) + (pos)))
+# define SVAL(buf,pos) (*(uint16x *)(CS (buf) + (pos)))
+# define IVAL(buf,pos) (*(uint32x *)(CS (buf) + (pos)))
+# define SVALS(buf,pos) (*(int16x *)(CS (buf) + (pos)))
+# define IVALS(buf,pos) (*(int32x *)(CS (buf) + (pos)))
/* store single value in an SMB buffer */
# define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16x)(val))
@@ -856,18 +856,18 @@ spa_smb_encrypt (uschar * passwd, uschar * c8, uschar * p24)
memset (p21, '\0', 21);
memset (p14, '\0', 14);
- StrnCpy ((char *) p14, (char *) passwd, 14);
+ StrnCpy (CS p14, CS passwd, 14);
- strupper ((char *) p14);
+ strupper (CS p14);
E_P16 (p14, p21);
SMBOWFencrypt (p21, c8, p24);
#ifdef DEBUG_PASSWORD
DEBUG_X (100, ("spa_smb_encrypt: lm#, challenge, response\n"));
- dump_data (100, (char *) p21, 16);
- dump_data (100, (char *) c8, 8);
- dump_data (100, (char *) p24, 24);
+ dump_data (100, CS p21, 16);
+ dump_data (100, CS c8, 8);
+ dump_data (100, CS p24, 24);
#endif
}
@@ -917,7 +917,7 @@ E_md4hash (uschar * passwd, uschar * p16)
int16x wpwd[129];
/* Password cannot be longer than 128 characters */
- len = strlen ((char *) passwd);
+ len = strlen (CS passwd);
if (len > 128)
len = 128;
/* Password must be converted to NT unicode */
@@ -945,7 +945,7 @@ nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
#ifdef DEBUG_PASSWORD
DEBUG_X (100, ("nt_lm_owf_gen: pwd, nt#\n"));
dump_data (120, passwd, strlen (passwd));
- dump_data (100, (char *) nt_p16, 16);
+ dump_data (100, CS nt_p16, 16);
#endif
/* Mangle the passwords into Lanman format */
@@ -960,7 +960,7 @@ nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
#ifdef DEBUG_PASSWORD
DEBUG_X (100, ("nt_lm_owf_gen: pwd, lm#\n"));
dump_data (120, passwd, strlen (passwd));
- dump_data (100, (char *) p16, 16);
+ dump_data (100, CS p16, 16);
#endif
/* clear out local copy of user's password (just being paranoid). */
memset (passwd, '\0', sizeof (passwd));
@@ -991,9 +991,9 @@ NTLMSSPOWFencrypt (uschar passwd[8], uschar * ntlmchalresp, uschar p24[24])
E_P24 (p21, ntlmchalresp, p24);
#ifdef DEBUG_PASSWORD
DEBUG_X (100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
- dump_data (100, (char *) p21, 21);
- dump_data (100, (char *) ntlmchalresp, 8);
- dump_data (100, (char *) p24, 24);
+ dump_data (100, CS p21, 21);
+ dump_data (100, CS ntlmchalresp, 8);
+ dump_data (100, CS p24, 24);
#endif
}
@@ -1012,9 +1012,9 @@ spa_smb_nt_encrypt (uschar * passwd, uschar * c8, uschar * p24)
#ifdef DEBUG_PASSWORD
DEBUG_X (100, ("spa_smb_nt_encrypt: nt#, challenge, response\n"));
- dump_data (100, (char *) p21, 16);
- dump_data (100, (char *) c8, 8);
- dump_data (100, (char *) p24, 24);
+ dump_data (100, CS p21, 16);
+ dump_data (100, CS c8, 8);
+ dump_data (100, CS p24, 24);
#endif
}
@@ -1261,7 +1261,7 @@ spa_bytes_add(ptr, header, b, len*2); \
#define GetUnicodeString(structPtr, header) \
unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
#define GetString(structPtr, header) \
-toString((((char *)structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
+toString(((CS structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
#ifdef notdef
@@ -1503,8 +1503,8 @@ spa_build_auth_response (SPAAuthChallenge * challenge,
}
else domain = d = strdup((cf & 0x1)?
- (const char *)GetUnicodeString(challenge, uDomain) :
- (const char *)GetString(challenge, uDomain));
+ CCS GetUnicodeString(challenge, uDomain) :
+ CCS GetString(challenge, uDomain));
spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
diff --git a/src/src/auths/call_pam.c b/src/src/auths/call_pam.c
index b4677ec5a..a5cbec3ed 100644
--- a/src/src/auths/call_pam.c
+++ b/src/src/auths/call_pam.c
@@ -189,7 +189,7 @@ if (pam_error == PAM_SUCCESS)
return OK;
}
-*errptr = (uschar *)pam_strerror(pamh, pam_error);
+*errptr = US pam_strerror(pamh, pam_error);
DEBUG(D_auth) debug_printf("PAM error: %s\n", *errptr);
if (pam_error == PAM_USER_UNKNOWN ||
diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c
index 1ae38a9a6..b9e57c1e9 100644
--- a/src/src/auths/cram_md5.c
+++ b/src/src/auths/cram_md5.c
@@ -47,6 +47,17 @@ auth_cram_md5_options_block auth_cram_md5_option_defaults = {
};
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_cram_md5_init(auth_instance *ablock) {}
+int auth_cram_md5_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_cram_md5_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
/*************************************************
* Initialization entry point *
*************************************************/
@@ -68,10 +79,12 @@ if (ob->client_secret != NULL)
}
}
+#endif /*!MACRO_PREDEF*/
#endif /* STAND_ALONE */
+#ifndef MACRO_PREDEF
/*************************************************
* Perform the CRAM-MD5 algorithm *
*************************************************/
@@ -108,8 +121,8 @@ and use that. */
if (len > 64)
{
md5_start(&base);
- md5_end(&base, (uschar *)secret, len, md5secret);
- secret = (uschar *)md5secret;
+ md5_end(&base, US secret, len, md5secret);
+ secret = US md5secret;
len = 16;
}
@@ -130,7 +143,7 @@ for (i = 0; i < 64; i++)
md5_start(&base);
md5_mid(&base, isecret);
-md5_end(&base, (uschar *)challenge, Ustrlen(challenge), md5secret);
+md5_end(&base, US challenge, Ustrlen(challenge), md5secret);
/* Compute the outer MD5 digest */
@@ -280,7 +293,8 @@ if (!secret || !name)
/* Initiate the authentication exchange and read the challenge, which arrives
in base 64. */
-if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", ablock->public_name) < 0)
+if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s\r\n",
+ ablock->public_name) < 0)
return FAIL_SEND;
if (!smtp_read_response(inblock, buffer, buffsize, '3', timeout))
return FAIL;
@@ -303,20 +317,17 @@ for (p = big_buffer; *p; ) p++;
*p++ = ' ';
for (i = 0; i < 16; i++)
- {
- sprintf(CS p, "%02x", digest[i]);
- p += 2;
- }
+ p += sprintf(CS p, "%02x", digest[i]);
/* Send the response, in base 64, and check the result. The response is
in big_buffer, but b64encode() returns its result in working store,
so calling smtp_write_command(), which uses big_buffer, is OK. */
buffer[0] = 0;
-if (smtp_write_command(outblock, FALSE, "%s\r\n", b64encode(big_buffer,
+if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", b64encode(big_buffer,
p - big_buffer)) < 0) return FAIL_SEND;
-return smtp_read_response(inblock, (uschar *)buffer, buffsize, '2', timeout)
+return smtp_read_response(inblock, US buffer, buffsize, '2', timeout)
? OK : FAIL;
}
#endif /* STAND_ALONE */
@@ -347,4 +358,5 @@ return 0;
#endif
+#endif /*!MACRO_PREDEF*/
/* End of cram_md5.c */
diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c
index bab2be36c..cbf244633 100644
--- a/src/src/auths/cyrus_sasl.c
+++ b/src/src/auths/cyrus_sasl.c
@@ -63,6 +63,20 @@ auth_cyrus_sasl_options_block auth_cyrus_sasl_option_defaults = {
};
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_cyrus_sasl_init(auth_instance *ablock) {}
+int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_cyrus_sasl_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+void auth_cyrus_sasl_version_report(FILE *f) {}
+
+#else /*!MACRO_PREDEF*/
+
+
+
+
/*************************************************
* Initialization entry point *
*************************************************/
@@ -525,6 +539,7 @@ auth_cyrus_sasl_client(
return FAIL;
}
+#endif /*!MACRO_PREDEF*/
#endif /* AUTH_CYRUS_SASL */
/* End of cyrus_sasl.c */
diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c
index 5bf7b9cc3..2dcaa0e42 100644
--- a/src/src/auths/dovecot.c
+++ b/src/src/auths/dovecot.c
@@ -71,6 +71,19 @@ auth_dovecot_options_block auth_dovecot_option_defaults = {
};
+
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_dovecot_init(auth_instance *ablock) {}
+int auth_dovecot_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_dovecot_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Static variables for reading from the socket */
static uschar sbuffer[256];
@@ -380,7 +393,7 @@ fprintf(f, "VERSION\t%d\t%d\r\nSERVICE\tSMTP\r\nCPID\t%d\r\n"
"AUTH\t%d\t%s\trip=%s\tlip=%s\tresp=%s\r\n",
VERSION_MAJOR, VERSION_MINOR, getpid(), cuid,
ablock->public_name, sender_host_address, interface_address,
- data ? (char *) data : "");
+ data ? CS data : "");
Subsequently, the command was modified to add "secured" and "valid-client-
cert" when relevant.
@@ -495,3 +508,6 @@ if (fd >= 0)
/* Expand server_condition as an authorization check */
return ret == OK ? auth_check_serv_cond(ablock) : ret;
}
+
+
+#endif /*!MACRO_PREDEF*/
diff --git a/src/src/auths/get_data.c b/src/src/auths/get_data.c
index 11bc581b9..3857e0738 100644
--- a/src/src/auths/get_data.c
+++ b/src/src/auths/get_data.c
@@ -30,7 +30,7 @@ auth_get_data(uschar **aptr, uschar *challenge, int challen)
{
int c;
int p = 0;
-smtp_printf("334 %s\r\n", b64encode(challenge, challen));
+smtp_printf("334 %s\r\n", FALSE, b64encode(challenge, challen));
while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF)
{
if (p >= big_buffer_size - 1) return BAD64;
diff --git a/src/src/auths/get_no64_data.c b/src/src/auths/get_no64_data.c
index 71e71394c..1bb611c1c 100644
--- a/src/src/auths/get_no64_data.c
+++ b/src/src/auths/get_no64_data.c
@@ -31,7 +31,7 @@ auth_get_no64_data(uschar **aptr, uschar *challenge)
{
int c;
int p = 0;
-smtp_printf("334 %s\r\n", challenge);
+smtp_printf("334 %s\r\n", FALSE, challenge);
while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF)
{
if (p >= big_buffer_size - 1) return BAD64;
diff --git a/src/src/auths/gsasl_exim.c b/src/src/auths/gsasl_exim.c
index 77db2e775..48621a402 100644
--- a/src/src/auths/gsasl_exim.c
+++ b/src/src/auths/gsasl_exim.c
@@ -78,6 +78,20 @@ auth_gsasl_options_block auth_gsasl_option_defaults = {
FALSE /* server_channelbinding */
};
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_gsasl_init(auth_instance *ablock) {}
+int auth_gsasl_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_gsasl_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+void auth_gsasl_version_report(FILE *f) {}
+
+#else /*!MACRO_PREDEF*/
+
+
+
/* "Globals" for managing the gsasl interface. */
static Gsasl *gsasl_ctx = NULL;
@@ -143,7 +157,7 @@ auth_gsasl_init(auth_instance *ablock)
ablock->name, gsasl_strerror_name(rc), gsasl_strerror(rc));
HDEBUG(D_auth) debug_printf("GNU SASL supports: %s\n", p);
- supported = gsasl_client_support_p(gsasl_ctx, (const char *)ob->server_mech);
+ supported = gsasl_client_support_p(gsasl_ctx, CCS ob->server_mech);
if (!supported)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
"GNU SASL does not support mechanism \"%s\"",
@@ -244,7 +258,7 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
debug_printf("GNU SASL: initialising session for %s, mechanism %s.\n",
ablock->name, ob->server_mech);
- rc = gsasl_server_start(gsasl_ctx, (const char *)ob->server_mech, &sctx);
+ rc = gsasl_server_start(gsasl_ctx, CCS ob->server_mech, &sctx);
if (rc != GSASL_OK) {
auth_defer_msg = string_sprintf("GNU SASL: session start failure: %s (%s)",
gsasl_strerror_name(rc), gsasl_strerror(rc));
@@ -294,7 +308,7 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
ablock->name);
gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE,
- (const char *) tls_channelbinding_b64);
+ CCS tls_channelbinding_b64);
} else {
HDEBUG(D_auth)
debug_printf("Auth %s: Not enabling channel-binding (data available)\n",
@@ -355,7 +369,7 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
if ((rc == GSASL_NEEDS_MORE) ||
(to_send && *to_send))
exim_error =
- auth_get_no64_data((uschar **)&received, (uschar *)to_send);
+ auth_get_no64_data((uschar **)&received, US to_send);
if (to_send) {
free(to_send);
@@ -435,11 +449,11 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
switch (prop) {
case GSASL_VALIDATE_SIMPLE:
/* GSASL_AUTHID, GSASL_AUTHZID, and GSASL_PASSWORD */
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHID);
+ propval = US gsasl_property_fast(sctx, GSASL_AUTHID);
auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+ propval = US gsasl_property_fast(sctx, GSASL_AUTHZID);
auth_vars[1] = expand_nstring[2] = propval ? propval : US"";
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_PASSWORD);
+ propval = US gsasl_property_fast(sctx, GSASL_PASSWORD);
auth_vars[2] = expand_nstring[3] = propval ? propval : US"";
expand_nmax = 3;
for (i = 1; i <= 3; ++i)
@@ -455,7 +469,7 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
cbrc = GSASL_AUTHENTICATION_ERROR;
break;
}
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+ propval = US gsasl_property_fast(sctx, GSASL_AUTHZID);
/* We always set $auth1, even if only to empty string. */
auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
expand_nlength[1] = Ustrlen(expand_nstring[1]);
@@ -472,7 +486,7 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
cbrc = GSASL_AUTHENTICATION_ERROR;
break;
}
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_ANONYMOUS_TOKEN);
+ propval = US gsasl_property_fast(sctx, GSASL_ANONYMOUS_TOKEN);
/* We always set $auth1, even if only to empty string. */
auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
expand_nlength[1] = Ustrlen(expand_nstring[1]);
@@ -493,9 +507,9 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
First coding, we had these values swapped, but for consistency and prior
to the first release of Exim with this authenticator, they've been
switched to match the ordering of GSASL_VALIDATE_SIMPLE. */
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_GSSAPI_DISPLAY_NAME);
+ propval = US gsasl_property_fast(sctx, GSASL_GSSAPI_DISPLAY_NAME);
auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+ propval = US gsasl_property_fast(sctx, GSASL_AUTHZID);
auth_vars[1] = expand_nstring[2] = propval ? propval : US"";
expand_nmax = 2;
for (i = 1; i <= 2; ++i)
@@ -528,11 +542,11 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
a new mechanism is added to the library. It *shouldn't* result in us
needing to add more glue, since avoiding that is a large part of the
point of SASL. */
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHID);
+ propval = US gsasl_property_fast(sctx, GSASL_AUTHID);
auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+ propval = US gsasl_property_fast(sctx, GSASL_AUTHZID);
auth_vars[1] = expand_nstring[2] = propval ? propval : US"";
- propval = (uschar *) gsasl_property_fast(sctx, GSASL_REALM);
+ propval = US gsasl_property_fast(sctx, GSASL_REALM);
auth_vars[2] = expand_nstring[3] = propval ? propval : US"";
expand_nmax = 3;
for (i = 1; i <= 3; ++i)
@@ -614,6 +628,7 @@ auth_gsasl_version_report(FILE *f)
GSASL_VERSION, runtime);
}
+#endif /*!MACRO_PREDEF*/
#endif /* AUTH_GSASL */
/* End of gsasl_exim.c */
diff --git a/src/src/auths/heimdal_gssapi.c b/src/src/auths/heimdal_gssapi.c
index 732a67381..03a4bec79 100644
--- a/src/src/auths/heimdal_gssapi.c
+++ b/src/src/auths/heimdal_gssapi.c
@@ -76,6 +76,20 @@ auth_heimdal_gssapi_options_block auth_heimdal_gssapi_option_defaults = {
US"smtp", /* server_service */
};
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_heimdal_init(auth_instance *ablock) {}
+int auth_heimdal_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_heimdal_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+void auth_heimdal_gssapi_version_report(FILE *f) {}
+
+#else /*!MACRO_PREDEF*/
+
+
+
/* "Globals" for managing the heimdal_gssapi interface. */
/* Utility functions */
@@ -590,6 +604,7 @@ auth_heimdal_gssapi_version_report(FILE *f)
heimdal_version, heimdal_long_version);
}
+#endif /*!MACRO_PREDEF*/
#endif /* AUTH_HEIMDAL_GSSAPI */
/* End of heimdal_gssapi.c */
diff --git a/src/src/auths/md5.c b/src/src/auths/md5.c
index 25655e9ba..71b8c9952 100644
--- a/src/src/auths/md5.c
+++ b/src/src/auths/md5.c
@@ -334,7 +334,7 @@ int main(void)
{
md5 base;
int i = 0x01020304;
-uschar *ctest = (uschar *)(&i);
+uschar *ctest = US (&i);
uschar buffer[256];
uschar digest[16];
printf("Checking md5: %s-endian\n", (ctest[0] == 0x04)? "little" : "big");
diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c
index 161aab6c0..8bba05823 100644
--- a/src/src/auths/plaintext.c
+++ b/src/src/auths/plaintext.c
@@ -35,6 +35,18 @@ auth_plaintext_options_block auth_plaintext_option_defaults = {
};
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_plaintext_init(auth_instance *ablock) {}
+int auth_plaintext_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_plaintext_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
/*************************************************
* Initialization entry point *
*************************************************/
@@ -173,7 +185,7 @@ int auth_var_idx = 0;
sent one by one. The first one is sent with the AUTH command; the remainder are
sent in response to subsequent prompts. Each is expanded before being sent. */
-while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL)
+while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)))
{
int i, len, clear_len;
uschar *ss = expand_string(s);
@@ -184,12 +196,12 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
sending a line containing "*". Save the failed expansion string, because it
is in big_buffer, and that gets used by the sending function. */
- if (ss == NULL)
+ if (!ss)
{
uschar *ssave = string_copy(s);
if (!first)
{
- if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0)
+ if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0)
(void) smtp_read_response(inblock, US buffer, buffsize, '2', timeout);
}
if (expand_string_forcedfail)
@@ -208,17 +220,15 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
needed for the PLAIN mechanism. It must be doubled if really needed. */
for (i = 0; i < len; i++)
- {
if (ss[i] == '^')
- {
- if (ss[i+1] != '^') ss[i] = 0; else
+ if (ss[i+1] != '^')
+ ss[i] = 0;
+ else
{
i++;
len--;
memmove(ss + i, ss + i + 1, len - i);
}
- }
- }
/* The first string is attached to the AUTH command; others are sent
unembellished. */
@@ -226,14 +236,14 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
if (first)
{
first = FALSE;
- if (smtp_write_command(outblock, FALSE, "AUTH %s%s%s\r\n",
+ if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s%s%s\r\n",
ablock->public_name, (len == 0)? "" : " ",
b64encode(ss, len)) < 0)
return FAIL_SEND;
}
else
{
- if (smtp_write_command(outblock, FALSE, "%s\r\n",
+ if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n",
b64encode(ss, len)) < 0)
return FAIL_SEND;
}
@@ -255,7 +265,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
if (text == NULL)
{
- if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0)
+ if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0)
(void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout);
string_format(buffer, buffsize, "Too few items in client_send in %s "
"authenticator", ablock->name);
@@ -277,7 +287,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
uschar *save_bad = string_copy(buffer);
if (!ob->client_ignore_invalid_base64)
{
- if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0)
+ if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0)
(void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout);
string_format(buffer, buffsize, "Invalid base64 string in server "
"response \"%s\"", save_bad);
@@ -296,4 +306,5 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
return FAIL;
}
+#endif /*!MACRO_PREDEF*/
/* End of plaintext.c */
diff --git a/src/src/auths/pwcheck.c b/src/src/auths/pwcheck.c
index 645265daa..54ba80f92 100644
--- a/src/src/auths/pwcheck.c
+++ b/src/src/auths/pwcheck.c
@@ -113,7 +113,7 @@ return PWCHECK_FAIL;
s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s == -1) { return PWCHECK_FAIL; }
- memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ memset(CS &srvaddr, 0, sizeof(srvaddr));
srvaddr.sun_family = AF_UNIX;
strncpy(srvaddr.sun_path, CYRUS_PWCHECK_SOCKET, sizeof(srvaddr.sun_path));
r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
@@ -124,9 +124,9 @@ return PWCHECK_FAIL;
return PWCHECK_FAIL;
}
- iov[0].iov_base = (char *)userid;
+ iov[0].iov_base = CS userid;
iov[0].iov_len = strlen(userid)+1;
- iov[1].iov_base = (char *)passwd;
+ iov[1].iov_base = CS passwd;
iov[1].iov_len = strlen(passwd)+1;
retry_writev(s, iov, 2);
@@ -200,7 +200,7 @@ int saslauthd_verify_password(const uschar *userid,
return PWCHECK_FAIL;
}
- memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ memset(CS &srvaddr, 0, sizeof(srvaddr));
srvaddr.sun_family = AF_UNIX;
strncpy(srvaddr.sun_path, CYRUS_SASLAUTHD_SOCKET,
sizeof(srvaddr.sun_path));
@@ -343,7 +343,7 @@ static int retry_read(int fd, void *inbuf, unsigned nbyte)
{
int n;
int nread = 0;
- char *buf = (char *)inbuf;
+ char *buf = CS inbuf;
if (nbyte == 0) return 0;
@@ -432,7 +432,7 @@ retry_writev (
for (i = 0; i < iovcnt; i++) {
if (iov[i].iov_len > (unsigned) n) {
- iov[i].iov_base = (char *)iov[i].iov_base + n;
+ iov[i].iov_base = CS iov[i].iov_base + n;
iov[i].iov_len -= n;
break;
}
diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c
index 4d435a411..f14ca5e54 100644
--- a/src/src/auths/spa.c
+++ b/src/src/auths/spa.c
@@ -71,6 +71,19 @@ auth_spa_options_block auth_spa_option_defaults = {
};
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_spa_init(auth_instance *ablock) {}
+int auth_spa_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_spa_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
+
/*************************************************
* Initialization entry point *
*************************************************/
@@ -110,7 +123,7 @@ ablock->server = ob->spa_serverpassword != NULL;
/* For interface, see auths/README */
-#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define CVAL(buf,pos) ((US (buf))[pos])
#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
@@ -138,7 +151,7 @@ if ((*data == '\0') &&
return FAIL;
}
-if (spa_base64_to_bits((char *)(&request), sizeof(request), (const char *)(data)) < 0)
+if (spa_base64_to_bits(CS (&request), sizeof(request), CCS (data)) < 0)
{
DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in "
"request: %s\n", data);
@@ -158,7 +171,7 @@ if (auth_get_no64_data(&data, msgbuf) != OK)
}
/* dump client response */
-if (spa_base64_to_bits((char *)(&response), sizeof(response), (const char *)(data)) < 0)
+if (spa_base64_to_bits(CS (&response), sizeof(response), CCS (data)) < 0)
{
DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in "
"response: %s\n", data);
@@ -261,109 +274,104 @@ auth_spa_client(
uschar *buffer, /* buffer for reading response */
int buffsize) /* size of buffer */
{
- auth_spa_options_block *ob =
- (auth_spa_options_block *)(ablock->options_block);
- SPAAuthRequest request;
- SPAAuthChallenge challenge;
- SPAAuthResponse response;
- char msgbuf[2048];
- char *domain = NULL;
- char *username, *password;
-
- /* Code added by PH to expand the options */
-
- *buffer = 0; /* Default no message when cancelled */
-
- username = CS expand_string(ob->spa_username);
- if (username == NULL)
- {
- if (expand_string_forcedfail) return CANCELLED;
- string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
- "authenticator: %s", ob->spa_username, ablock->name,
- expand_string_message);
- return ERROR;
- }
-
- password = CS expand_string(ob->spa_password);
- if (password == NULL)
- {
- if (expand_string_forcedfail) return CANCELLED;
- string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
- "authenticator: %s", ob->spa_password, ablock->name,
- expand_string_message);
- return ERROR;
- }
-
- if (ob->spa_domain != NULL)
- {
- domain = CS expand_string(ob->spa_domain);
- if (domain == NULL)
- {
- if (expand_string_forcedfail) return CANCELLED;
- string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
- "authenticator: %s", ob->spa_domain, ablock->name,
- expand_string_message);
- return ERROR;
- }
- }
-
- /* Original code */
-
- if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n",
- ablock->public_name) < 0)
- return FAIL_SEND;
-
- /* wait for the 3XX OK message */
- if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout))
- return FAIL;
-
- DSPA("\n\n%s authenticator: using domain %s\n\n",
- ablock->name, domain);
-
- spa_build_auth_request (&request, CS username, domain);
- spa_bits_to_base64 (US msgbuf, (unsigned char*)&request,
- spa_request_length(&request));
-
- DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name,
- msgbuf);
-
- /* send the encrypted password */
- if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0)
- return FAIL_SEND;
-
- /* wait for the auth challenge */
- if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout))
- return FAIL;
-
- /* convert the challenge into the challenge struct */
- DSPA("\n\n%s authenticator: challenge (%s)\n\n",
- ablock->name, buffer + 4);
- spa_base64_to_bits ((char *)(&challenge), sizeof(challenge), (const char *)(buffer + 4));
-
- spa_build_auth_response (&challenge, &response,
- CS username, CS password);
- spa_bits_to_base64 (US msgbuf, (unsigned char*)&response,
- spa_request_length(&response));
- DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name,
- msgbuf);
-
- /* send the challenge response */
- if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0)
- return FAIL_SEND;
-
- /* If we receive a success response from the server, authentication
- has succeeded. There may be more data to send, but is there any point
- in provoking an error here? */
- if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout))
- return OK;
-
- /* Not a success response. If errno != 0 there is some kind of transmission
- error. Otherwise, check the response code in the buffer. If it starts with
- '3', more data is expected. */
- if (errno != 0 || buffer[0] != '3')
- return FAIL;
-
- return FAIL;
+auth_spa_options_block *ob =
+ (auth_spa_options_block *)(ablock->options_block);
+SPAAuthRequest request;
+SPAAuthChallenge challenge;
+SPAAuthResponse response;
+char msgbuf[2048];
+char *domain = NULL;
+char *username, *password;
+
+/* Code added by PH to expand the options */
+
+*buffer = 0; /* Default no message when cancelled */
+
+if (!(username = CS expand_string(ob->spa_username)))
+ {
+ if (expand_string_forcedfail) return CANCELLED;
+ string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
+ "authenticator: %s", ob->spa_username, ablock->name,
+ expand_string_message);
+ return ERROR;
+ }
+
+if (!(password = CS expand_string(ob->spa_password)))
+ {
+ if (expand_string_forcedfail) return CANCELLED;
+ string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
+ "authenticator: %s", ob->spa_password, ablock->name,
+ expand_string_message);
+ return ERROR;
+ }
+
+if (ob->spa_domain)
+ {
+ if (!(domain = CS expand_string(ob->spa_domain)))
+ {
+ if (expand_string_forcedfail) return CANCELLED;
+ string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
+ "authenticator: %s", ob->spa_domain, ablock->name,
+ expand_string_message);
+ return ERROR;
+ }
+ }
+
+/* Original code */
+
+if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s\r\n",
+ ablock->public_name) < 0)
+ return FAIL_SEND;
+
+/* wait for the 3XX OK message */
+if (!smtp_read_response(inblock, US buffer, buffsize, '3', timeout))
+ return FAIL;
+
+DSPA("\n\n%s authenticator: using domain %s\n\n", ablock->name, domain);
+
+spa_build_auth_request (&request, CS username, domain);
+spa_bits_to_base64 (US msgbuf, (unsigned char*)&request,
+ spa_request_length(&request));
+
+DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name, msgbuf);
+
+/* send the encrypted password */
+if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", msgbuf) < 0)
+ return FAIL_SEND;
+
+/* wait for the auth challenge */
+if (!smtp_read_response(inblock, US buffer, buffsize, '3', timeout))
+ return FAIL;
+
+/* convert the challenge into the challenge struct */
+DSPA("\n\n%s authenticator: challenge (%s)\n\n", ablock->name, buffer + 4);
+spa_base64_to_bits (CS (&challenge), sizeof(challenge), CCS (buffer + 4));
+
+spa_build_auth_response (&challenge, &response, CS username, CS password);
+spa_bits_to_base64 (US msgbuf, (unsigned char*)&response,
+ spa_request_length(&response));
+DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name, msgbuf);
+
+/* send the challenge response */
+if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", msgbuf) < 0)
+ return FAIL_SEND;
+
+/* If we receive a success response from the server, authentication
+has succeeded. There may be more data to send, but is there any point
+in provoking an error here? */
+
+if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout))
+ return OK;
+
+/* Not a success response. If errno != 0 there is some kind of transmission
+error. Otherwise, check the response code in the buffer. If it starts with
+'3', more data is expected. */
+
+if (errno != 0 || buffer[0] != '3')
+ return FAIL;
+
+return FAIL;
}
+#endif /*!MACRO_PREDEF*/
/* End of spa.c */
diff --git a/src/src/auths/tls.c b/src/src/auths/tls.c
index 99c756374..bdcae3194 100644
--- a/src/src/auths/tls.c
+++ b/src/src/auths/tls.c
@@ -40,6 +40,19 @@ auth_tls_options_block auth_tls_option_defaults = {
};
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_tls_init(auth_instance *ablock) {}
+int auth_tls_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_tls_client(auth_instance *ablock, smtp_inblock *inblock,
+ smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
+
/*************************************************
* Initialization entry point *
*************************************************/
@@ -77,4 +90,5 @@ return auth_check_serv_cond(ablock);
}
+#endif /*!MACRO_PREDEF*/
/* End of tls.c */
diff --git a/src/src/auths/xtextencode.c b/src/src/auths/xtextencode.c
index 7cdfe3224..4d189fc06 100644
--- a/src/src/auths/xtextencode.c
+++ b/src/src/auths/xtextencode.c
@@ -28,7 +28,7 @@ uschar *
auth_xtextencode(uschar *clear, int len)
{
uschar *code;
-uschar *p = (uschar *)clear;
+uschar *p = US clear;
uschar *pp;
int c = len;
int count = 1;
@@ -42,17 +42,13 @@ while (c -- > 0)
pp = code = store_get(count);
-p = (uschar *)clear;
+p = US clear;
c = len;
while (c-- > 0)
- {
if ((x = *p++) < 33 || x > 127 || x == '+' || x == '=')
- {
- sprintf(CS pp, "+%.02x", x); /* There's always room */
- pp += 3;
- }
- else *pp++ = x;
- }
+ pp += sprintf(CS pp, "+%.02x", x); /* There's always room */
+ else
+ *pp++ = x;
*pp = 0;
return code;
diff --git a/src/src/base64.c b/src/src/base64.c
index cee77c3c3..9dcbb74f0 100644
--- a/src/src/base64.c
+++ b/src/src/base64.c
@@ -150,7 +150,7 @@ static uschar dec64table[] = {
};
int
-b64decode(uschar *code, uschar **ptr)
+b64decode(const uschar *code, uschar **ptr)
{
int x, y;
uschar *result = store_get(3*(Ustrlen(code)/4) + 1);
diff --git a/src/src/bmi_spam.c b/src/src/bmi_spam.c
index 378514939..546ac1e36 100644
--- a/src/src/bmi_spam.c
+++ b/src/src/bmi_spam.c
@@ -27,7 +27,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
uschar *verdicts = NULL;
int i,j;
- err = bmiInitSystem(BMI_VERSION, (char *)bmi_config_file, &system);
+ err = bmiInitSystem(BMI_VERSION, CS bmi_config_file, &system);
if (bmiErrorIsFatal(err) == BMI_TRUE) {
err_loc = bmiErrorGetLocation(err);
err_type = bmiErrorGetType(err);
@@ -51,24 +51,24 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
host_address = localhost;
else
host_address = sender_host_address;
- err = bmiProcessConnection((char *)host_address, message);
+ err = bmiProcessConnection(CS host_address, message);
if (bmiErrorIsFatal(err) == BMI_TRUE) {
err_loc = bmiErrorGetLocation(err);
err_type = bmiErrorGetType(err);
log_write(0, LOG_PANIC,
- "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, (char *)host_address);
+ "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, CS host_address);
bmiFreeMessage(message);
bmiFreeSystem(system);
return NULL;
};
/* Send envelope sender address */
- err = bmiProcessFROM((char *)sender_address, message);
+ err = bmiProcessFROM(CS sender_address, message);
if (bmiErrorIsFatal(err) == BMI_TRUE) {
err_loc = bmiErrorGetLocation(err);
err_type = bmiErrorGetType(err);
log_write(0, LOG_PANIC,
- "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, (char *)sender_address);
+ "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, CS sender_address);
bmiFreeMessage(message);
bmiFreeSystem(system);
return NULL;
@@ -86,14 +86,14 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
err = bmiOptinMset(optin, r->bmi_optin, ':');
if (bmiErrorIsFatal(err) == BMI_TRUE) {
log_write(0, LOG_PANIC|LOG_MAIN,
- "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, (char *)r->address, (char *)r->bmi_optin);
+ "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, CS r->address, CS r->bmi_optin);
if (optin != NULL)
bmiOptinFree(optin);
optin = NULL;
};
};
- err = bmiAccumulateTO((char *)r->address, optin, message);
+ err = bmiAccumulateTO(CS r->address, optin, message);
if (optin != NULL)
bmiOptinFree(optin);
@@ -102,7 +102,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
err_loc = bmiErrorGetLocation(err);
err_type = bmiErrorGetType(err);
log_write(0, LOG_PANIC,
- "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, (char *)r->address);
+ "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, CS r->address);
bmiFreeMessage(message);
bmiFreeSystem(system);
return NULL;
@@ -126,7 +126,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
header_list = header_list->next;
continue;
};
- err = bmiAccumulateHeaders((const char *)header_list->text, header_list->slen, message);
+ err = bmiAccumulateHeaders(CCS header_list->text, header_list->slen, message);
if (bmiErrorIsFatal(err) == BMI_TRUE) {
err_loc = bmiErrorGetLocation(err);
err_type = bmiErrorGetType(err);
@@ -154,7 +154,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
do {
j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
if (j > 0) {
- err = bmiAccumulateBody((const char *)data_buffer, j, message);
+ err = bmiAccumulateBody(CCS data_buffer, j, message);
if (bmiErrorIsFatal(err) == BMI_TRUE) {
err_loc = bmiErrorGetLocation(err);
err_type = bmiErrorGetType(err);
@@ -328,7 +328,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
/* loop through verdicts */
verdict_ptr = bmi_verdicts;
- while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
+ while ((verdict_str = CCS string_nextinlist(&verdict_ptr, &sep,
verdict_buffer,
Ustrlen(bmi_verdicts)+1)) != NULL) {
@@ -350,7 +350,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
uschar *rcpt_domain;
/* compare address against our subject */
- rcpt_local_part = (unsigned char *)bmiRecipientAccessAddress(recipient);
+ rcpt_local_part = US bmiRecipientAccessAddress(recipient);
rcpt_domain = Ustrchr(rcpt_local_part,'@');
if (rcpt_domain == NULL) {
rcpt_domain = US"";
@@ -364,7 +364,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
(strcmpic(rcpt_domain, bmi_domain) == 0) ) {
/* found verdict */
bmiFreeVerdict(verdict);
- return (uschar *)verdict_str;
+ return US verdict_str;
};
};
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index 58e181309..dbfde8935 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -8,7 +8,10 @@
/* The default settings for Exim configuration variables. A #define without
any data just defines the existence of the variable; it won't get included
in config.h unless some value is defined in Local/Makefile. If there is data,
-it's a default value. */
+it's a default value.
+
+Do not put spaces between # and the 'define'.
+*/
#define ALT_CONFIG_PREFIX
#define TRUSTED_CONFIG_LIST
@@ -178,11 +181,13 @@ it's a default value. */
#define EXPERIMENTAL_DCC
#define EXPERIMENTAL_DSN_INFO
#define EXPERIMENTAL_DMARC
+ #define DMARC_TLD_FILE "/etc/exim/opendmarc.tlds"
#define EXPERIMENTAL_LMDB
#define EXPERIMENTAL_QUEUEFILE
#define EXPERIMENTAL_SPF
#define EXPERIMENTAL_SRS
+
/* For developers */
#define WANT_DEEPER_PRINTF_CHECKS
diff --git a/src/src/daemon.c b/src/src/daemon.c
index ebd06b523..b91b43746 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -21,7 +21,7 @@ typedef struct smtp_slot {
/* An empty slot for initializing (Standard C does not allow constructor
expressions in assignments except as initializers in declarations). */
-static smtp_slot empty_smtp_slot = { 0, NULL };
+static smtp_slot empty_smtp_slot = { .pid = 0, .host_address = NULL };
@@ -109,7 +109,7 @@ never_error(uschar *log_msg, uschar *smtp_msg, int was_errno)
uschar *emsg = (was_errno <= 0)? US"" :
string_sprintf(": %s", strerror(was_errno));
log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg);
-if (smtp_out != NULL) smtp_printf("421 %s\r\n", smtp_msg);
+if (smtp_out != NULL) smtp_printf("421 %s\r\n", FALSE, smtp_msg);
}
@@ -189,7 +189,7 @@ if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr),
{
log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
"getsockname() failed: %s", strerror(errno));
- smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n");
+ smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", FALSE);
goto ERROR_RETURN;
}
@@ -222,7 +222,7 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max)
DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n",
smtp_accept_count, smtp_accept_max);
smtp_printf("421 Too many concurrent SMTP connections; "
- "please try again later.\r\n");
+ "please try again later.\r\n", FALSE);
log_write(L_connection_reject,
LOG_MAIN, "Connection from %s refused: too many connections",
whofrom);
@@ -241,7 +241,7 @@ if (smtp_load_reserve >= 0)
{
DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
(double)load_average/1000.0);
- smtp_printf("421 Too much load; please try again later.\r\n");
+ smtp_printf("421 Too much load; please try again later.\r\n", FALSE);
log_write(L_connection_reject,
LOG_MAIN, "Connection from %s refused: load average = %.2f",
whofrom, (double)load_average/1000.0);
@@ -312,7 +312,7 @@ if ((max_for_this_host > 0) &&
"IP address: count=%d max=%d\n",
host_accept_count, max_for_this_host);
smtp_printf("421 Too many concurrent SMTP connections "
- "from this IP address; please try again later.\r\n");
+ "from this IP address; please try again later.\r\n", FALSE);
log_write(L_connection_reject,
LOG_MAIN, "Connection from %s refused: too many connections "
"from that IP address", whofrom);
@@ -396,7 +396,7 @@ if (pid == 0)
"(smtp_active_hostname): %s", raw_active_hostname,
expand_string_message);
smtp_printf("421 Local configuration error; "
- "please try again later.\r\n");
+ "please try again later.\r\n", FALSE);
mac_smtp_fflush();
search_tidyup();
_exit(EXIT_FAILURE);
@@ -510,6 +510,7 @@ if (pid == 0)
search_tidyup(); /* Close cached databases */
if (!ok) /* Connection was dropped */
{
+ cancel_cutthrough_connection(TRUE, US"receive dropped");
mac_smtp_fflush();
smtp_log_no_mail(); /* Log no mail if configured */
_exit(EXIT_SUCCESS);
@@ -528,6 +529,7 @@ if (pid == 0)
if (fcntl(fd, F_SETFL, O_NONBLOCK) == 0)
for(i = 16; read(fd, buf, sizeof(buf)) > 0 && i > 0; ) i--;
}
+ cancel_cutthrough_connection(TRUE, US"message setup dropped");
search_tidyup();
smtp_log_no_mail(); /* Log no mail if configured */
@@ -653,9 +655,9 @@ if (pid == 0)
/* Don't ever molest the parent's SSL connection, but do clean up
the data structures if necessary. */
- #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
tls_close(TRUE, FALSE);
- #endif
+#endif
/* Reset SIGHUP and SIGCHLD in the child in both cases. */
@@ -665,25 +667,28 @@ if (pid == 0)
if (geteuid() != root_uid && !deliver_drop_privilege)
{
signal(SIGALRM, SIG_DFL);
- (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE,
- 2, US"-Mc", message_id);
+ delivery_re_exec(CEE_EXEC_PANIC);
/* Control does not return here. */
}
/* No need to re-exec; SIGALRM remains set to the default handler */
- (void)deliver_message(message_id, FALSE, FALSE);
+ (void) deliver_message(message_id, FALSE, FALSE);
search_tidyup();
_exit(EXIT_SUCCESS);
}
if (dpid > 0)
{
+ release_cutthrough_connection(US"passed for delivery");
DEBUG(D_any) debug_printf("forked delivery process %d\n", (int)dpid);
}
else
+ {
+ cancel_cutthrough_connection(TRUE, US"delivery fork failed");
log_write(0, LOG_MAIN|LOG_PANIC, "daemon: delivery process fork "
"failed: %s", strerror(errno));
+ }
}
}
}
@@ -1168,6 +1173,8 @@ if (daemon_listen && !inetd_wait_mode)
while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
if (!isdigit(*s))
{
+ int size = 0, len = 0;
+
list = tls_in.on_connect_ports;
tls_in.on_connect_ports = NULL;
sep = 0;
@@ -1175,13 +1182,13 @@ if (daemon_listen && !inetd_wait_mode)
{
if (!isdigit(*s))
{
- struct servent *smtp_service = getservbyname(CS s, "tcp");
+ struct servent * smtp_service = getservbyname(CS s, "tcp");
if (!smtp_service)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
- s= string_sprintf("%d", (int)ntohs(smtp_service->s_port));
+ s = string_sprintf("%d", (int)ntohs(smtp_service->s_port));
}
tls_in.on_connect_ports = string_append_listele(tls_in.on_connect_ports,
- ':', s);
+ &size, &len, ':', s);
}
break;
}
@@ -1201,11 +1208,12 @@ if (daemon_listen && !inetd_wait_mode)
In the same scan, fill in missing port numbers from the default list. When
there is more than one item in the list, extra items are created. */
- for (ipa = addresses; ipa != NULL; ipa = ipa->next)
+ for (ipa = addresses; ipa; ipa = ipa->next)
{
int i;
- if (Ustrcmp(ipa->address, "0.0.0.0") == 0) ipa->address[0] = 0;
+ if (Ustrcmp(ipa->address, "0.0.0.0") == 0)
+ ipa->address[0] = 0;
else if (Ustrcmp(ipa->address, "::0") == 0)
{
ipa->address[0] = ':';
@@ -1217,12 +1225,14 @@ if (daemon_listen && !inetd_wait_mode)
if (daemon_smtp_port[0] <= 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "no port specified for interface "
"%s and daemon_smtp_port is unset; cannot start daemon",
- (ipa->address[0] == 0)? US"\"all IPv4\"" :
- (ipa->address[1] == 0)? US"\"all IPv6\"" : ipa->address);
+ ipa->address[0] == 0 ? US"\"all IPv4\"" :
+ ipa->address[1] == 0 ? US"\"all IPv6\"" : ipa->address);
+
ipa->port = default_smtp_port[0];
for (i = 1; default_smtp_port[i] > 0; i++)
{
ip_address_item *new = store_get(sizeof(ip_address_item));
+
memcpy(new->address, ipa->address, Ustrlen(ipa->address) + 1);
new->port = default_smtp_port[i];
new->next = ipa->next;
@@ -1237,15 +1247,14 @@ if (daemon_listen && !inetd_wait_mode)
also simplifies the construction of the "daemon started" log line. */
pipa = &addresses;
- for (ipa = addresses; ipa != NULL; pipa = &(ipa->next), ipa = ipa->next)
+ for (ipa = addresses; ipa; pipa = &ipa->next, ipa = ipa->next)
{
ip_address_item *ipa2;
/* Handle an IPv4 wildcard */
if (ipa->address[0] == 0)
- {
- for (ipa2 = ipa; ipa2->next != NULL; ipa2 = ipa2->next)
+ for (ipa2 = ipa; ipa2->next; ipa2 = ipa2->next)
{
ip_address_item *ipa3 = ipa2->next;
if (ipa3->address[0] == ':' &&
@@ -1258,13 +1267,11 @@ if (daemon_listen && !inetd_wait_mode)
break;
}
}
- }
/* Handle an IPv6 wildcard. */
else if (ipa->address[0] == ':' && ipa->address[1] == 0)
- {
- for (ipa2 = ipa; ipa2->next != NULL; ipa2 = ipa2->next)
+ for (ipa2 = ipa; ipa2->next; ipa2 = ipa2->next)
{
ip_address_item *ipa3 = ipa2->next;
if (ipa3->address[0] == 0 && ipa3->port == ipa->port)
@@ -1276,12 +1283,11 @@ if (daemon_listen && !inetd_wait_mode)
break;
}
}
- }
}
/* Get a vector to remember all the sockets in */
- for (ipa = addresses; ipa != NULL; ipa = ipa->next)
+ for (ipa = addresses; ipa; ipa = ipa->next)
listen_socket_count++;
listen_sockets = store_get(sizeof(int) * listen_socket_count);
@@ -1403,20 +1409,20 @@ if (daemon_listen && !inetd_wait_mode)
available. Just log failure (can get protocol not available, just like
socket creation can). */
- #ifdef IPV6_V6ONLY
+#ifdef IPV6_V6ONLY
if (af == AF_INET6 && wildcard &&
- setsockopt(listen_sockets[sk], IPPROTO_IPV6, IPV6_V6ONLY, (char *)(&on),
+ setsockopt(listen_sockets[sk], IPPROTO_IPV6, IPV6_V6ONLY, CS (&on),
sizeof(on)) < 0)
log_write(0, LOG_MAIN, "Setting IPV6_V6ONLY on daemon's IPv6 wildcard "
"socket failed (%s): carrying on without it", strerror(errno));
- #endif /* IPV6_V6ONLY */
+#endif /* IPV6_V6ONLY */
/* Set SO_REUSEADDR so that the daemon can be restarted while a connection
is being handled. Without this, a connection will prevent reuse of the
smtp port for listening. */
if (setsockopt(listen_sockets[sk], SOL_SOCKET, SO_REUSEADDR,
- (uschar *)(&on), sizeof(on)) < 0)
+ US (&on), sizeof(on)) < 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "setting SO_REUSEADDR on socket "
"failed when starting daemon: %s", strerror(errno));
@@ -1424,7 +1430,7 @@ if (daemon_listen && !inetd_wait_mode)
disable this because it breaks some broken clients. */
if (tcp_nodelay) setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_NODELAY,
- (uschar *)(&on), sizeof(on));
+ US (&on), sizeof(on));
/* Now bind the socket to the required port; if Exim is being restarted
it may not always be possible to bind immediately, even with SO_REUSEADDR
@@ -1451,8 +1457,11 @@ if (daemon_listen && !inetd_wait_mode)
goto SKIP_SOCKET;
}
msg = US strerror(errno);
- addr = wildcard? ((af == AF_INET6)? US"(any IPv6)" : US"(any IPv4)") :
- ipa->address;
+ addr = wildcard
+ ? af == AF_INET6
+ ? US"(any IPv6)"
+ : US"(any IPv4)"
+ : ipa->address;
if (daemon_startup_retries <= 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
"socket bind() to port %d for address %s failed: %s: "
@@ -1506,7 +1515,7 @@ if (daemon_listen && !inetd_wait_mode)
are going to ignore. We remove the address from the chain, and back up the
counts. */
- SKIP_SOCKET:
+ SKIP_SOCKET:
sk--; /* Back up the count */
listen_socket_count--; /* Reduce the total */
if (ipa == addresses) addresses = ipa->next; else
@@ -1522,7 +1531,8 @@ if (daemon_listen && !inetd_wait_mode)
/* If we are not listening, we want to write a pid file only if -oP was
explicitly given. */
-else if (override_pid_file_path == NULL) write_pid = FALSE;
+else if (!override_pid_file_path)
+ write_pid = FALSE;
/* Write the pid to a known file for assistance in identification, if required.
We do this before giving up root privilege, because on some systems it is
@@ -1542,25 +1552,22 @@ if (running_in_test_harness || write_pid)
{
FILE *f;
- if (override_pid_file_path != NULL)
+ if (override_pid_file_path)
pid_file_path = override_pid_file_path;
if (pid_file_path[0] == 0)
pid_file_path = string_sprintf("%s/exim-daemon.pid", spool_directory);
- f = modefopen(pid_file_path, "wb", 0644);
- if (f != NULL)
+ if ((f = modefopen(pid_file_path, "wb", 0644)))
{
(void)fprintf(f, "%d\n", (int)getpid());
(void)fclose(f);
DEBUG(D_any) debug_printf("pid written to %s\n", pid_file_path);
}
else
- {
DEBUG(D_any)
debug_printf("%s\n", string_open_failed(errno, "pid file %s",
pid_file_path));
- }
}
/* Set up the handler for SIGHUP, which causes a restart of the daemon. */
@@ -1630,7 +1637,7 @@ else if (daemon_listen)
int i, j;
int smtp_ports = 0;
int smtps_ports = 0;
- ip_address_item * ipa;
+ ip_address_item * ipa, * i2;
uschar * p = big_buffer;
uschar * qinfo = queue_interval > 0
? string_sprintf("-q%s", readconf_printtime(queue_interval))
@@ -1646,62 +1653,60 @@ else if (daemon_listen)
for (j = 0; j < 2; j++)
{
for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next)
- {
- /* First time round, look for SMTP ports; second time round, look for
- SMTPS ports. For the first one of each, insert leading text. */
-
- if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
- {
- if (j == 0)
- {
- if (smtp_ports++ == 0)
- {
- memcpy(p, "SMTP on", 8);
- p += 7;
- }
- }
- else
- {
- if (smtps_ports++ == 0)
- {
- (void)sprintf(CS p, "%sSMTPS on",
- smtp_ports == 0 ? "" : " and for ");
- while (*p) p++;
- }
- }
-
- /* Now the information about the port (and sometimes interface) */
-
- if (ipa->address[0] == ':' && ipa->address[1] == 0)
- {
- if (ipa->next != NULL && ipa->next->address[0] == 0 &&
- ipa->next->port == ipa->port)
- {
- (void)sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port);
- ipa = ipa->next;
- }
- else if (ipa->v6_include_v4)
- (void)sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port);
- else
- (void)sprintf(CS p, " port %d (IPv6)", ipa->port);
- }
- else if (ipa->address[0] == 0)
- (void)sprintf(CS p, " port %d (IPv4)", ipa->port);
- else if ( i > 0
- && host_is_tls_on_connect_port(ipa[-1].port) == (j > 0)
- && Ustrcmp(ipa->address, ipa[-1].address) == 0
- )
+ {
+ /* First time round, look for SMTP ports; second time round, look for
+ SMTPS ports. For the first one of each, insert leading text. */
+
+ if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
+ {
+ if (j == 0)
+ {
+ if (smtp_ports++ == 0)
+ {
+ memcpy(p, "SMTP on", 8);
+ p += 7;
+ }
+ }
+ else
+ if (smtps_ports++ == 0)
+ p += sprintf(CS p, "%sSMTPS on",
+ smtp_ports == 0 ? "" : " and for ");
+
+ /* Now the information about the port (and sometimes interface) */
+
+ if (ipa->address[0] == ':' && ipa->address[1] == 0)
+ { /* v6 wildcard */
+ if (ipa->next && ipa->next->address[0] == 0 &&
+ ipa->next->port == ipa->port)
{
- if (p[-1] == '}') p--;
- while (isdigit(*--p)) ;
- (void)sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{",
- ipa[-1].port, ipa->port);
+ p += sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port);
+ ipa = ipa->next;
}
- else
- (void)sprintf(CS p, " [%s]:%d", ipa->address, ipa->port);
- while (*p != 0) p++;
- }
- }
+ else if (ipa->v6_include_v4)
+ p += sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port);
+ else
+ p += sprintf(CS p, " port %d (IPv6)", ipa->port);
+ }
+ else if (ipa->address[0] == 0) /* v4 wildcard */
+ p += sprintf(CS p, " port %d (IPv4)", ipa->port);
+ else /* check for previously-seen IP */
+ {
+ for (i2 = addresses; i2 != ipa; i2 = i2->next)
+ if ( host_is_tls_on_connect_port(i2->port) == (j > 0)
+ && Ustrcmp(ipa->address, i2->address) == 0
+ )
+ { /* found; append port to list */
+ if (p[-1] == '}') p--;
+ while (isdigit(*--p)) ;
+ p += 1 + sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{",
+ i2->port, ipa->port);
+ break;
+ }
+ if (i2 == ipa) /* first-time IP */
+ p += sprintf(CS p, " [%s]:%d", ipa->address, ipa->port);
+ }
+ }
+ }
if (ipa)
{
@@ -1962,10 +1967,8 @@ for (;;)
errno = EINTR;
}
else
- {
lcount = select(max_socket + 1, (SELECT_ARG2_TYPE *)&select_listen,
NULL, NULL, NULL);
- }
if (lcount < 0)
{
@@ -1991,10 +1994,9 @@ for (;;)
while (lcount-- > 0)
{
int accept_socket = -1;
+
if (!select_failed)
- {
for (sk = 0; sk < listen_socket_count; sk++)
- {
if (FD_ISSET(listen_sockets[sk], &select_listen))
{
len = sizeof(accepted);
@@ -2003,8 +2005,6 @@ for (;;)
FD_CLR(listen_sockets[sk], &select_listen);
break;
}
- }
- }
/* If select or accept has failed and this was not caused by an
interruption, log the incident and try again. With asymmetric TCP/IP
diff --git a/src/src/dane-openssl.c b/src/src/dane-openssl.c
index 97acccb5a..0a74f1f28 100644
--- a/src/src/dane-openssl.c
+++ b/src/src/dane-openssl.c
@@ -84,6 +84,7 @@ typedef int CRYPTO_ONCE;
#ifndef OPENSSL_NO_ERR
#define DANESSL_F_PLACEHOLDER 0 /* FIRST! Value TBD */
static ERR_STRING_DATA dane_str_functs[] = {
+ /* error string */
{DANESSL_F_PLACEHOLDER, "DANE library"}, /* FIRST!!! */
{DANESSL_F_ADD_SKID, "add_skid"},
{DANESSL_F_ADD_TLSA, "DANESSL_add_tlsa"},
@@ -101,6 +102,7 @@ static ERR_STRING_DATA dane_str_functs[] = {
{0, NULL}
};
static ERR_STRING_DATA dane_str_reasons[] = {
+ /* error string */
{DANESSL_R_BAD_CERT, "Bad TLSA record certificate"},
{DANESSL_R_BAD_CERT_PKEY, "Bad TLSA record certificate public key"},
{DANESSL_R_BAD_DATA_LENGTH, "Bad TLSA record digest length"},
@@ -251,12 +253,12 @@ for (matched = 0; !matched && slist; slist = slist->next)
{
case DANESSL_SELECTOR_CERT:
len = i2d_X509(cert, NULL);
- buf2 = buf = (unsigned char *) OPENSSL_malloc(len);
+ buf2 = buf = US OPENSSL_malloc(len);
if(buf) i2d_X509(cert, &buf2);
break;
case DANESSL_SELECTOR_SPKI:
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
- buf2 = buf = (unsigned char *) OPENSSL_malloc(len);
+ buf2 = buf = US OPENSSL_malloc(len);
if(buf) i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &buf2);
break;
}
@@ -822,7 +824,7 @@ if (gn->type != GEN_DNS)
return 0;
if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING)
return 0;
-return check_name((const char *) ASN1_STRING_get0_data(gn->d.ia5),
+return check_name(CCS ASN1_STRING_get0_data(gn->d.ia5),
ASN1_STRING_length(gn->d.ia5));
}
@@ -846,12 +848,12 @@ if (!(entry_str = X509_NAME_ENTRY_get_data(entry)))
if ((len = ASN1_STRING_to_UTF8(&namebuf, entry_str)) < 0)
return 0;
-if (len <= 0 || check_name((char *) namebuf, len) == 0)
+if (len <= 0 || check_name(CS namebuf, len) == 0)
{
OPENSSL_free(namebuf);
return 0;
}
-return (char *) namebuf;
+return CS namebuf;
}
static int
diff --git a/src/src/dbfn.c b/src/src/dbfn.c
index c9c6fb707..5529fe93f 100644
--- a/src/src/dbfn.c
+++ b/src/src/dbfn.c
@@ -91,7 +91,7 @@ int rc, save_errno;
BOOL read_only = flags == O_RDONLY;
BOOL created = FALSE;
flock_t lock_data;
-uschar buffer[256];
+uschar dirname[256], filename[256];
/* The first thing to do is to open a separate file on which to lock. This
ensures that Exim has exclusive use of the database before it even tries to
@@ -106,19 +106,20 @@ make the directory as well, just in case. We won't be doing this many times
unnecessarily, because usually the lock file will be there. If the directory
exists, there is no error. */
-sprintf(CS buffer, "%s/db/%s.lockfile", spool_directory, name);
+snprintf(CS dirname, sizeof(dirname), "%s/db", spool_directory);
+snprintf(CS filename, sizeof(filename), "%s/%s.lockfile", dirname, name);
-if ((dbblock->lockfd = Uopen(buffer, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
+if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
{
created = TRUE;
(void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, TRUE);
- dbblock->lockfd = Uopen(buffer, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
+ dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
}
if (dbblock->lockfd < 0)
{
log_write(0, LOG_MAIN, "%s",
- string_open_failed(errno, "database lock file %s", buffer));
+ string_open_failed(errno, "database lock file %s", filename));
errno = 0; /* Indicates locking failure */
return NULL;
}
@@ -130,7 +131,7 @@ lock_data.l_type = read_only? F_RDLCK : F_WRLCK;
lock_data.l_whence = lock_data.l_start = lock_data.l_len = 0;
DEBUG(D_hints_lookup|D_retry|D_route|D_deliver)
- debug_printf("locking %s\n", buffer);
+ debug_printf("locking %s\n", filename);
sigalrm_seen = FALSE;
alarm(EXIMDB_LOCK_TIMEOUT);
@@ -141,14 +142,14 @@ if (sigalrm_seen) errno = ETIMEDOUT;
if (rc < 0)
{
log_write(0, LOG_MAIN|LOG_PANIC, "Failed to get %s lock for %s: %s",
- read_only ? "read" : "write", buffer,
+ read_only ? "read" : "write", filename,
errno == ETIMEDOUT ? "timed out" : strerror(errno));
(void)close(dbblock->lockfd);
errno = 0; /* Indicates locking failure */
return NULL;
}
-DEBUG(D_hints_lookup) debug_printf("locked %s\n", buffer);
+DEBUG(D_hints_lookup) debug_printf("locked %s\n", filename);
/* At this point we have an opened and locked separate lock file, that is,
exclusive access to the database, so we can go ahead and open it. If we are
@@ -159,18 +160,15 @@ databases - often this is caused by non-matching db.h and the library. To make
it easy to pin this down, there are now debug statements on either side of the
open call. */
-sprintf(CS buffer, "%s/db/%s", spool_directory, name);
-DEBUG(D_hints_lookup) debug_printf("EXIM_DBOPEN(%s)\n", buffer);
-EXIM_DBOPEN(buffer, flags, EXIMDB_MODE, &(dbblock->dbptr));
-DEBUG(D_hints_lookup) debug_printf("returned from EXIM_DBOPEN\n");
+snprintf(CS filename, sizeof(filename), "%s/%s", dirname, name);
+EXIM_DBOPEN(filename, dirname, flags, EXIMDB_MODE, &(dbblock->dbptr));
if (!dbblock->dbptr && errno == ENOENT && flags == O_RDWR)
{
DEBUG(D_hints_lookup)
- debug_printf("%s appears not to exist: trying to create\n", buffer);
+ debug_printf("%s appears not to exist: trying to create\n", filename);
created = TRUE;
- EXIM_DBOPEN(buffer, flags|O_CREAT, EXIMDB_MODE, &(dbblock->dbptr));
- DEBUG(D_hints_lookup) debug_printf("returned from EXIM_DBOPEN\n");
+ EXIM_DBOPEN(filename, dirname, flags|O_CREAT, EXIMDB_MODE, &(dbblock->dbptr));
}
save_errno = errno;
@@ -193,22 +191,22 @@ if (created && geteuid() == root_uid)
{
DIR *dd;
struct dirent *ent;
- uschar *lastname = Ustrrchr(buffer, '/') + 1;
+ uschar *lastname = Ustrrchr(filename, '/') + 1;
int namelen = Ustrlen(name);
*lastname = 0;
- dd = opendir(CS buffer);
+ dd = opendir(CS filename);
while ((ent = readdir(dd)))
if (Ustrncmp(ent->d_name, name, namelen) == 0)
{
struct stat statbuf;
Ustrcpy(lastname, ent->d_name);
- if (Ustat(buffer, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
+ if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
{
- DEBUG(D_hints_lookup) debug_printf("ensuring %s is owned by exim\n", buffer);
- if (Uchown(buffer, exim_uid, exim_gid))
- DEBUG(D_hints_lookup) debug_printf("failed setting %s to owned by exim\n", buffer);
+ DEBUG(D_hints_lookup) debug_printf("ensuring %s is owned by exim\n", filename);
+ if (Uchown(filename, exim_uid, exim_gid))
+ DEBUG(D_hints_lookup) debug_printf("failed setting %s to owned by exim\n", filename);
}
}
@@ -216,25 +214,25 @@ if (created && geteuid() == root_uid)
}
/* If the open has failed, return NULL, leaving errno set. If lof is TRUE,
-log the event - also for debugging - but not if the file just doesn't exist. */
+log the event - also for debugging - but debug only if the file just doesn't
+exist. */
if (!dbblock->dbptr)
{
- if (save_errno != ENOENT)
- if (lof)
- log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s",
- buffer));
- else
- DEBUG(D_hints_lookup)
- debug_printf("%s", CS string_open_failed(save_errno, "DB file %s\n",
- buffer));
+ if (lof && save_errno != ENOENT)
+ log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s",
+ filename));
+ else
+ DEBUG(D_hints_lookup)
+ debug_printf("%s\n", CS string_open_failed(save_errno, "DB file %s",
+ filename));
(void)close(dbblock->lockfd);
errno = save_errno;
return NULL;
}
DEBUG(D_hints_lookup)
- debug_printf("opened hints database %s: flags=%s\n", buffer,
+ debug_printf("opened hints database %s: flags=%s\n", filename,
flags == O_RDONLY ? "O_RDONLY"
: flags == O_RDWR ? "O_RDWR"
: flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
@@ -531,7 +529,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE);
stop = clock();
- if (odb != NULL)
+ if (odb)
{
current = i;
printf("opened %d\n", current);
diff --git a/src/src/dbstuff.h b/src/src/dbstuff.h
index 576941b61..aec549f48 100644
--- a/src/src/dbstuff.h
+++ b/src/src/dbstuff.h
@@ -39,7 +39,7 @@ tdb_traverse to be called) */
/* Access functions */
/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
*(dbpp) = tdb_open(CS name, 0, TDB_DEFAULT, flags, mode)
/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
@@ -77,7 +77,7 @@ free() must not die when passed NULL */
#define EXIM_DBDELETE_CURSOR(cursor) free(cursor)
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) tdb_close(db)
+#define EXIM_DBCLOSE__(db) tdb_close(db)
/* Datum access types - these are intended to be assignable */
@@ -113,87 +113,176 @@ definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
/***************** Berkeley db 3.x/4.x native definitions ******************/
/* Basic DB type */
-#define EXIM_DB DB
-
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+# define EXIM_DB DB_ENV
/* Cursor type, for scanning */
-#define EXIM_CURSOR DBC
+# define EXIM_CURSOR DBC
/* The datum type used for queries */
-#define EXIM_DATUM DBT
+# define EXIM_DATUM DBT
/* Some text for messages */
-#define EXIM_DBTYPE "db (v3/4)"
+# define EXIM_DBTYPE "db (v4.1+)"
+
+/* Only more-recent versions. 5+ ? */
+# ifndef DB_FORCESYNC
+# define DB_FORCESYNC 0
+# endif
+
/* Access functions */
/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. The
-API changed for DB 4.1. */
+API changed for DB 4.1. - and we also starting using the "env" with a
+specified working dir, to avoid the DBCONFIG file trap. */
+
+# define ENV_TO_DB(env) ((DB *)((env)->app_private))
+
+# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
+ if ( db_env_create(dbpp, 0) != 0 \
+ || ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), 0) \
+ || (*dbpp)->open(*dbpp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0\
+ ) \
+ *dbpp = NULL; \
+ else if (db_create((DB **) &((*dbpp)->app_private), *dbpp, 0) != 0) \
+ { \
+ ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0); \
+ *dbpp = NULL; \
+ } \
+ else if (ENV_TO_DB(*dbpp)->open(ENV_TO_DB(*dbpp), NULL, CS name, NULL, \
+ (flags) == O_RDONLY ? DB_UNKNOWN : DB_HASH, \
+ (flags) == O_RDONLY ? DB_RDONLY : DB_CREATE, \
+ mode) != 0 \
+ ) \
+ { \
+ ENV_TO_DB(*dbpp)->close(ENV_TO_DB(*dbpp), 0); \
+ ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0); \
+ *dbpp = NULL; \
+ }
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
- if (db_create(dbpp, NULL, 0) != 0 || \
- ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), \
- ((*dbpp)->open)(*dbpp, NULL, CS name, NULL, \
- ((flags) == O_RDONLY)? DB_UNKNOWN : DB_HASH, \
- ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
- mode)) != 0) *(dbpp) = NULL
-#else
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+# define EXIM_DBGET(db, key, data) \
+ (ENV_TO_DB(db)->get(ENV_TO_DB(db), NULL, &key, &data, 0) == 0)
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+# define EXIM_DBPUT(db, key, data) \
+ ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, 0)
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+# define EXIM_DBPUTB(db, key, data) \
+ ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, DB_NOOVERWRITE)
+
+/* Return values from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
+
+/* EXIM_DBDEL */
+# define EXIM_DBDEL(db, key) ENV_TO_DB(db)->del(ENV_TO_DB(db), NULL, &key, 0)
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
+
+# define EXIM_DBCREATE_CURSOR(db, cursor) \
+ ENV_TO_DB(db)->cursor(ENV_TO_DB(db), NULL, cursor, 0)
+
+/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
+# define EXIM_DBSCAN(db, key, data, first, cursor) \
+ ((cursor)->c_get(cursor, &key, &data, \
+ (first? DB_FIRST : DB_NEXT)) == 0)
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
+# define EXIM_DBDELETE_CURSOR(cursor) \
+ (cursor)->c_close(cursor)
+
+/* EXIM_DBCLOSE */
+# define EXIM_DBCLOSE__(db) \
+ (ENV_TO_DB(db)->close(ENV_TO_DB(db), 0) , ((DB_ENV *)(db))->close((DB_ENV *)(db), DB_FORCESYNC))
+
+/* Datum access types - these are intended to be assignable. */
+
+# define EXIM_DATUM_SIZE(datum) (datum).size
+# define EXIM_DATUM_DATA(datum) (datum).data
+
+/* The whole datum structure contains other fields that must be cleared
+before use, but we don't have to free anything after reading data. */
+
+# define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
+# define EXIM_DATUM_FREE(datum)
+
+#else /* pre- 4.1 */
+
+# define EXIM_DB DB
+
+/* Cursor type, for scanning */
+# define EXIM_CURSOR DBC
+
+/* The datum type used for queries */
+# define EXIM_DATUM DBT
+
+/* Some text for messages */
+# define EXIM_DBTYPE "db (v3/4)"
+
+/* Access functions */
+
+/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. */
+
+# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
if (db_create(dbpp, NULL, 0) != 0 || \
((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), \
((*dbpp)->open)(*dbpp, CS name, NULL, \
((flags) == O_RDONLY)? DB_UNKNOWN : DB_HASH, \
((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
mode)) != 0) *(dbpp) = NULL
-#endif
/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-#define EXIM_DBGET(db, key, data) \
+# define EXIM_DBGET(db, key, data) \
((db)->get(db, NULL, &key, &data, 0) == 0)
/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-#define EXIM_DBPUT(db, key, data) \
+# define EXIM_DBPUT(db, key, data) \
(db)->put(db, NULL, &key, &data, 0)
/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-#define EXIM_DBPUTB(db, key, data) \
+# define EXIM_DBPUTB(db, key, data) \
(db)->put(db, NULL, &key, &data, DB_NOOVERWRITE)
/* Return values from EXIM_DBPUTB */
-#define EXIM_DBPUTB_OK 0
-#define EXIM_DBPUTB_DUP DB_KEYEXIST
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
/* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0)
+# define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0)
/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-#define EXIM_DBCREATE_CURSOR(db, cursor) \
+# define EXIM_DBCREATE_CURSOR(db, cursor) \
(db)->cursor(db, NULL, cursor, 0)
/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-#define EXIM_DBSCAN(db, key, data, first, cursor) \
+# define EXIM_DBSCAN(db, key, data, first, cursor) \
((cursor)->c_get(cursor, &key, &data, \
(first? DB_FIRST : DB_NEXT)) == 0)
/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
-#define EXIM_DBDELETE_CURSOR(cursor) \
+# define EXIM_DBDELETE_CURSOR(cursor) \
(cursor)->c_close(cursor)
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) (db)->close(db, 0)
+# define EXIM_DBCLOSE__(db) (db)->close(db, 0)
/* Datum access types - these are intended to be assignable. */
-#define EXIM_DATUM_SIZE(datum) (datum).size
-#define EXIM_DATUM_DATA(datum) (datum).data
+# define EXIM_DATUM_SIZE(datum) (datum).size
+# define EXIM_DATUM_DATA(datum) (datum).data
/* The whole datum structure contains other fields that must be cleared
before use, but we don't have to free anything after reading data. */
-#define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
-#define EXIM_DATUM_FREE(datum)
+# define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
+# define EXIM_DATUM_FREE(datum)
+
+#endif
#else /* DB_VERSION_MAJOR >= 3 */
@@ -215,7 +304,7 @@ before use, but we don't have to free anything after reading data. */
/* Access functions */
/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
if ((errno = db_open(CS name, DB_HASH, \
((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
mode, NULL, NULL, dbpp)) != 0) *(dbpp) = NULL
@@ -264,7 +353,7 @@ the new option that is available, so I guess that it happened at 2.5.x. */
(cursor)->c_close(cursor)
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) (db)->close(db, 0)
+#define EXIM_DBCLOSE__(db) (db)->close(db, 0)
/* Datum access types - these are intended to be assignable. */
@@ -312,7 +401,7 @@ before been able to pass successfully. */
/* Access functions */
/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
*(dbpp) = dbopen(CS name, flags, mode, DB_HASH, NULL)
/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
@@ -347,7 +436,7 @@ refer to cursor, to keep picky compilers happy. */
#define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; }
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) (db)->close(db)
+#define EXIM_DBCLOSE__(db) (db)->close(db)
/* Datum access types - these are intended to be assignable */
@@ -389,7 +478,7 @@ typedef struct {
/* Access functions */
/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
{ (*(dbpp)) = (EXIM_DB *) malloc(sizeof(EXIM_DB));\
if (*(dbpp) != NULL) { \
(*(dbpp))->lkey.dptr = NULL;\
@@ -435,7 +524,7 @@ refer to cursor, to keep picky compilers happy. */
#define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; }
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) \
+#define EXIM_DBCLOSE__(db) \
{ gdbm_close((db)->gdbm);\
if ((db)->lkey.dptr != NULL) free((db)->lkey.dptr);\
free(db); }
@@ -478,7 +567,7 @@ interface */
/* Access functions */
/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
*(dbpp) = dbm_open(CS name, flags, mode)
/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
@@ -513,7 +602,7 @@ refer to cursor, to keep picky compilers happy. */
#define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; }
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) dbm_close(db)
+#define EXIM_DBCLOSE__(db) dbm_close(db)
/* Datum access types - these are intended to be assignable */
@@ -528,6 +617,34 @@ after reading data. */
#endif /* USE_GDBM */
+
+
+
+
+# ifdef COMPILE_UTILITY
+
+# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
+ EXIM_DBOPEN__(name, dirname, flags, mode, dbpp)
+# define EXIM_DBCLOSE(db) EXIM_DBCLOSE__(db)
+
+# else
+
+# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
+ do { \
+ DEBUG(D_hints_lookup) \
+ debug_printf("EXIM_DBOPEN: file <%s> dir <%s> flags 0x%x\n", \
+ (name), (dirname), flags); \
+ EXIM_DBOPEN__(name, dirname, flags, mode, dbpp); \
+ DEBUG(D_hints_lookup) debug_printf("returned from EXIM_DBOPEN: %p\n", *dbpp); \
+ } while(0)
+# define EXIM_DBCLOSE(db) \
+ do { \
+ DEBUG(D_hints_lookup) debug_printf("EXIM_DBCLOSE(%p)\n", db); \
+ EXIM_DBCLOSE__(db); \
+ } while(0)
+
+# endif
+
/********************* End of dbm library definitions **********************/
diff --git a/src/src/dcc.c b/src/src/dcc.c
index fcdc5a897..a11e12df4 100644
--- a/src/src/dcc.c
+++ b/src/src/dcc.c
@@ -185,10 +185,10 @@ dcc_process(uschar **listptr)
/* If sockip contains an ip, we use a tcp socket, otherwise a UNIX socket */
if(Ustrcmp(sockip, "")){
- ipaddress = gethostbyname((char *)sockip);
- bzero((char *) &serv_addr_in, sizeof(serv_addr_in));
+ ipaddress = gethostbyname(CS sockip);
+ bzero(CS &serv_addr_in, sizeof(serv_addr_in));
serv_addr_in.sin_family = AF_INET;
- bcopy((char *)ipaddress->h_addr, (char *)&serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
+ bcopy(CS ipaddress->h_addr, CS &serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
serv_addr_in.sin_port = htons(portnr);
if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){
DEBUG(D_acl)
diff --git a/src/src/debug.c b/src/src/debug.c
index 35571547f..09e03f1e4 100644
--- a/src/src/debug.c
+++ b/src/src/debug.c
@@ -182,17 +182,21 @@ if (debug_ptr == debug_buffer)
{
DEBUG(D_timestamp)
{
- time_t now = time(NULL);
- struct tm *t = timestamps_utc? gmtime(&now) : localtime(&now);
- (void) sprintf(CS debug_ptr, "%02d:%02d:%02d ", t->tm_hour, t->tm_min,
- t->tm_sec);
- while(*debug_ptr != 0) debug_ptr++;
+ struct timeval now;
+ time_t tmp;
+ struct tm * t;
+
+ gettimeofday(&now, NULL);
+ tmp = now.tv_sec;
+ t = timestamps_utc ? gmtime(&tmp) : localtime(&tmp);
+ debug_ptr += sprintf(CS debug_ptr,
+ LOGGING(millisec) ? "%02d:%02d:%02d.%03d " : "%02d:%02d:%02d ",
+ t->tm_hour, t->tm_min, t->tm_sec, (int)(now.tv_usec/1000));
}
DEBUG(D_pid)
{
- sprintf(CS debug_ptr, "%5d ", (int)getpid());
- while(*debug_ptr != 0) debug_ptr++;
+ debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid());
}
/* Set up prefix if outputting for host checking and not debugging */
diff --git a/src/src/deliver.c b/src/src/deliver.c
index cb4616e6c..73921980e 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -9,6 +9,7 @@
#include "exim.h"
+#include "transports/smtp.h"
#include <assert.h>
@@ -381,6 +382,7 @@ for (addr2 = addr->next; addr2; addr2 = addr2->next)
addr2->transport_return = addr->transport_return;
addr2->basic_errno = addr->basic_errno;
addr2->more_errno = addr->more_errno;
+ addr2->delivery_usec = addr->delivery_usec;
addr2->special_action = addr->special_action;
addr2->message = addr->message;
addr2->user_message = addr->user_message;
@@ -750,7 +752,12 @@ if (LOGGING(proxy) && proxy_local_address)
}
#endif
-return d_log_interface(s, sp, pp);
+s = d_log_interface(s, sp, pp);
+
+if (testflag(addr, af_tcp_fastopen))
+ s = string_catn(s, sp, pp, US" TFO", 4);
+
+return s;
}
@@ -841,7 +848,7 @@ deliver_host = addr->host_used ? addr->host_used->name : NULL;
addr->host_used
|| Ustrcmp(addr->transport->driver_name, "smtp") == 0
|| Ustrcmp(addr->transport->driver_name, "lmtp") == 0
- ? addr->message : NULL);
+ ? addr->message : NULL);
deliver_host_port = save_port;
deliver_host_address = save_address;
@@ -1028,6 +1035,43 @@ return str;
}
+
+void
+timesince(struct timeval * diff, struct timeval * then)
+{
+gettimeofday(diff, NULL);
+diff->tv_sec -= then->tv_sec;
+if ((diff->tv_usec -= then->tv_usec) < 0)
+ {
+ diff->tv_sec--;
+ diff->tv_usec += 1000*1000;
+ }
+}
+
+
+
+static uschar *
+string_timediff(struct timeval * diff)
+{
+static uschar buf[sizeof("0.000s")];
+
+if (diff->tv_sec >= 5 || !LOGGING(millisec))
+ return readconf_printtime((int)diff->tv_sec);
+
+sprintf(CS buf, "%d.%03ds", (int)diff->tv_sec, (int)diff->tv_usec/1000);
+return buf;
+}
+
+
+uschar *
+string_timesince(struct timeval * then)
+{
+struct timeval diff;
+
+timesince(&diff, then);
+return string_timediff(&diff);
+}
+
/******************************************************************************/
@@ -1156,11 +1200,11 @@ else
}
#ifndef DISABLE_PRDR
- if (addr->flags & af_prdr_used)
+ if (testflag(addr, af_prdr_used))
s = string_catn(s, &size, &ptr, US" PRDR", 5);
#endif
- if (addr->flags & af_chunking_used)
+ if (testflag(addr, af_chunking_used))
s = string_catn(s, &size, &ptr, US" K", 2);
}
@@ -1190,11 +1234,13 @@ if ( LOGGING(smtp_confirmation)
if (LOGGING(queue_time))
s = string_append(s, &size, &ptr, 2, US" QT=",
- readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
+ string_timesince(&received_time));
if (LOGGING(deliver_time))
- s = string_append(s, &size, &ptr, 2, US" DT=",
- readconf_printtime(addr->more_errno));
+ {
+ struct timeval diff = {.tv_sec = addr->more_errno, .tv_usec = addr->delivery_usec};
+ s = string_append(s, &size, &ptr, 2, US" DT=", string_timediff(&diff));
+ }
/* string_cat() always leaves room for the terminator. Release the
store we used to build the line after writing it. */
@@ -1616,7 +1662,7 @@ else
later (with a log entry). */
if (!*sender_address && message_age >= ignore_bounce_errors_after)
- setflag(addr, af_ignore_error);
+ addr->prop.ignore_error = TRUE;
/* Freeze the message if requested, or if this is a bounce message (or other
message with null sender) and this address does not have its own errors
@@ -1624,7 +1670,7 @@ else
to ignore occurs later, instead of sending a message. Logging of freezing
occurs later, just before writing the -H file. */
- if ( !testflag(addr, af_ignore_error)
+ if ( !addr->prop.ignore_error
&& ( addr->special_action == SPECIAL_FREEZE
|| (sender_address[0] == 0 && !addr->prop.errors_address)
) )
@@ -2175,7 +2221,7 @@ if ( !shadowing
addr->return_filename =
spool_fname(US"msglog", message_subdir, message_id,
string_sprintf("-%d-%d", getpid(), return_count++));
-
+
if ((addr->return_file = open_msglog_file(addr->return_filename, 0400, &error)) < 0)
{
common_error(TRUE, addr, errno, US"Unable to %s file for %s transport "
@@ -2346,6 +2392,7 @@ if ((pid = fork()) == 0)
|| (ret = write(pfd[pipe_write], &addr2->flags, sizeof(addr2->flags))) != sizeof(addr2->flags)
|| (ret = write(pfd[pipe_write], &addr2->basic_errno, sizeof(int))) != sizeof(int)
|| (ret = write(pfd[pipe_write], &addr2->more_errno, sizeof(int))) != sizeof(int)
+ || (ret = write(pfd[pipe_write], &addr2->delivery_usec, sizeof(int))) != sizeof(int)
|| (ret = write(pfd[pipe_write], &addr2->special_action, sizeof(int))) != sizeof(int)
|| (ret = write(pfd[pipe_write], &addr2->transport,
sizeof(transport_instance *))) != sizeof(transport_instance *)
@@ -2413,6 +2460,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next)
len = read(pfd[pipe_read], &addr2->flags, sizeof(addr2->flags));
len = read(pfd[pipe_read], &addr2->basic_errno, sizeof(int));
len = read(pfd[pipe_read], &addr2->more_errno, sizeof(int));
+ len = read(pfd[pipe_read], &addr2->delivery_usec, sizeof(int));
len = read(pfd[pipe_read], &addr2->special_action, sizeof(int));
len = read(pfd[pipe_read], &addr2->transport,
sizeof(transport_instance *));
@@ -2638,8 +2686,8 @@ time_t now = time(NULL);
while (addr_local)
{
- time_t delivery_start;
- int deliver_time;
+ struct timeval delivery_start;
+ struct timeval deliver_time;
address_item *addr2, *addr3, *nextaddr;
int logflags = LOG_MAIN;
int logchar = dont_deliver? '*' : '=';
@@ -2734,7 +2782,8 @@ while (addr_local)
BOOL ok =
tp == next->transport
&& !previously_transported(next, TRUE)
- && (addr->flags & (af_pfr|af_file)) == (next->flags & (af_pfr|af_file))
+ && testflag(addr, af_pfr) == testflag(next, af_pfr)
+ && testflag(addr, af_file) == testflag(next, af_file)
&& (!uses_lp || Ustrcmp(next->local_part, addr->local_part) == 0)
&& (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0)
&& same_strings(next->prop.errors_address, addr->prop.errors_address)
@@ -2935,9 +2984,10 @@ while (addr_local)
single delivery. */
deliver_set_expansions(addr);
- delivery_start = time(NULL);
+
+ gettimeofday(&delivery_start, NULL);
deliver_local(addr, FALSE);
- deliver_time = (int)(time(NULL) - delivery_start);
+ timesince(&deliver_time, &delivery_start);
/* If a shadow transport (which must perforce be another local transport), is
defined, and its condition is met, we must pass the message to the shadow
@@ -3074,7 +3124,11 @@ while (addr_local)
/* Done with this address */
- if (result == OK) addr2->more_errno = deliver_time;
+ if (result == OK)
+ {
+ addr2->more_errno = deliver_time.tv_sec;
+ addr2->delivery_usec = deliver_time.tv_usec;
+ }
post_process_one(addr2, result, logflags, DTYPE_TRANSPORT, logchar);
/* If a pipe delivery generated text to be sent back, the result may be
@@ -3216,6 +3270,9 @@ small items (less than PIPE_BUF, which seems to be at least 512 in any Unix and
often bigger) so even if we are reading while the subprocess is still going, we
should never have only a partial item in the buffer.
+hs12: This assumption is not true anymore, since we got quit large items (certificate
+information and such)
+
Argument:
poffset the offset of the parlist item
eop TRUE if the process has completed
@@ -3234,147 +3291,113 @@ address_item *addrlist = p->addrlist;
address_item *addr = p->addr;
pid_t pid = p->pid;
int fd = p->fd;
-uschar *endptr = big_buffer;
-uschar *ptr = endptr;
+
uschar *msg = p->msg;
BOOL done = p->done;
-BOOL finished = FALSE;
-/* minimum size to read is header size including id, subid and length */
-int required = PIPE_HEADER_SIZE;
/* Loop through all items, reading from the pipe when necessary. The pipe
-is set up to be non-blocking, but there are two different Unix mechanisms in
-use. Exim uses O_NONBLOCK if it is defined. This returns 0 for end of file,
-and EAGAIN for no more data. If O_NONBLOCK is not defined, Exim uses O_NDELAY,
-which returns 0 for both end of file and no more data. We distinguish the
-two cases by taking 0 as end of file only when we know the process has
-completed.
-
-Each separate item is written to the pipe in a single write(), and as they are
-all short items, the writes will all be atomic and we should never find
-ourselves in the position of having read an incomplete item. "Short" in this
-case can mean up to about 1K in the case when there is a long error message
-associated with an address. */
+used to be non-blocking. But I do not see a reason for using non-blocking I/O
+here, as the preceding select() tells us, if data is available for reading.
-DEBUG(D_deliver) debug_printf("reading pipe for subprocess %d (%s)\n",
- (int)p->pid, eop? "ended" : "not ended");
+A read() on a "selected" handle should never block, but(!) it may return
+less data then we expected. (The buffer size we pass to read() shouldn't be
+understood as a "request", but as a "limit".)
-while (!done)
- {
- retry_item *r, **rp;
- int remaining = endptr - ptr;
- uschar header[PIPE_HEADER_SIZE + 1];
- uschar id, subid;
- uschar *endc;
+Each separate item is written to the pipe in a timely manner. But, especially for
+larger items, the read(2) may already return partial data from the write(2).
- /* Read (first time) or top up the chars in the buffer if necessary.
- There will be only one read if we get all the available data (i.e. don't
- fill the buffer completely). */
+The write is atomic mostly (depending on the amount written), but atomic does
+not imply "all or noting", it just is "not intermixed" with other writes on the
+same channel (pipe).
- if (remaining < required && !finished)
- {
- int len;
- int available = big_buffer_size - remaining;
-
- if (remaining > 0) memmove(big_buffer, ptr, remaining);
-
- ptr = big_buffer;
- endptr = big_buffer + remaining;
- len = read(fd, endptr, available);
-
- DEBUG(D_deliver) debug_printf("read() yielded %d\n", len);
-
- /* If the result is EAGAIN and the process is not complete, just
- stop reading any more and process what we have already. */
-
- if (len < 0)
- {
- if (!eop && errno == EAGAIN) len = 0; else
- {
- msg = string_sprintf("failed to read pipe from transport process "
- "%d for transport %s: %s", pid, addr->transport->driver_name,
- strerror(errno));
- break;
- }
- }
+*/
- /* If the length is zero (eof or no-more-data), just process what we
- already have. Note that if the process is still running and we have
- read all the data in the pipe (but less that "available") then we
- won't read any more, as "finished" will get set. */
+DEBUG(D_deliver) debug_printf("reading pipe for subprocess %d (%s)\n",
+ (int)p->pid, eop? "ended" : "not ended yet");
- endptr += len;
- remaining += len;
- finished = len != available;
+while (!done)
+ {
+ retry_item *r, **rp;
+ uschar pipeheader[PIPE_HEADER_SIZE+1];
+ uschar *id = &pipeheader[0];
+ uschar *subid = &pipeheader[1];
+ uschar *ptr = big_buffer;
+ size_t required = PIPE_HEADER_SIZE; /* first the pipehaeder, later the data */
+ ssize_t got;
+
+ DEBUG(D_deliver) debug_printf(
+ "expect %lu bytes (pipeheader) from tpt process %d\n", (u_long)required, pid);
+
+ /* We require(!) all the PIPE_HEADER_SIZE bytes here, as we know,
+ they're written in a timely manner, so waiting for the write shouldn't hurt a lot.
+ If we get less, we can assume the subprocess do be done and do not expect any further
+ information from it. */
+
+ got = readn(fd, pipeheader, required);
+ if (got != required)
+ {
+ msg = string_sprintf("got %d of %d bytes (pipeheader) "
+ "from transport process %d for transport %s",
+ got, PIPE_HEADER_SIZE, pid, addr->transport->driver_name);
+ done = TRUE;
+ break;
}
- /* If we are at the end of the available data, exit the loop. */
- if (ptr >= endptr) break;
+ pipeheader[PIPE_HEADER_SIZE] = '\0';
+ DEBUG(D_deliver)
+ debug_printf("got %ld bytes (pipeheader) from transport process %d\n",
+ (long) got, pid);
- /* copy and read header */
- memcpy(header, ptr, PIPE_HEADER_SIZE);
- header[PIPE_HEADER_SIZE] = '\0';
- id = header[0];
- subid = header[1];
- required = Ustrtol(header + 2, &endc, 10) + PIPE_HEADER_SIZE; /* header + data */
+ {
+ /* If we can't decode the pipeheader, the subprocess seems to have a
+ problem, we do not expect any furher information from it. */
+ char *endc;
+ required = Ustrtol(pipeheader+2, &endc, 10);
if (*endc)
{
- msg = string_sprintf("failed to read pipe from transport process "
- "%d for transport %s: error reading size from header", pid, addr->transport->driver_name);
+ msg = string_sprintf("failed to read pipe "
+ "from transport process %d for transport %s: error decoding size from header",
+ pid, addr->transport->driver_name);
done = TRUE;
break;
}
+ }
DEBUG(D_deliver)
- debug_printf("header read id:%c,subid:%c,size:%s,required:%d,remaining:%d,finished:%d\n",
- id, subid, header+2, required, remaining, finished);
-
- /* is there room for the dataset we want to read ? */
- if (required > big_buffer_size - PIPE_HEADER_SIZE)
- {
- msg = string_sprintf("failed to read pipe from transport process "
- "%d for transport %s: big_buffer too small! required size=%d buffer size=%d", pid, addr->transport->driver_name,
- required, big_buffer_size - PIPE_HEADER_SIZE);
- done = TRUE;
- break;
- }
-
- /* We wrote all datasets with atomic write() calls. Remaining < required only
- happens if big_buffer was too small to get all available data from pipe;
- finished has to be false as well. */
-
- if (remaining < required)
- {
- if (!finished)
- continue;
- msg = string_sprintf("failed to read pipe from transport process "
- "%d for transport %s: required size=%d > remaining size=%d and finished=true",
- pid, addr->transport->driver_name, required, remaining);
- done = TRUE;
- break;
+ debug_printf("expect %lu bytes (pipedata) from transport process %d\n",
+ (u_long)required, pid);
+
+ /* Same as above, the transport process will write the bytes announced
+ in a timely manner, so we can just wait for the bytes, getting less than expected
+ is considered a problem of the subprocess, we do not expect anything else from it. */
+ got = readn(fd, big_buffer, required);
+ if (got != required)
+ {
+ msg = string_sprintf("got only %d of %d bytes (pipedata) "
+ "from transport process %d for transport %s",
+ got, required, pid, addr->transport->driver_name);
+ done = TRUE;
+ break;
}
- /* Step past the header */
- ptr += PIPE_HEADER_SIZE;
-
/* Handle each possible type of item, assuming the complete item is
available in store. */
- switch (id)
+ switch (*id)
{
/* Host items exist only if any hosts were marked unusable. Match
up by checking the IP address. */
case 'H':
- for (h = addrlist->host_list; h; h = h->next)
- {
- if (!h->address || Ustrcmp(h->address, ptr+2) != 0) continue;
- h->status = ptr[0];
- h->why = ptr[1];
- }
- ptr += 2;
- while (*ptr++);
- break;
+ for (h = addrlist->host_list; h; h = h->next)
+ {
+ if (!h->address || Ustrcmp(h->address, ptr+2) != 0) continue;
+ h->status = ptr[0];
+ h->why = ptr[1];
+ }
+ ptr += 2;
+ while (*ptr++);
+ break;
/* Retry items are sent in a preceding R item for each address. This is
kept separate to keep each message short enough to guarantee it won't
@@ -3388,62 +3411,61 @@ while (!done)
that a "delete" item is dropped in favour of an "add" item. */
case 'R':
- if (!addr) goto ADDR_MISMATCH;
+ if (!addr) goto ADDR_MISMATCH;
- DEBUG(D_deliver|D_retry)
- debug_printf("reading retry information for %s from subprocess\n",
- ptr+1);
+ DEBUG(D_deliver|D_retry)
+ debug_printf("reading retry information for %s from subprocess\n",
+ ptr+1);
- /* Cut out any "delete" items on the list. */
+ /* Cut out any "delete" items on the list. */
- for (rp = &(addr->retries); (r = *rp); rp = &r->next)
- if (Ustrcmp(r->key, ptr+1) == 0) /* Found item with same key */
- {
- if ((r->flags & rf_delete) == 0) break; /* It was not "delete" */
- *rp = r->next; /* Excise a delete item */
- DEBUG(D_deliver|D_retry)
- debug_printf(" existing delete item dropped\n");
- }
+ for (rp = &addr->retries; (r = *rp); rp = &r->next)
+ if (Ustrcmp(r->key, ptr+1) == 0) /* Found item with same key */
+ {
+ if (!(r->flags & rf_delete)) break; /* It was not "delete" */
+ *rp = r->next; /* Excise a delete item */
+ DEBUG(D_deliver|D_retry)
+ debug_printf(" existing delete item dropped\n");
+ }
- /* We want to add a delete item only if there is no non-delete item;
- however we still have to step ptr through the data. */
+ /* We want to add a delete item only if there is no non-delete item;
+ however we still have to step ptr through the data. */
- if (!r || (*ptr & rf_delete) == 0)
- {
- r = store_get(sizeof(retry_item));
- r->next = addr->retries;
- addr->retries = r;
- r->flags = *ptr++;
- r->key = string_copy(ptr);
- while (*ptr++);
- memcpy(&(r->basic_errno), ptr, sizeof(r->basic_errno));
- ptr += sizeof(r->basic_errno);
- memcpy(&(r->more_errno), ptr, sizeof(r->more_errno));
- ptr += sizeof(r->more_errno);
- r->message = (*ptr)? string_copy(ptr) : NULL;
- DEBUG(D_deliver|D_retry)
- debug_printf(" added %s item\n",
- ((r->flags & rf_delete) == 0)? "retry" : "delete");
- }
+ if (!r || !(*ptr & rf_delete))
+ {
+ r = store_get(sizeof(retry_item));
+ r->next = addr->retries;
+ addr->retries = r;
+ r->flags = *ptr++;
+ r->key = string_copy(ptr);
+ while (*ptr++);
+ memcpy(&r->basic_errno, ptr, sizeof(r->basic_errno));
+ ptr += sizeof(r->basic_errno);
+ memcpy(&r->more_errno, ptr, sizeof(r->more_errno));
+ ptr += sizeof(r->more_errno);
+ r->message = *ptr ? string_copy(ptr) : NULL;
+ DEBUG(D_deliver|D_retry) debug_printf(" added %s item\n",
+ r->flags & rf_delete ? "delete" : "retry");
+ }
- else
- {
- DEBUG(D_deliver|D_retry)
- debug_printf(" delete item not added: non-delete item exists\n");
- ptr++;
- while(*ptr++);
- ptr += sizeof(r->basic_errno) + sizeof(r->more_errno);
- }
+ else
+ {
+ DEBUG(D_deliver|D_retry)
+ debug_printf(" delete item not added: non-delete item exists\n");
+ ptr++;
+ while(*ptr++);
+ ptr += sizeof(r->basic_errno) + sizeof(r->more_errno);
+ }
- while(*ptr++);
- break;
+ while(*ptr++);
+ break;
/* Put the amount of data written into the parlist block */
case 'S':
- memcpy(&(p->transport_count), ptr, sizeof(transport_count));
- ptr += sizeof(transport_count);
- break;
+ memcpy(&(p->transport_count), ptr, sizeof(transport_count));
+ ptr += sizeof(transport_count);
+ break;
/* Address items are in the order of items on the address chain. We
remember the current address value in case this function is called
@@ -3454,164 +3476,163 @@ while (!done)
#ifdef SUPPORT_TLS
case 'X':
- if (!addr) goto ADDR_MISMATCH; /* Below, in 'A' handler */
- switch (subid)
- {
- case '1':
- addr->cipher = NULL;
- addr->peerdn = NULL;
-
- if (*ptr)
- addr->cipher = string_copy(ptr);
- while (*ptr++);
- if (*ptr)
- addr->peerdn = string_copy(ptr);
- break;
-
- case '2':
- if (*ptr)
- (void) tls_import_cert(ptr, &addr->peercert);
- else
- addr->peercert = NULL;
- break;
+ if (!addr) goto ADDR_MISMATCH; /* Below, in 'A' handler */
+ switch (*subid)
+ {
+ case '1':
+ addr->cipher = NULL;
+ addr->peerdn = NULL;
- case '3':
- if (*ptr)
- (void) tls_import_cert(ptr, &addr->ourcert);
- else
- addr->ourcert = NULL;
- break;
+ if (*ptr)
+ addr->cipher = string_copy(ptr);
+ while (*ptr++);
+ if (*ptr)
+ addr->peerdn = string_copy(ptr);
+ break;
+
+ case '2':
+ if (*ptr)
+ (void) tls_import_cert(ptr, &addr->peercert);
+ else
+ addr->peercert = NULL;
+ break;
+
+ case '3':
+ if (*ptr)
+ (void) tls_import_cert(ptr, &addr->ourcert);
+ else
+ addr->ourcert = NULL;
+ break;
# ifndef DISABLE_OCSP
- case '4':
- addr->ocsp = OCSP_NOT_REQ;
- if (*ptr)
- addr->ocsp = *ptr - '0';
- break;
+ case '4':
+ addr->ocsp = *ptr ? *ptr - '0' : OCSP_NOT_REQ;
+ break;
# endif
- }
- while (*ptr++);
- break;
+ }
+ while (*ptr++);
+ break;
#endif /*SUPPORT_TLS*/
case 'C': /* client authenticator information */
- switch (subid)
- {
- case '1':
- addr->authenticator = (*ptr)? string_copy(ptr) : NULL;
- break;
- case '2':
- addr->auth_id = (*ptr)? string_copy(ptr) : NULL;
- break;
- case '3':
- addr->auth_sndr = (*ptr)? string_copy(ptr) : NULL;
- break;
- }
- while (*ptr++);
- break;
+ switch (*subid)
+ {
+ case '1': addr->authenticator = *ptr ? string_copy(ptr) : NULL; break;
+ case '2': addr->auth_id = *ptr ? string_copy(ptr) : NULL; break;
+ case '3': addr->auth_sndr = *ptr ? string_copy(ptr) : NULL; break;
+ }
+ while (*ptr++);
+ break;
#ifndef DISABLE_PRDR
case 'P':
- addr->flags |= af_prdr_used;
- break;
+ setflag(addr, af_prdr_used);
+ break;
#endif
case 'K':
- addr->flags |= af_chunking_used;
- break;
+ setflag(addr, af_chunking_used);
+ break;
- case 'D':
- if (!addr) goto ADDR_MISMATCH;
- memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware));
- ptr += sizeof(addr->dsn_aware);
- DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware);
- break;
+ case 'T':
+ setflag(addr, af_tcp_fastopen);
+ break;
- case 'A':
- if (!addr)
- {
- ADDR_MISMATCH:
- msg = string_sprintf("address count mismatch for data read from pipe "
- "for transport process %d for transport %s", pid,
- addrlist->transport->driver_name);
- done = TRUE;
+ case 'D':
+ if (!addr) goto ADDR_MISMATCH;
+ memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware));
+ ptr += sizeof(addr->dsn_aware);
+ DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware);
break;
- }
- switch (subid)
- {
-#ifdef SUPPORT_SOCKS
- case '2': /* proxy information; must arrive before A0 and applies to that addr XXX oops*/
- proxy_session = TRUE; /*XXX should this be cleared somewhere? */
- if (*ptr == 0)
- ptr++;
- else
- {
- proxy_local_address = string_copy(ptr);
- while(*ptr++);
- memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port));
- ptr += sizeof(proxy_local_port);
- }
+ case 'A':
+ if (!addr)
+ {
+ ADDR_MISMATCH:
+ msg = string_sprintf("address count mismatch for data read from pipe "
+ "for transport process %d for transport %s", pid,
+ addrlist->transport->driver_name);
+ done = TRUE;
break;
-#endif
+ }
-#ifdef EXPERIMENTAL_DSN_INFO
- case '1': /* must arrive before A0, and applies to that addr */
- /* Two strings: smtp_greeting and helo_response */
- addr->smtp_greeting = string_copy(ptr);
- while(*ptr++);
- addr->helo_response = string_copy(ptr);
- while(*ptr++);
- break;
-#endif
+ switch (*subid)
+ {
+ #ifdef SUPPORT_SOCKS
+ case '2': /* proxy information; must arrive before A0 and applies to that addr XXX oops*/
+ proxy_session = TRUE; /*XXX should this be cleared somewhere? */
+ if (*ptr == 0)
+ ptr++;
+ else
+ {
+ proxy_local_address = string_copy(ptr);
+ while(*ptr++);
+ memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port));
+ ptr += sizeof(proxy_local_port);
+ }
+ break;
+ #endif
- case '0':
- addr->transport_return = *ptr++;
- addr->special_action = *ptr++;
- memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
- ptr += sizeof(addr->basic_errno);
- memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
- ptr += sizeof(addr->more_errno);
- memcpy(&(addr->flags), ptr, sizeof(addr->flags));
- ptr += sizeof(addr->flags);
- addr->message = (*ptr)? string_copy(ptr) : NULL;
- while(*ptr++);
- addr->user_message = (*ptr)? string_copy(ptr) : NULL;
- while(*ptr++);
+ #ifdef EXPERIMENTAL_DSN_INFO
+ case '1': /* must arrive before A0, and applies to that addr */
+ /* Two strings: smtp_greeting and helo_response */
+ addr->smtp_greeting = string_copy(ptr);
+ while(*ptr++);
+ addr->helo_response = string_copy(ptr);
+ while(*ptr++);
+ break;
+ #endif
+
+ case '0':
+ DEBUG(D_deliver) debug_printf("A0 %s tret %d\n", addr->address, *ptr);
+ addr->transport_return = *ptr++;
+ addr->special_action = *ptr++;
+ memcpy(&addr->basic_errno, ptr, sizeof(addr->basic_errno));
+ ptr += sizeof(addr->basic_errno);
+ memcpy(&addr->more_errno, ptr, sizeof(addr->more_errno));
+ ptr += sizeof(addr->more_errno);
+ memcpy(&addr->delivery_usec, ptr, sizeof(addr->delivery_usec));
+ ptr += sizeof(addr->delivery_usec);
+ memcpy(&addr->flags, ptr, sizeof(addr->flags));
+ ptr += sizeof(addr->flags);
+ addr->message = *ptr ? string_copy(ptr) : NULL;
+ while(*ptr++);
+ addr->user_message = *ptr ? string_copy(ptr) : NULL;
+ while(*ptr++);
- /* Always two strings for host information, followed by the port number and DNSSEC mark */
+ /* Always two strings for host information, followed by the port number and DNSSEC mark */
- if (*ptr != 0)
- {
- h = store_get(sizeof(host_item));
- h->name = string_copy(ptr);
- while (*ptr++);
- h->address = string_copy(ptr);
- while(*ptr++);
- memcpy(&(h->port), ptr, sizeof(h->port));
- ptr += sizeof(h->port);
- h->dnssec = *ptr == '2' ? DS_YES
- : *ptr == '1' ? DS_NO
- : DS_UNK;
- ptr++;
- addr->host_used = h;
- }
- else ptr++;
+ if (*ptr)
+ {
+ h = store_get(sizeof(host_item));
+ h->name = string_copy(ptr);
+ while (*ptr++);
+ h->address = string_copy(ptr);
+ while(*ptr++);
+ memcpy(&h->port, ptr, sizeof(h->port));
+ ptr += sizeof(h->port);
+ h->dnssec = *ptr == '2' ? DS_YES
+ : *ptr == '1' ? DS_NO
+ : DS_UNK;
+ ptr++;
+ addr->host_used = h;
+ }
+ else ptr++;
- /* Finished with this address */
+ /* Finished with this address */
- addr = addr->next;
- break;
- }
- break;
+ addr = addr->next;
+ break;
+ }
+ break;
/* Local interface address/port */
case 'I':
- if (*ptr) sending_ip_address = string_copy(ptr);
- while (*ptr++) ;
- if (*ptr) sending_port = atoi(CS ptr);
- while (*ptr++) ;
- break;
+ if (*ptr) sending_ip_address = string_copy(ptr);
+ while (*ptr++) ;
+ if (*ptr) sending_port = atoi(CS ptr);
+ while (*ptr++) ;
+ break;
/* Z marks the logical end of the data. It is followed by '0' if
continue_transport was NULL at the end of transporting, otherwise '1'.
@@ -3620,23 +3641,23 @@ while (!done)
most normal messages it will remain NULL all the time. */
case 'Z':
- if (*ptr == '0')
- {
- continue_transport = NULL;
- continue_hostname = NULL;
- }
- done = TRUE;
- DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr);
- break;
+ if (*ptr == '0')
+ {
+ continue_transport = NULL;
+ continue_hostname = NULL;
+ }
+ done = TRUE;
+ DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr);
+ break;
/* Anything else is a disaster. */
default:
- msg = string_sprintf("malformed data (%d) read from pipe for transport "
- "process %d for transport %s", ptr[-1], pid,
- addr->transport->driver_name);
- done = TRUE;
- break;
+ msg = string_sprintf("malformed data (%d) read from pipe for transport "
+ "process %d for transport %s", ptr[-1], pid,
+ addr->transport->driver_name);
+ done = TRUE;
+ break;
}
}
@@ -3646,7 +3667,7 @@ call the function again when the process finishes. */
p->done = done;
/* If the process hadn't finished, and we haven't seen the end of the data
-or suffered a disaster, update the rest of the state, and return FALSE to
+or if we suffered a disaster, update the rest of the state, and return FALSE to
indicate "not finished". */
if (!eop && !done)
@@ -3679,6 +3700,7 @@ if (msg)
addr->transport_return = DEFER;
addr->special_action = SPECIAL_FREEZE;
addr->message = msg;
+ log_write(0, LOG_MAIN|LOG_PANIC, "Delivery status for %s: %s\n", addr->address, addr->message);
}
/* Return TRUE to indicate we have got all we need from this process, even
@@ -3898,14 +3920,12 @@ for (;;) /* Normally we do not repeat this loop */
maxpipe = 0;
FD_ZERO(&select_pipes);
for (poffset = 0; poffset < remote_max_parallel; poffset++)
- {
if (parlist[poffset].pid != 0)
{
int fd = parlist[poffset].fd;
FD_SET(fd, &select_pipes);
if (fd > maxpipe) maxpipe = fd;
}
- }
/* Stick in a 60-second timeout, just in case. */
@@ -3938,7 +3958,6 @@ for (;;) /* Normally we do not repeat this loop */
{
readycount--;
if (par_read_pipe(poffset, FALSE)) /* Finished with this pipe */
- {
for (;;) /* Loop for signals */
{
pid_t endedpid = waitpid(pid, &status, 0);
@@ -3948,7 +3967,6 @@ for (;;) /* Normally we do not repeat this loop */
"%d (errno = %d) from waitpid() for process %d",
(int)endedpid, errno, (int)pid);
}
- }
}
}
@@ -4080,47 +4098,45 @@ while (parcount > max)
}
}
-
-
-
static void
-rmt_dlv_checked_write(int fd, char id, char subid, void * buf, int size)
+rmt_dlv_checked_write(int fd, char id, char subid, void * buf, ssize_t size)
{
-uschar writebuffer[PIPE_HEADER_SIZE + BIG_BUFFER_SIZE];
-int header_length;
-int ret;
+uschar pipe_header[PIPE_HEADER_SIZE+1];
+size_t total_len = PIPE_HEADER_SIZE + size;
+
+struct iovec iov[2] = {
+ { pipe_header, PIPE_HEADER_SIZE }, /* indication about the data to expect */
+ { buf, size } /* *the* data */
+};
+
+ssize_t ret;
/* we assume that size can't get larger then BIG_BUFFER_SIZE which currently is set to 16k */
/* complain to log if someone tries with buffer sizes we can't handle*/
-if (size > 99999)
+if (size > BIG_BUFFER_SIZE-1)
{
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
- "Failed writing transport result to pipe: can't handle buffers > 99999 bytes. truncating!\n");
- size = 99999;
+ "Failed writing transport result to pipe: can't handle buffers > %d bytes. truncating!\n",
+ BIG_BUFFER_SIZE-1);
+ size = BIG_BUFFER_SIZE;
}
-/* to keep the write() atomic we build header in writebuffer and copy buf behind */
-/* two write() calls would increase the complexity of reading from pipe */
+/* Should we check that we do not write more than PIPE_BUF? What would
+that help? */
/* convert size to human readable string prepended by id and subid */
-header_length = snprintf(CS writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
-if (header_length != PIPE_HEADER_SIZE)
- {
+if (PIPE_HEADER_SIZE != snprintf(CS pipe_header, PIPE_HEADER_SIZE+1, "%c%c%05ld",
+ id, subid, (long)size))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
- writebuffer[0] = '\0';
- }
-DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%d,final:%s\n",
- id, subid, size, writebuffer);
+DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%ld,final:%s\n",
+ id, subid, (long)size, pipe_header);
-if (buf && size > 0)
- memcpy(writebuffer + PIPE_HEADER_SIZE, buf, size);
-
-size += PIPE_HEADER_SIZE;
-if ((ret = write(fd, writebuffer, size)) != size)
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed writing transport result to pipe: %s\n",
- ret == -1 ? strerror(errno) : "short write");
+if ((ret = writev(fd, iov, 2)) != total_len)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "Failed writing transport result to pipe (%ld of %ld bytes): %s",
+ (long)ret, (long)total_len, ret == -1 ? strerror(errno) : "short write");
}
/*************************************************
@@ -4436,6 +4452,23 @@ for (delivery_count = 0; addr_remote; delivery_count++)
if (tp->setup)
(void)((tp->setup)(addr->transport, addr, NULL, uid, gid, NULL));
+ /* If we have a connection still open from a verify stage (lazy-close)
+ treat it as if it is a continued connection (apart from the counter used
+ for the log line mark). */
+
+ if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+ {
+ DEBUG(D_deliver)
+ debug_printf("lazy-callout-close: have conn still open from verification\n");
+ continue_transport = cutthrough.transport;
+ continue_hostname = string_copy(cutthrough.host.name);
+ continue_host_address = string_copy(cutthrough.host.address);
+ continue_sequence = 1;
+ sending_ip_address = cutthrough.snd_ip;
+ sending_port = cutthrough.snd_port;
+ smtp_peer_options = cutthrough.peer_options;
+ }
+
/* If this is a run to continue delivery down an already-established
channel, check that this set of addresses matches the transport and
the channel. If it does not, defer the addresses. If a host list exists,
@@ -4446,14 +4479,31 @@ for (delivery_count = 0; addr_remote; delivery_count++)
if (continue_transport)
{
BOOL ok = Ustrcmp(continue_transport, tp->name) == 0;
- if (ok && addr->host_list)
+
+ /* If the transport is about to override the host list do not check
+ it here but take the cost of running the transport process to discover
+ if the continued_hostname connection is suitable. This is a layering
+ violation which is unfortunate as it requires we haul in the smtp
+ include file. */
+
+ if (ok)
{
- host_item *h;
- ok = FALSE;
- for (h = addr->host_list; h; h = h->next)
- if (Ustrcmp(h->name, continue_hostname) == 0)
-/*XXX should also check port here */
- { ok = TRUE; break; }
+ smtp_transport_options_block * ob;
+
+ if ( !( Ustrcmp(tp->info->driver_name, "smtp") == 0
+ && (ob = (smtp_transport_options_block *)tp->options_block)
+ && ob->hosts_override && ob->hosts
+ )
+ && addr->host_list
+ )
+ {
+ host_item * h;
+ ok = FALSE;
+ for (h = addr->host_list; h; h = h->next)
+ if (Ustrcmp(h->name, continue_hostname) == 0)
+ /*XXX should also check port here */
+ { ok = TRUE; break; }
+ }
}
/* Addresses not suitable; defer or queue for fallback hosts (which
@@ -4461,7 +4511,10 @@ for (delivery_count = 0; addr_remote; delivery_count++)
if (!ok)
{
- DEBUG(D_deliver) debug_printf("not suitable for continue_transport\n");
+ DEBUG(D_deliver) debug_printf("not suitable for continue_transport (%s)\n",
+ Ustrcmp(continue_transport, tp->name) != 0
+ ? string_sprintf("tpt %s vs %s", continue_transport, tp->name)
+ : string_sprintf("no host matching %s", continue_hostname));
if (serialize_key) enq_end(serialize_key);
if (addr->fallback_hosts && !fallback)
@@ -4492,9 +4545,12 @@ for (delivery_count = 0; addr_remote; delivery_count++)
/* Set a flag indicating whether there are further addresses that list
the continued host. This tells the transport to leave the channel open,
- but not to pass it to another delivery process. */
+ but not to pass it to another delivery process. We'd like to do that
+ for non-continue_transport cases too but the knowlege of which host is
+ connected to is too hard to manage. Perhaps we need a finer-grain
+ interface to the transport. */
- for (next = addr_remote; next; next = next->next)
+ for (next = addr_remote; next && !continue_more; next = next->next)
{
host_item *h;
for (h = next->host_list; h; h = h->next)
@@ -4527,11 +4583,15 @@ for (delivery_count = 0; addr_remote; delivery_count++)
that it can use either of them, though it prefers O_NONBLOCK, which
distinguishes between EOF and no-more-data. */
+/* The data appears in a timely manner and we already did a select on
+all pipes, so I do not see a reason to use non-blocking IO here
+
#ifdef O_NONBLOCK
(void)fcntl(pfd[pipe_read], F_SETFL, O_NONBLOCK);
#else
(void)fcntl(pfd[pipe_read], F_SETFL, O_NDELAY);
#endif
+*/
/* If the maximum number of subprocesses already exist, wait for a process
to finish. If we ran out of file descriptors, parmax will have been reduced
@@ -4574,10 +4634,12 @@ for (delivery_count = 0; addr_remote; delivery_count++)
search_tidyup();
+
if ((pid = fork()) == 0)
{
int fd = pfd[pipe_write];
host_item *h;
+ DEBUG(D_deliver) debug_selector |= D_pid; // hs12
/* Setting this global in the subprocess means we need never clear it */
transport_name = tp->name;
@@ -4598,7 +4660,7 @@ for (delivery_count = 0; addr_remote; delivery_count++)
predictable settings for each delivery process, so do something explicit
here rather they rely on the fixed reset in the random number function. */
- random_seed = running_in_test_harness? 42 + 2*delivery_count : 0;
+ random_seed = running_in_test_harness ? 42 + 2*delivery_count : 0;
/* Set close-on-exec on the pipe so that it doesn't get passed on to
a new process that may be forked to do another delivery down the same
@@ -4713,13 +4775,17 @@ for (delivery_count = 0; addr_remote; delivery_count++)
if (!addr->peerdn)
*ptr++ = 0;
else
- {
- ptr += sprintf(CS ptr, "%.512s", addr->peerdn);
- ptr++;
- }
+ ptr += sprintf(CS ptr, "%.512s", addr->peerdn) + 1;
rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
}
+ else if (continue_proxy_cipher)
+ {
+ ptr = big_buffer + sprintf(CS big_buffer, "%.128s", continue_proxy_cipher) + 1;
+ *ptr++ = 0;
+ rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
+ }
+
if (addr->peercert)
{
ptr = big_buffer;
@@ -4764,16 +4830,18 @@ for (delivery_count = 0; addr_remote; delivery_count++)
}
#ifndef DISABLE_PRDR
- if (addr->flags & af_prdr_used)
+ if (testflag(addr, af_prdr_used))
rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
#endif
- if (addr->flags & af_chunking_used)
+ if (testflag(addr, af_chunking_used))
rmt_dlv_checked_write(fd, 'K', '0', NULL, 0);
+ if (testflag(addr, af_tcp_fastopen))
+ rmt_dlv_checked_write(fd, 'T', '0', NULL, 0);
+
memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
- DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware);
/* Retry information: for most success cases this will be null. */
@@ -4781,9 +4849,9 @@ for (delivery_count = 0; addr_remote; delivery_count++)
{
sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
- memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
+ memcpy(ptr, &r->basic_errno, sizeof(r->basic_errno));
ptr += sizeof(r->basic_errno);
- memcpy(ptr, &(r->more_errno), sizeof(r->more_errno));
+ memcpy(ptr, &r->more_errno, sizeof(r->more_errno));
ptr += sizeof(r->more_errno);
if (!r->message) *ptr++ = 0; else
{
@@ -4832,11 +4900,13 @@ for (delivery_count = 0; addr_remote; delivery_count++)
sprintf(CS big_buffer, "%c%c", addr->transport_return, addr->special_action);
ptr = big_buffer + 2;
- memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
+ memcpy(ptr, &addr->basic_errno, sizeof(addr->basic_errno));
ptr += sizeof(addr->basic_errno);
- memcpy(ptr, &(addr->more_errno), sizeof(addr->more_errno));
+ memcpy(ptr, &addr->more_errno, sizeof(addr->more_errno));
ptr += sizeof(addr->more_errno);
- memcpy(ptr, &(addr->flags), sizeof(addr->flags));
+ memcpy(ptr, &addr->delivery_usec, sizeof(addr->delivery_usec));
+ ptr += sizeof(addr->delivery_usec);
+ memcpy(ptr, &addr->flags, sizeof(addr->flags));
ptr += sizeof(addr->flags);
if (!addr->message) *ptr++ = 0; else
@@ -4849,7 +4919,7 @@ for (delivery_count = 0; addr_remote; delivery_count++)
{
ptr += sprintf(CS ptr, "%.256s", addr->host_used->name) + 1;
ptr += sprintf(CS ptr, "%.64s", addr->host_used->address) + 1;
- memcpy(ptr, &(addr->host_used->port), sizeof(addr->host_used->port));
+ memcpy(ptr, &addr->host_used->port, sizeof(addr->host_used->port));
ptr += sizeof(addr->host_used->port);
/* DNS lookup status */
@@ -4888,9 +4958,22 @@ for (delivery_count = 0; addr_remote; delivery_count++)
(void)close(pfd[pipe_write]);
+ /* If we have a connection still open from a verify stage (lazy-close)
+ release its TLS library context (if any) as responsibility was passed to
+ the delivery child process. */
+
+ if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+ {
+#ifdef SUPPORT_TLS
+ tls_close(FALSE, FALSE);
+#endif
+ (void) close(cutthrough.fd);
+ release_cutthrough_connection(US"passed to transport proc");
+ }
+
/* Fork failed; defer with error message */
- if (pid < 0)
+ if (pid == -1)
{
(void)close(pfd[pipe_read]);
panicmsg = string_sprintf("fork failed for remote delivery to %s: %s",
@@ -5512,14 +5595,15 @@ give up; if the message has been around for sufficiently long, remove it. */
if (rc != spool_read_hdrerror)
{
- received_time = 0;
+ received_time.tv_sec = received_time.tv_usec = 0;
+ /*XXX subsec precision?*/
for (i = 0; i < 6; i++)
- received_time = received_time * BASE_62 + tab62[id[i] - '0'];
+ received_time.tv_sec = received_time.tv_sec * BASE_62 + tab62[id[i] - '0'];
}
/* If we've had this malformed message too long, sling it. */
- if (now - received_time > keep_malformed)
+ if (now - received_time.tv_sec > keep_malformed)
{
Uunlink(spool_fname(US"msglog", message_subdir, id, US""));
Uunlink(spool_fname(US"input", message_subdir, id, US"-D"));
@@ -5914,11 +5998,11 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
uschar *type;
p->uid = uid;
p->gid = gid;
- setflag(p, af_uid_set |
- af_gid_set |
- af_allow_file |
- af_allow_pipe |
- af_allow_reply);
+ setflag(p, af_uid_set);
+ setflag(p, af_gid_set);
+ setflag(p, af_allow_file);
+ setflag(p, af_allow_pipe);
+ setflag(p, af_allow_reply);
/* Find the name of the system filter's appropriate pfr transport */
@@ -6020,9 +6104,7 @@ spool if the message is deferred, and in any case there are casing
complications for local addresses. */
if (process_recipients != RECIP_IGNORE)
- {
for (i = 0; i < recipients_count; i++)
- {
if (!tree_search(tree_nonrecipients, recipients_list[i].address))
{
recipient_item *r = recipients_list + i;
@@ -6138,8 +6220,6 @@ if (process_recipients != RECIP_IGNORE)
}
#endif
}
- }
- }
DEBUG(D_deliver)
{
@@ -6204,10 +6284,8 @@ while (addr_new) /* Loop until all addresses dealt with */
not exist. In both cases, dbm_file is NULL. */
if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
- {
DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
debug_printf("no retry data available\n");
- }
/* Scan the current batch of new addresses, to handle pipes, files and
autoreplies, and determine which others are ready for routing. */
@@ -6243,8 +6321,8 @@ while (addr_new) /* Loop until all addresses dealt with */
addr->local_part = addr->address;
addr->message =
US"filter autoreply generated syntactically invalid recipient";
- setflag(addr, af_ignore_error);
- (void)post_process_one(addr, FAIL, LOG_MAIN, DTYPE_ROUTER, 0);
+ addr->prop.ignore_error = TRUE;
+ (void) post_process_one(addr, FAIL, LOG_MAIN, DTYPE_ROUTER, 0);
continue; /* with the next new address */
}
@@ -6599,7 +6677,6 @@ while (addr_new) /* Loop until all addresses dealt with */
if ((rc = match_isinlist(addr->domain, (const uschar **)&queue_domains, 0,
&domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
!= OK)
- {
if (rc == DEFER)
{
addr->basic_errno = ERRNO_LISTDEFER;
@@ -6611,7 +6688,6 @@ while (addr_new) /* Loop until all addresses dealt with */
addr->next = okaddr;
okaddr = addr;
}
- }
else
{
addr->basic_errno = ERRNO_QUEUE_DOMAIN;
@@ -6646,7 +6722,7 @@ while (addr_new) /* Loop until all addresses dealt with */
&addr_succeed, v_none)) == DEFER)
retry_add_item(addr,
addr->router->retry_use_local_part
- ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
+ ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
: string_sprintf("R:%s", addr->domain),
0);
@@ -6740,15 +6816,14 @@ while (addr_new) /* Loop until all addresses dealt with */
addr2->host_list = addr->host_list;
addr2->fallback_hosts = addr->fallback_hosts;
addr2->prop.errors_address = addr->prop.errors_address;
- copyflag(addr2, addr, af_hide_child | af_local_host_removed);
+ copyflag(addr2, addr, af_hide_child);
+ copyflag(addr2, addr, af_local_host_removed);
DEBUG(D_deliver|D_route)
- {
debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
"routing %s\n"
"Routing for %s copied from %s\n",
addr2->address, addr2->address, addr->address);
- }
}
}
} /* Continue with routing the next address. */
@@ -6910,7 +6985,7 @@ if (addr_local || addr_remote)
if (journal_fd < 0)
{
uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
-
+
if ((journal_fd = Uopen(fname,
#ifdef O_CLOEXEC
O_CLOEXEC |
@@ -7038,6 +7113,7 @@ phase, to minimize cases of half-done things. */
DEBUG(D_deliver)
debug_printf(">>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>\n");
+cancel_cutthrough_connection(TRUE, US"deliveries are done");
/* Root privilege is no longer needed */
@@ -7174,7 +7250,7 @@ if (addr_senddsn)
FILE *f = fdopen(fd, "wb");
/* header only as required by RFC. only failure DSN needs to honor RET=FULL */
uschar * bound;
- transport_ctx tctx = {0};
+ transport_ctx tctx = {{0}};
DEBUG(D_deliver)
debug_printf("sending error message to: %s\n", sender_address);
@@ -7254,8 +7330,9 @@ if (addr_senddsn)
/* Write the original email out */
+ tctx.u.fd = fileno(f);
tctx.options = topt_add_return_path | topt_no_body;
- transport_write_message(fileno(f), &tctx, 0);
+ transport_write_message(&tctx, 0);
fflush(f);
fprintf(f,"\n--%s--\n", bound);
@@ -7311,19 +7388,18 @@ while (addr_failed)
if (sender_address[0] == 0 && !addr_failed->prop.errors_address)
{
if ( !testflag(addr_failed, af_retry_timedout)
- && !testflag(addr_failed, af_ignore_error))
- {
+ && !addr_failed->prop.ignore_error)
log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message "
"failure is neither frozen nor ignored (it's been ignored)");
- }
- setflag(addr_failed, af_ignore_error);
+
+ addr_failed->prop.ignore_error = TRUE;
}
/* If the first address on the list has af_ignore_error set, just remove
it from the list, throw away any saved message file, log it, and
mark the recipient done. */
- if ( testflag(addr_failed, af_ignore_error)
+ if ( addr_failed->prop.ignore_error
|| ( addr_failed->dsn_flags & rf_dsnflags
&& (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure
) )
@@ -7711,14 +7787,15 @@ wording. */
transport_filter_argv = NULL; /* Just in case */
return_path = sender_address; /* In case not previously set */
{ /* Dummy transport for headers add */
- transport_ctx tctx = {0};
+ transport_ctx tctx = {{0}};
transport_instance tb = {0};
+ tctx.u.fd = fileno(f);
tctx.tblock = &tb;
tctx.options = topt;
tb.add_headers = dsnnotifyhdr;
- transport_write_message(fileno(f), &tctx, 0);
+ transport_write_message(&tctx, 0);
}
fflush(f);
@@ -7750,7 +7827,7 @@ wording. */
if (rc != 0)
{
uschar *s = US"";
- if (now - received_time < retry_maximum_timeout && !addr_defer)
+ if (now - received_time.tv_sec < retry_maximum_timeout && !addr_defer)
{
addr_defer = (address_item *)(+1);
deliver_freeze = TRUE;
@@ -7836,7 +7913,7 @@ if (!addr_defer)
if (LOGGING(queue_time_overall))
log_write(0, LOG_MAIN, "Completed QT=%s",
- readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
+ string_timesince(&received_time));
else
log_write(0, LOG_MAIN, "Completed");
@@ -7974,7 +8051,7 @@ else if (addr_defer != (address_item *)(+1))
{
int count;
int show_time;
- int queue_time = time(NULL) - received_time;
+ int queue_time = time(NULL) - received_time.tv_sec;
/* When running in the test harness, there's an option that allows us to
fudge this time so as to get repeatability of the tests. Take the first
@@ -8032,7 +8109,7 @@ else if (addr_defer != (address_item *)(+1))
FILE *wmf = NULL;
FILE *f = fdopen(fd, "wb");
uschar * bound;
- transport_ctx tctx = {0};
+ transport_ctx tctx = {{0}};
if (warn_message_file)
if (!(wmf = Ufopen(warn_message_file, "rb")))
@@ -8179,12 +8256,13 @@ else if (addr_defer != (address_item *)(+1))
fflush(f);
/* header only as required by RFC. only failure DSN needs to honor RET=FULL */
+ tctx.u.fd = fileno(f);
tctx.options = topt_add_return_path | topt_no_body;
transport_filter_argv = NULL; /* Just in case */
return_path = sender_address; /* In case not previously set */
/* Write the original email out */
- transport_write_message(fileno(f), &tctx, 0);
+ transport_write_message(&tctx, 0);
fflush(f);
fprintf(f,"\n--%s--\n", bound);
@@ -8414,6 +8492,72 @@ deliver_datafile = -1;
return new_sender_address;
}
+
+
+void
+delivery_re_exec(int exec_type)
+{
+uschar * where;
+
+if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+ {
+ int pfd[2], channel_fd = cutthrough.fd, pid;
+
+ smtp_peer_options = cutthrough.peer_options;
+ continue_sequence = 0;
+
+#ifdef SUPPORT_TLS
+ if (cutthrough.is_tls)
+ {
+ smtp_peer_options |= OPTION_TLS;
+ sending_ip_address = cutthrough.snd_ip;
+ sending_port = cutthrough.snd_port;
+
+ where = US"socketpair";
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) != 0)
+ goto fail;
+
+ where = US"fork";
+ if ((pid = fork()) < 0)
+ goto fail;
+
+ else if (pid == 0) /* child: fork again to totally disconnect */
+ {
+ close(pfd[1]);
+ if ((pid = fork()))
+ _exit(pid ? EXIT_FAILURE : EXIT_SUCCESS);
+ smtp_proxy_tls(big_buffer, big_buffer_size, pfd[0], 5*60);
+ exim_exit(0);
+ }
+
+ close(pfd[0]);
+ waitpid(pid, NULL, 0);
+ (void) close(channel_fd); /* release the client socket */
+ channel_fd = pfd[1];
+ }
+#endif
+
+ transport_do_pass_socket(cutthrough.transport, cutthrough.host.name,
+ cutthrough.host.address, message_id, channel_fd);
+ }
+else
+ {
+ cancel_cutthrough_connection(TRUE, US"non-continued delivery");
+ (void) child_exec_exim(exec_type, FALSE, NULL, FALSE, 2, US"-Mc", message_id);
+ }
+return; /* compiler quietening; control does not reach here. */
+
+fail:
+ log_write(0,
+ LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),
+ "delivery re-exec %s failed: %s", where, strerror(errno));
+
+ /* Get here if exec_type == CEE_EXEC_EXIT.
+ Note: this must be _exit(), not exit(). */
+
+ _exit(EX_EXECFAILED);
+}
+
/* vi: aw ai sw=2
*/
/* End of deliver.c */
diff --git a/src/src/dkim.c b/src/src/dkim.c
index f51021443..cd8a16ae6 100644
--- a/src/src/dkim.c
+++ b/src/src/dkim.c
@@ -20,6 +20,12 @@ pdkim_signature *dkim_signatures = NULL;
pdkim_signature *dkim_cur_sig = NULL;
static const uschar * dkim_collect_error = NULL;
+
+
+/*XXX the caller only uses the first record if we return multiple.
+Could we hand back an allocated string?
+*/
+
static int
dkim_exim_query_dns_txt(char *name, char *answer)
{
@@ -48,7 +54,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
uschar len = rr->data[rr_offset++];
snprintf(answer + answer_offset,
PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
- "%.*s", (int)len, (char *) (rr->data + rr_offset));
+ "%.*s", (int)len, CS (rr->data + rr_offset));
rr_offset += len;
answer_offset += len;
if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
@@ -104,7 +110,7 @@ int rc;
store_pool = POOL_PERM;
if ( dkim_collect_input
- && (rc = pdkim_feed(dkim_verify_ctx, CS data, len)) != PDKIM_OK)
+ && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
{
dkim_collect_error = pdkim_errstr(rc);
log_write(0, LOG_MAIN,
@@ -164,17 +170,15 @@ for (sig = dkim_signatures; sig; sig = sig->next)
logmsg = string_append(logmsg, &size, &ptr, 7,
" c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
"/", sig->canon_body == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
- " a=", sig->algo == PDKIM_ALGO_RSA_SHA256
- ? "rsa-sha256"
- : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
+ " a=", dkim_sig_to_a_tag(sig),
string_sprintf(" b=%d",
(int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
- if ((s= sig->identity)) string_append(logmsg, &size, &ptr, 2, " i=", s);
- if (sig->created > 0) string_append(logmsg, &size, &ptr, 1,
+ if ((s= sig->identity)) logmsg = string_append(logmsg, &size, &ptr, 2, " i=", s);
+ if (sig->created > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
string_sprintf(" t=%lu", sig->created));
- if (sig->expires > 0) string_append(logmsg, &size, &ptr, 1,
+ if (sig->expires > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
string_sprintf(" x=%lu", sig->expires));
- if (sig->bodylength > -1) string_append(logmsg, &size, &ptr, 1,
+ if (sig->bodylength > -1) logmsg = string_append(logmsg, &size, &ptr, 1,
string_sprintf(" l=%lu", sig->bodylength));
switch (sig->verify_status)
@@ -251,10 +255,12 @@ for (sig = dkim_signatures; sig; sig = sig->next)
/* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
if (sig->domain)
- dkim_signers = string_append_listele(dkim_signers, ':', sig->domain);
+ dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
+ &dkim_signers_ptr, ':', sig->domain);
if (sig->identity)
- dkim_signers = string_append_listele(dkim_signers, ':', sig->identity);
+ dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
+ &dkim_signers_ptr, ':', sig->identity);
/* Process next signature */
}
@@ -336,12 +342,7 @@ if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
switch (what)
{
case DKIM_ALGO:
- switch (dkim_cur_sig->algo)
- {
- case PDKIM_ALGO_RSA_SHA1: return US"rsa-sha1";
- case PDKIM_ALGO_RSA_SHA256:
- default: return US"rsa-sha256";
- }
+ return dkim_sig_to_a_tag(dkim_cur_sig);
case DKIM_BODYLENGTH:
return dkim_cur_sig->bodylength >= 0
@@ -448,222 +449,239 @@ switch (what)
}
-uschar *
-dkim_exim_sign(int dkim_fd, struct ob_dkim * dkim, const uschar ** errstr)
+/* Generate signatures for the given file, returning a string.
+If a prefix is given, prepend it to the file for the calculations.
+*/
+
+blob *
+dkim_exim_sign(int fd, off_t off, uschar * prefix,
+ struct ob_dkim * dkim, const uschar ** errstr)
{
const uschar * dkim_domain;
int sep = 0;
-uschar *seen_items = NULL;
-int seen_items_size = 0;
-int seen_items_offset = 0;
-uschar itembuf[256];
-uschar *dkim_canon_expanded;
-uschar *dkim_sign_headers_expanded;
-uschar *dkim_private_key_expanded;
-pdkim_ctx *ctx = NULL;
-uschar *rc = NULL;
-uschar *sigbuf = NULL;
+uschar * seen_doms = NULL;
+int seen_doms_size = 0;
+int seen_doms_offset = 0;
+pdkim_ctx ctx;
+pdkim_signature * sig;
+blob * sigbuf = NULL;
int sigsize = 0;
-int sigptr = 0;
-pdkim_signature *signature;
-int pdkim_canon;
int pdkim_rc;
int sread;
-char buf[4096];
+uschar buf[4096];
int save_errno = 0;
int old_pool = store_pool;
+uschar * errwhen;
store_pool = POOL_MAIN;
+pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
+
if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
- {
/* expansion error, do not send message. */
- log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
- "dkim_domain: %s", expand_string_message);
- goto bad;
- }
+ { errwhen = US"dkim_domain"; goto expand_bad; }
/* Set $dkim_domain expansion variable to each unique domain in list. */
-while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
- itembuf, sizeof(itembuf))))
+while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
{
- if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
+ const uschar * dkim_sel;
+ int sel_sep = 0;
+
+ if (dkim_signing_domain[0] == '\0')
continue;
/* Only sign once for each domain, no matter how often it
appears in the expanded list. */
- if (seen_items)
- {
- const uschar *seen_items_list = seen_items;
- if (match_isinlist(dkim_signing_domain,
- &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
- NULL) == OK)
- continue;
-
- seen_items =
- string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
- }
+ if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
+ 0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
+ continue;
- seen_items =
- string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
- dkim_signing_domain);
- seen_items[seen_items_offset] = '\0';
+ seen_doms = string_append_listele(seen_doms, &seen_doms_size,
+ &seen_doms_offset, ':', dkim_signing_domain);
- /* Set up $dkim_selector expansion variable. */
+ /* Set $dkim_selector expansion variable to each selector in list,
+ for this domain. */
+ if (!(dkim_sel = expand_string(dkim->dkim_selector)))
if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
- {
- log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
- "dkim_selector: %s", expand_string_message);
- goto bad;
- }
-
- /* Get canonicalization to use */
-
- dkim_canon_expanded = dkim->dkim_canon
- ? expand_string(dkim->dkim_canon) : US"relaxed";
- if (!dkim_canon_expanded)
- {
- /* expansion error, do not send message. */
- log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
- "dkim_canon: %s", expand_string_message);
- goto bad;
- }
+ { errwhen = US"dkim_selector"; goto expand_bad; }
- if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
- pdkim_canon = PDKIM_CANON_RELAXED;
- else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
- pdkim_canon = PDKIM_CANON_SIMPLE;
- else
+ while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
+ NULL, 0)))
{
- log_write(0, LOG_MAIN,
- "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
- dkim_canon_expanded);
- pdkim_canon = PDKIM_CANON_RELAXED;
- }
-
- dkim_sign_headers_expanded = NULL;
- if (dkim->dkim_sign_headers)
- if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
+ uschar * dkim_canon_expanded;
+ int pdkim_canon;
+ uschar * dkim_sign_headers_expanded = NULL;
+ uschar * dkim_private_key_expanded;
+ uschar * dkim_hash_expanded;
+ uschar * dkim_identity_expanded = NULL;
+
+ /* Get canonicalization to use */
+
+ dkim_canon_expanded = dkim->dkim_canon
+ ? expand_string(dkim->dkim_canon) : US"relaxed";
+ if (!dkim_canon_expanded) /* expansion error, do not send message. */
+ { errwhen = US"dkim_canon"; goto expand_bad; }
+
+ if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
+ pdkim_canon = PDKIM_CANON_RELAXED;
+ else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
+ pdkim_canon = PDKIM_CANON_SIMPLE;
+ else
{
- log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
- "dkim_sign_headers: %s", expand_string_message);
- goto bad;
+ log_write(0, LOG_MAIN,
+ "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
+ dkim_canon_expanded);
+ pdkim_canon = PDKIM_CANON_RELAXED;
}
- /* else pass NULL, which means default header list */
- /* Get private key to use. */
+ if ( dkim->dkim_sign_headers
+ && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
+ { errwhen = US"dkim_sign_header"; goto expand_bad; }
+ /* else pass NULL, which means default header list */
- if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
- {
- log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
- "dkim_private_key: %s", expand_string_message);
- goto bad;
- }
+ /* Get private key to use. */
- if ( Ustrlen(dkim_private_key_expanded) == 0
- || Ustrcmp(dkim_private_key_expanded, "0") == 0
- || Ustrcmp(dkim_private_key_expanded, "false") == 0
- )
- continue; /* don't sign, but no error */
+ if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
+ { errwhen = US"dkim_private_key"; goto expand_bad; }
- if (dkim_private_key_expanded[0] == '/')
- {
- int privkey_fd, off = 0, len;
+ if ( Ustrlen(dkim_private_key_expanded) == 0
+ || Ustrcmp(dkim_private_key_expanded, "0") == 0
+ || Ustrcmp(dkim_private_key_expanded, "false") == 0
+ )
+ continue; /* don't sign, but no error */
- /* Looks like a filename, load the private key. */
+ if (dkim_private_key_expanded[0] == '/')
+ {
+ int privkey_fd, off = 0, len;
- memset(big_buffer, 0, big_buffer_size);
+ /* Looks like a filename, load the private key. */
- if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
- {
- log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
- "private key file for reading: %s",
- dkim_private_key_expanded);
- goto bad;
- }
+ memset(big_buffer, 0, big_buffer_size);
- do
- {
- if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
+ if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
{
- (void) close(privkey_fd);
- log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
+ log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
+ "private key file for reading: %s",
dkim_private_key_expanded);
goto bad;
}
- off += len;
+
+ do
+ {
+ if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
+ {
+ (void) close(privkey_fd);
+ log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
+ dkim_private_key_expanded);
+ goto bad;
+ }
+ off += len;
+ }
+ while (len > 0);
+
+ (void) close(privkey_fd);
+ big_buffer[off] = '\0';
+ dkim_private_key_expanded = big_buffer;
}
- while (len > 0);
- (void) close(privkey_fd);
- big_buffer[off] = '\0';
- dkim_private_key_expanded = big_buffer;
- }
+ if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
+ { errwhen = US"dkim_hash"; goto expand_bad; }
- if (!(ctx = pdkim_init_sign(CS dkim_signing_domain,
- CS dkim_signing_selector,
- CS dkim_private_key_expanded,
- PDKIM_ALGO_RSA_SHA256,
- dkim->dot_stuffed,
- &dkim_exim_query_dns_txt,
- errstr
- )))
- goto bad;
- dkim_private_key_expanded[0] = '\0';
- pdkim_set_optional(ctx,
- CS dkim_sign_headers_expanded,
- NULL,
- pdkim_canon,
- pdkim_canon, -1, 0, 0);
-
- lseek(dkim_fd, 0, SEEK_SET);
-
- while ((sread = read(dkim_fd, &buf, sizeof(buf))) > 0)
- if ((pdkim_rc = pdkim_feed(ctx, buf, sread)) != PDKIM_OK)
- goto pk_bad;
+ if (dkim->dkim_identity)
+ if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
+ { errwhen = US"dkim_identity"; goto expand_bad; }
+ else if (!*dkim_identity_expanded)
+ dkim_identity_expanded = NULL;
- /* Handle failed read above. */
- if (sread == -1)
- {
- debug_printf("DKIM: Error reading -K file.\n");
- save_errno = errno;
- goto bad;
+ /*XXX so we currently nail signing to RSA + this hash.
+ Need to extract algo from privkey and check for disallowed combos. */
+
+ if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
+ dkim_signing_selector,
+ dkim_private_key_expanded,
+ dkim_hash_expanded,
+ errstr
+ )))
+ goto bad;
+ dkim_private_key_expanded[0] = '\0';
+
+ pdkim_set_optional(sig,
+ CS dkim_sign_headers_expanded,
+ dkim_identity_expanded,
+ pdkim_canon,
+ pdkim_canon, -1, 0, 0);
+
+ if (!ctx.sig) /* link sig to context chain */
+ ctx.sig = sig;
+ else
+ {
+ pdkim_signature * n = ctx.sig;
+ while (n->next) n = n->next;
+ n->next = sig;
+ }
}
+ }
- if ((pdkim_rc = pdkim_feed_finish(ctx, &signature, errstr)) != PDKIM_OK)
- goto pk_bad;
+if (prefix)
+ pdkim_feed(&ctx, prefix, Ustrlen(prefix));
- sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
- US signature->signature_header, US"\r\n");
+if (lseek(fd, off, SEEK_SET) < 0)
+ sread = -1;
+else
+ while ((sread = read(fd, &buf, sizeof(buf))) > 0)
+ if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
+ goto pk_bad;
- pdkim_free_ctx(ctx);
- ctx = NULL;
+/* Handle failed read above. */
+if (sread == -1)
+ {
+ debug_printf("DKIM: Error reading -K file.\n");
+ save_errno = errno;
+ goto bad;
}
-if (sigbuf)
+/* Build string of headers, one per signature */
+
+if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
+ goto pk_bad;
+
+sigbuf = store_get(sizeof(blob));
+sigbuf->data = NULL;
+sigbuf->len = 0;
+
+while (sig)
{
- sigbuf[sigptr] = '\0';
- rc = sigbuf;
+ int len = sigbuf->len;
+ sigbuf->data = string_append(sigbuf->data, &sigsize, &len, 2,
+ US sig->signature_header, US"\r\n");
+ sigbuf->len = len;
+ sig = sig->next;
}
+
+if (sigbuf->data)
+ sigbuf->data[sigbuf->len] = '\0';
else
- rc = US"";
+ sigbuf->data = US"";
CLEANUP:
- if (ctx)
- pdkim_free_ctx(ctx);
store_pool = old_pool;
errno = save_errno;
- return rc;
+ return sigbuf;
pk_bad:
log_write(0, LOG_MAIN|LOG_PANIC,
"DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
bad:
- rc = NULL;
+ sigbuf = NULL;
goto CLEANUP;
+
+expand_bad:
+ log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
+ errwhen, expand_string_message);
+ goto bad;
}
#endif
diff --git a/src/src/dkim.h b/src/src/dkim.h
index bfdc7d42b..a3419db42 100644
--- a/src/src/dkim.h
+++ b/src/src/dkim.h
@@ -6,7 +6,7 @@
/* See the file NOTICE for conditions of use and distribution. */
void dkim_exim_init(void);
-uschar *dkim_exim_sign(int, struct ob_dkim *, const uschar **);
+blob * dkim_exim_sign(int, off_t, uschar *, struct ob_dkim *, const uschar **);
void dkim_exim_verify_init(BOOL);
void dkim_exim_verify_feed(uschar *, int);
void dkim_exim_verify_finish(void);
diff --git a/src/src/dkim_transport.c b/src/src/dkim_transport.c
new file mode 100644
index 000000000..85a73dcae
--- /dev/null
+++ b/src/src/dkim_transport.c
@@ -0,0 +1,365 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Transport shim for dkim signing */
+
+
+#include "exim.h"
+
+#ifndef DISABLE_DKIM /* rest of file */
+
+
+static BOOL
+dkt_sign_fail(struct ob_dkim * dkim, int * errp)
+{
+if (dkim->dkim_strict)
+ {
+ uschar * dkim_strict_result = expand_string(dkim->dkim_strict);
+
+ if (dkim_strict_result)
+ if ( (strcmpic(dkim->dkim_strict, US"1") == 0) ||
+ (strcmpic(dkim->dkim_strict, US"true") == 0) )
+ {
+ /* Set errno to something halfway meaningful */
+ *errp = EACCES;
+ log_write(0, LOG_MAIN, "DKIM: message could not be signed,"
+ " and dkim_strict is set. Deferring message delivery.");
+ return FALSE;
+ }
+ }
+return TRUE;
+}
+
+/* Send the file at in_fd down the output fd */
+
+static BOOL
+dkt_send_file(int out_fd, int in_fd, off_t off, size_t size)
+{
+DEBUG(D_transport) debug_printf("send file fd=%d size=%u\n", out_fd, (unsigned)(size - off));
+
+/*XXX should implement timeout, like transport_write_block_fd() ? */
+
+#ifdef OS_SENDFILE
+/* We can use sendfile() to shove the file contents
+ to the socket. However only if we don't use TLS,
+ as then there's another layer of indirection
+ before the data finally hits the socket. */
+if (tls_out.active != out_fd)
+ {
+ ssize_t copied = 0;
+
+ while(copied >= 0 && off < size)
+ copied = os_sendfile(out_fd, in_fd, &off, size - off);
+ if (copied < 0)
+ return FALSE;
+ }
+else
+
+#endif
+
+ {
+ int sread, wwritten;
+
+ /* Rewind file */
+ if (lseek(in_fd, off, SEEK_SET) < 0) return FALSE;
+
+ /* Send file down the original fd */
+ while((sread = read(in_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) > 0)
+ {
+ uschar * p = deliver_out_buffer;
+ /* write the chunk */
+
+ while (sread)
+ {
+#ifdef SUPPORT_TLS
+ wwritten = tls_out.active == out_fd
+ ? tls_write(FALSE, p, sread, FALSE)
+ : write(out_fd, CS p, sread);
+#else
+ wwritten = write(out_fd, CS p, sread);
+#endif
+ if (wwritten == -1)
+ return FALSE;
+ p += wwritten;
+ sread -= wwritten;
+ }
+ }
+
+ if (sread == -1)
+ return FALSE;
+ }
+
+return TRUE;
+}
+
+
+
+
+/* This function is a wrapper around transport_write_message().
+ It is only called from the smtp transport if DKIM or Domainkeys support
+ is active and no transport filter is to be used.
+
+Arguments:
+ As for transport_write_message() in transort.c, with additional arguments
+ for DKIM.
+
+Returns: TRUE on success; FALSE (with errno) for any failure
+*/
+
+static BOOL
+dkt_direct(transport_ctx * tctx, struct ob_dkim * dkim,
+ const uschar ** err)
+{
+int save_fd = tctx->u.fd;
+int save_options = tctx->options;
+BOOL save_wireformat = spool_file_wireformat;
+uschar * hdrs;
+blob * dkim_signature;
+int hsize;
+const uschar * errstr;
+BOOL rc;
+
+DEBUG(D_transport) debug_printf("dkim signing direct-mode\n");
+
+/* Get headers in string for signing and transmission. Do CRLF
+and dotstuffing (but no body nor dot-termination) */
+
+tctx->u.msg = NULL;
+tctx->options = tctx->options & ~(topt_end_dot | topt_use_bdat)
+ | topt_output_string | topt_no_body;
+
+rc = transport_write_message(tctx, 0);
+hdrs = tctx->u.msg;
+hdrs[hsize = tctx->msg_ptr] = '\0';
+
+tctx->u.fd = save_fd;
+tctx->options = save_options;
+if (!rc) return FALSE;
+
+/* Get signatures for headers plus spool data file */
+
+dkim->dot_stuffed = !!(save_options & topt_end_dot);
+
+if (!(dkim_signature = dkim_exim_sign(deliver_datafile, SPOOL_DATA_START_OFFSET,
+ hdrs, dkim, &errstr)))
+ if (!(rc = dkt_sign_fail(dkim, &errno)))
+ {
+ *err = errstr;
+ return FALSE;
+ }
+
+/* Write the signature and headers into the deliver-out-buffer. This should
+mean they go out in the same packet as the MAIL, RCPT and (first) BDAT commands
+(transport_write_message() sizes the BDAT for the buffered amount) - for short
+messages, the BDAT LAST command. We want no dotstuffing expansion here, it
+having already been done - but we have to say we want CRLF output format, and
+temporarily set the marker for possible already-CRLF input. */
+
+tctx->options &= ~topt_escape_headers;
+spool_file_wireformat = TRUE;
+transport_write_reset(0);
+if ( ( dkim_signature
+ && dkim_signature->len > 0
+ && !write_chunk(tctx, dkim_signature->data, dkim_signature->len)
+ )
+ || !write_chunk(tctx, hdrs, hsize)
+ )
+ return FALSE;
+
+spool_file_wireformat = save_wireformat;
+tctx->options = save_options | topt_no_headers | topt_continuation;
+
+if (!(transport_write_message(tctx, 0)))
+ return FALSE;
+
+tctx->options = save_options;
+return TRUE;
+}
+
+
+/* This function is a wrapper around transport_write_message().
+ It is only called from the smtp transport if DKIM or Domainkeys support
+ is active and a transport filter is to be used. The function sets up a
+ replacement fd into a -K file, then calls the normal function. This way, the
+ exact bits that exim would have put "on the wire" will end up in the file
+ (except for TLS encapsulation, which is the very very last thing). When we
+ are done signing the file, send the signed message down the original fd (or
+ TLS fd).
+
+Arguments:
+ As for transport_write_message() in transort.c, with additional arguments
+ for DKIM.
+
+Returns: TRUE on success; FALSE (with errno) for any failure
+*/
+
+static BOOL
+dkt_via_kfile(transport_ctx * tctx, struct ob_dkim * dkim, const uschar ** err)
+{
+int dkim_fd;
+int save_errno = 0;
+BOOL rc;
+uschar * dkim_spool_name;
+blob * dkim_signature;
+int options, dlen;
+off_t k_file_size;
+const uschar * errstr;
+
+dkim_spool_name = spool_fname(US"input", message_subdir, message_id,
+ string_sprintf("-%d-K", (int)getpid()));
+
+DEBUG(D_transport) debug_printf("dkim signing via file %s\n", dkim_spool_name);
+
+if ((dkim_fd = Uopen(dkim_spool_name, O_RDWR|O_CREAT|O_TRUNC, SPOOL_MODE)) < 0)
+ {
+ /* Can't create spool file. Ugh. */
+ rc = FALSE;
+ save_errno = errno;
+ *err = string_sprintf("dkim spoolfile create: %s", strerror(errno));
+ goto CLEANUP;
+ }
+
+/* Call transport utility function to write the -K file; does the CRLF expansion
+(but, in the CHUNKING case, neither dot-stuffing nor dot-termination). */
+
+ {
+ int save_fd = tctx->u.fd;
+ tctx->u.fd = dkim_fd;
+ options = tctx->options;
+ tctx->options &= ~topt_use_bdat;
+
+ rc = transport_write_message(tctx, 0);
+
+ tctx->u.fd = save_fd;
+ tctx->options = options;
+ }
+
+/* Save error state. We must clean up before returning. */
+if (!rc)
+ {
+ save_errno = errno;
+ goto CLEANUP;
+ }
+
+/* Feed the file to the goats^W DKIM lib */
+
+dkim->dot_stuffed = !!(options & topt_end_dot);
+if (!(dkim_signature = dkim_exim_sign(dkim_fd, 0, NULL, dkim, &errstr)))
+ {
+ dlen = 0;
+ if (!(rc = dkt_sign_fail(dkim, &save_errno)))
+ {
+ *err = errstr;
+ goto CLEANUP;
+ }
+ }
+else
+ dlen = dkim_signature->len;
+
+#ifndef OS_SENDFILE
+if (options & topt_use_bdat)
+#endif
+ if ((k_file_size = lseek(dkim_fd, 0, SEEK_END)) < 0)
+ {
+ *err = string_sprintf("dkim spoolfile seek: %s", strerror(errno));
+ goto CLEANUP;
+ }
+
+if (options & topt_use_bdat)
+ {
+ /* On big messages output a precursor chunk to get any pipelined
+ MAIL & RCPT commands flushed, then reap the responses so we can
+ error out on RCPT rejects before sending megabytes. */
+
+ if ( dlen + k_file_size > DELIVER_OUT_BUFFER_SIZE
+ && dlen > 0)
+ {
+ if ( tctx->chunk_cb(tctx, dlen, 0) != OK
+ || !transport_write_block(tctx,
+ dkim_signature->data, dlen, FALSE)
+ || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK
+ )
+ goto err;
+ dlen = 0;
+ }
+
+ /* Send the BDAT command for the entire message, as a single LAST-marked
+ chunk. */
+
+ if (tctx->chunk_cb(tctx, dlen + k_file_size, tc_chunk_last) != OK)
+ goto err;
+ }
+
+if(dlen > 0 && !transport_write_block(tctx, dkim_signature->data, dlen, TRUE))
+ goto err;
+
+if (!dkt_send_file(tctx->u.fd, dkim_fd, 0, k_file_size))
+ {
+ save_errno = errno;
+ rc = FALSE;
+ }
+
+CLEANUP:
+ /* unlink -K file */
+ if (dkim_fd >= 0) (void)close(dkim_fd);
+ Uunlink(dkim_spool_name);
+ errno = save_errno;
+ return rc;
+
+err:
+ save_errno = errno;
+ rc = FALSE;
+ goto CLEANUP;
+}
+
+
+
+/***************************************************************************************************
+* External interface to write the message, while signing it with DKIM and/or Domainkeys *
+***************************************************************************************************/
+
+/* This function is a wrapper around transport_write_message().
+ It is only called from the smtp transport if DKIM or Domainkeys support
+ is compiled in.
+
+Arguments:
+ As for transport_write_message() in transort.c, with additional arguments
+ for DKIM.
+
+Returns: TRUE on success; FALSE (with errno) for any failure
+*/
+
+BOOL
+dkim_transport_write_message(transport_ctx * tctx,
+ struct ob_dkim * dkim, const uschar ** err)
+{
+/* If we can't sign, just call the original function. */
+
+if (!(dkim->dkim_private_key && dkim->dkim_domain && dkim->dkim_selector))
+ return transport_write_message(tctx, 0);
+
+/* If there is no filter command set up, construct the message and calculate
+a dkim signature of it, send the signature and a reconstructed message. This
+avoids using a temprary file. */
+
+if ( !transport_filter_argv
+ || !*transport_filter_argv
+ || !**transport_filter_argv
+ )
+ return dkt_direct(tctx, dkim, err);
+
+/* Use the transport path to write a file, calculate a dkim signature,
+send the signature and then send the file. */
+
+return dkt_via_kfile(tctx, dkim, err);
+}
+
+#endif /* whole file */
+
+/* vi: aw ai sw=2
+*/
+/* End of dkim_transport.c */
diff --git a/src/src/dmarc.c b/src/src/dmarc.c
index c005d4ab9..704b0c88d 100644
--- a/src/src/dmarc.c
+++ b/src/src/dmarc.c
@@ -44,6 +44,7 @@ typedef struct dmarc_exim_p {
} dmarc_exim_p;
static dmarc_exim_p dmarc_policy_description[] = {
+ /* name value */
{ US"", DMARC_RECORD_P_UNSPECIFIED },
{ US"none", DMARC_RECORD_P_NONE },
{ US"quarantine", DMARC_RECORD_P_QUARANTINE },
@@ -83,8 +84,7 @@ int dmarc_init()
int *netmask = NULL; /* Ignored */
int is_ipv6 = 0;
char *tld_file = (dmarc_tld_file == NULL) ?
- "/etc/exim/opendmarc.tlds" :
- (char *)dmarc_tld_file;
+ DMARC_TLD_FILE : CS dmarc_tld_file;
/* Set some sane defaults. Also clears previous results when
* multiple messages in one connection. */
@@ -308,7 +308,7 @@ if (!dmarc_abort && !sender_host_authenticated)
sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR :
ARES_RESULT_UNKNOWN;
origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM;
- spf_human_readable = (uschar *)spf_response->header_comment;
+ spf_human_readable = US spf_response->header_comment;
DEBUG(D_receive)
debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain);
}
@@ -336,7 +336,7 @@ if (!dmarc_abort && !sender_host_authenticated)
vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL :
vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
DMARC_POLICY_DKIM_OUTCOME_NONE;
- libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain,
+ libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain,
dkim_result, US"");
DEBUG(D_receive)
debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
@@ -400,7 +400,7 @@ if (!dmarc_abort && !sender_host_authenticated)
/* Can't use exim's string manipulation functions so allocate memory
* for libopendmarc using its max hostname length definition. */
- uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
+ uschar *dmarc_domain = US calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx,
dmarc_domain, DMARC_MAXHOSTNAMELEN-1);
dmarc_used_domain = string_copy(dmarc_domain);
diff --git a/src/src/dns.c b/src/src/dns.c
index e29f86c48..4950079b4 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -271,10 +271,7 @@ else
{
int j;
for (j = 0; j < 32; j += 4)
- {
- sprintf(CS pp, "%x.", (v6[i] >> j) & 15);
- pp += 2;
- }
+ pp += sprintf(CS pp, "%x.", (v6[i] >> j) & 15);
}
Ustrcpy(pp, "ip6.arpa.");
@@ -1019,7 +1016,7 @@ switch (type)
assertion field. */
case T_CSA:
{
- uschar *srvname, *namesuff, *tld, *p;
+ uschar *srvname, *namesuff, *tld;
int priority, weight, port;
int limit, rc, i;
BOOL ipv6;
diff --git a/src/src/drtables.c b/src/src/drtables.c
index 3e1c5e626..10b4ae8e0 100644
--- a/src/src/drtables.c
+++ b/src/src/drtables.c
@@ -19,8 +19,6 @@ all described in src/EDITME. */
lookup_info **lookup_list;
int lookup_list_count = 0;
-static int lookup_list_init_done = 0;
-
/* Table of information about all possible authentication mechanisms. All
entries are always present if any mechanism is declared, but the functions are
set to NULL for those that are not compiled into the binary. */
@@ -63,117 +61,117 @@ auth_info auths_available[] = {
#ifdef AUTH_CRAM_MD5
{
- US"cram_md5", /* lookup name */
- auth_cram_md5_options,
- &auth_cram_md5_options_count,
- &auth_cram_md5_option_defaults,
- sizeof(auth_cram_md5_options_block),
- auth_cram_md5_init, /* init function */
- auth_cram_md5_server, /* server function */
- auth_cram_md5_client, /* client function */
- NULL /* diagnostic function */
+ .driver_name = US"cram_md5", /* lookup name */
+ .options = auth_cram_md5_options,
+ .options_count = &auth_cram_md5_options_count,
+ .options_block = &auth_cram_md5_option_defaults,
+ .options_len = sizeof(auth_cram_md5_options_block),
+ .init = auth_cram_md5_init,
+ .servercode = auth_cram_md5_server,
+ .clientcode = auth_cram_md5_client,
+ .version_report = NULL
},
#endif
#ifdef AUTH_CYRUS_SASL
{
- US"cyrus_sasl", /* lookup name */
- auth_cyrus_sasl_options,
- &auth_cyrus_sasl_options_count,
- &auth_cyrus_sasl_option_defaults,
- sizeof(auth_cyrus_sasl_options_block),
- auth_cyrus_sasl_init, /* init function */
- auth_cyrus_sasl_server, /* server function */
- NULL, /* client function */
- auth_cyrus_sasl_version_report /* diagnostic function */
+ .driver_name = US"cyrus_sasl",
+ .options = auth_cyrus_sasl_options,
+ .options_count = &auth_cyrus_sasl_options_count,
+ .options_block = &auth_cyrus_sasl_option_defaults,
+ .options_len = sizeof(auth_cyrus_sasl_options_block),
+ .init = auth_cyrus_sasl_init,
+ .servercode = auth_cyrus_sasl_server,
+ .clientcode = NULL,
+ .version_report = auth_cyrus_sasl_version_report
},
#endif
#ifdef AUTH_DOVECOT
{
- US"dovecot", /* lookup name */
- auth_dovecot_options,
- &auth_dovecot_options_count,
- &auth_dovecot_option_defaults,
- sizeof(auth_dovecot_options_block),
- auth_dovecot_init, /* init function */
- auth_dovecot_server, /* server function */
- NULL, /* client function */
- NULL /* diagnostic function */
+ .driver_name = US"dovecot",
+ .options = auth_dovecot_options,
+ .options_count = &auth_dovecot_options_count,
+ .options_block = &auth_dovecot_option_defaults,
+ .options_len = sizeof(auth_dovecot_options_block),
+ .init = auth_dovecot_init,
+ .servercode = auth_dovecot_server,
+ .clientcode = NULL,
+ .version_report = NULL
},
#endif
#ifdef AUTH_GSASL
{
- US"gsasl", /* lookup name */
- auth_gsasl_options,
- &auth_gsasl_options_count,
- &auth_gsasl_option_defaults,
- sizeof(auth_gsasl_options_block),
- auth_gsasl_init, /* init function */
- auth_gsasl_server, /* server function */
- NULL, /* client function */
- auth_gsasl_version_report /* diagnostic function */
+ .driver_name = US"gsasl",
+ .options = auth_gsasl_options,
+ .options_count = &auth_gsasl_options_count,
+ .options_block = &auth_gsasl_option_defaults,
+ .options_len = sizeof(auth_gsasl_options_block),
+ .init = auth_gsasl_init,
+ .servercode = auth_gsasl_server,
+ .clientcode = NULL,
+ .version_report = auth_gsasl_version_report
},
#endif
#ifdef AUTH_HEIMDAL_GSSAPI
{
- US"heimdal_gssapi", /* lookup name */
- auth_heimdal_gssapi_options,
- &auth_heimdal_gssapi_options_count,
- &auth_heimdal_gssapi_option_defaults,
- sizeof(auth_heimdal_gssapi_options_block),
- auth_heimdal_gssapi_init, /* init function */
- auth_heimdal_gssapi_server, /* server function */
- NULL, /* client function */
- auth_heimdal_gssapi_version_report /* diagnostic function */
+ .driver_name = US"heimdal_gssapi",
+ .options = auth_heimdal_gssapi_options,
+ .options_count &auth_heimdal_gssapi_options_count,
+ .options_block = &auth_heimdal_gssapi_option_defaults,
+ .options_len = sizeof(auth_heimdal_gssapi_options_block),
+ .init = auth_heimdal_gssapi_init,
+ .servercode = auth_heimdal_gssapi_server,
+ .clientcode = NULL,
+ .version_report = auth_heimdal_gssapi_version_report
},
#endif
#ifdef AUTH_PLAINTEXT
{
- US"plaintext", /* lookup name */
- auth_plaintext_options,
- &auth_plaintext_options_count,
- &auth_plaintext_option_defaults,
- sizeof(auth_plaintext_options_block),
- auth_plaintext_init, /* init function */
- auth_plaintext_server, /* server function */
- auth_plaintext_client, /* client function */
- NULL /* diagnostic function */
+ .driver_name = US"plaintext",
+ .options = auth_plaintext_options,
+ .options_count = &auth_plaintext_options_count,
+ .options_block = &auth_plaintext_option_defaults,
+ .options_len = sizeof(auth_plaintext_options_block),
+ .init = auth_plaintext_init,
+ .servercode = auth_plaintext_server,
+ .clientcode = auth_plaintext_client,
+ .version_report = NULL
},
#endif
#ifdef AUTH_SPA
{
- US"spa", /* lookup name */
- auth_spa_options,
- &auth_spa_options_count,
- &auth_spa_option_defaults,
- sizeof(auth_spa_options_block),
- auth_spa_init, /* init function */
- auth_spa_server, /* server function */
- auth_spa_client, /* client function */
- NULL /* diagnostic function */
+ .driver_name = US"spa",
+ .options = auth_spa_options,
+ .options_count = &auth_spa_options_count,
+ .options_block = &auth_spa_option_defaults,
+ .options_len = sizeof(auth_spa_options_block),
+ .init = auth_spa_init,
+ .servercode = auth_spa_server,
+ .clientcode = auth_spa_client,
+ .version_report = NULL
},
#endif
#ifdef AUTH_TLS
{
- US"tls", /* lookup name */
- auth_tls_options,
- &auth_tls_options_count,
- &auth_tls_option_defaults,
- sizeof(auth_tls_options_block),
- auth_tls_init, /* init function */
- auth_tls_server, /* server function */
- NULL, /* client function */
- NULL /* diagnostic function */
+ .driver_name = US"tls",
+ .options = auth_tls_options,
+ .options_count = &auth_tls_options_count,
+ .options_block = &auth_tls_option_defaults,
+ .options_len = sizeof(auth_tls_options_block),
+ .init = auth_tls_init,
+ .servercode = auth_tls_server,
+ .clientcode = NULL,
+ .version_report = NULL
},
#endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
+{ .driver_name = US"" } /* end marker */
};
@@ -242,96 +240,96 @@ exim binary. */
router_info routers_available[] = {
#ifdef ROUTER_ACCEPT
{
- US"accept",
- accept_router_options,
- &accept_router_options_count,
- &accept_router_option_defaults,
- sizeof(accept_router_options_block),
- accept_router_init,
- accept_router_entry,
- NULL, /* no tidyup entry */
- ri_yestransport
+ .driver_name = US"accept",
+ .options = accept_router_options,
+ .options_count = &accept_router_options_count,
+ .options_block = &accept_router_option_defaults,
+ .options_len = sizeof(accept_router_options_block),
+ .init = accept_router_init,
+ .code = accept_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = ri_yestransport
},
#endif
#ifdef ROUTER_DNSLOOKUP
{
- US"dnslookup",
- dnslookup_router_options,
- &dnslookup_router_options_count,
- &dnslookup_router_option_defaults,
- sizeof(dnslookup_router_options_block),
- dnslookup_router_init,
- dnslookup_router_entry,
- NULL, /* no tidyup entry */
- ri_yestransport
+ .driver_name = US"dnslookup",
+ .options = dnslookup_router_options,
+ .options_count = &dnslookup_router_options_count,
+ .options_block = &dnslookup_router_option_defaults,
+ .options_len = sizeof(dnslookup_router_options_block),
+ .init = dnslookup_router_init,
+ .code = dnslookup_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = ri_yestransport
},
#endif
#ifdef ROUTER_IPLITERAL
{
- US"ipliteral",
- ipliteral_router_options,
- &ipliteral_router_options_count,
- &ipliteral_router_option_defaults,
- sizeof(ipliteral_router_options_block),
- ipliteral_router_init,
- ipliteral_router_entry,
- NULL, /* no tidyup entry */
- ri_yestransport
+ .driver_name = US"ipliteral",
+ .options = ipliteral_router_options,
+ .options_count = &ipliteral_router_options_count,
+ .options_block = &ipliteral_router_option_defaults,
+ .options_len = sizeof(ipliteral_router_options_block),
+ .init = ipliteral_router_init,
+ .code = ipliteral_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = ri_yestransport
},
#endif
#ifdef ROUTER_IPLOOKUP
{
- US"iplookup",
- iplookup_router_options,
- &iplookup_router_options_count,
- &iplookup_router_option_defaults,
- sizeof(iplookup_router_options_block),
- iplookup_router_init,
- iplookup_router_entry,
- NULL, /* no tidyup entry */
- ri_notransport
+ .driver_name = US"iplookup",
+ .options = iplookup_router_options,
+ .options_count = &iplookup_router_options_count,
+ .options_block = &iplookup_router_option_defaults,
+ .options_len = sizeof(iplookup_router_options_block),
+ .init = iplookup_router_init,
+ .code = iplookup_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = ri_notransport
},
#endif
#ifdef ROUTER_MANUALROUTE
{
- US"manualroute",
- manualroute_router_options,
- &manualroute_router_options_count,
- &manualroute_router_option_defaults,
- sizeof(manualroute_router_options_block),
- manualroute_router_init,
- manualroute_router_entry,
- NULL, /* no tidyup entry */
- 0
+ .driver_name = US"manualroute",
+ .options = manualroute_router_options,
+ .options_count = &manualroute_router_options_count,
+ .options_block = &manualroute_router_option_defaults,
+ .options_len = sizeof(manualroute_router_options_block),
+ .init = manualroute_router_init,
+ .code = manualroute_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = 0
},
#endif
#ifdef ROUTER_QUERYPROGRAM
{
- US"queryprogram",
- queryprogram_router_options,
- &queryprogram_router_options_count,
- &queryprogram_router_option_defaults,
- sizeof(queryprogram_router_options_block),
- queryprogram_router_init,
- queryprogram_router_entry,
- NULL, /* no tidyup entry */
- 0
+ .driver_name = US"queryprogram",
+ .options = queryprogram_router_options,
+ .options_count = &queryprogram_router_options_count,
+ .options_block = &queryprogram_router_option_defaults,
+ .options_len = sizeof(queryprogram_router_options_block),
+ .init = queryprogram_router_init,
+ .code = queryprogram_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = 0
},
#endif
#ifdef ROUTER_REDIRECT
{
- US"redirect",
- redirect_router_options,
- &redirect_router_options_count,
- &redirect_router_option_defaults,
- sizeof(redirect_router_options_block),
- redirect_router_init,
- redirect_router_entry,
- NULL, /* no tidyup entry */
- ri_notransport
+ .driver_name = US"redirect",
+ .options = redirect_router_options,
+ .options_count = &redirect_router_options_count,
+ .options_block = &redirect_router_option_defaults,
+ .options_len = sizeof(redirect_router_options_block),
+ .init = redirect_router_init,
+ .code = redirect_router_entry,
+ .tidyup = NULL, /* no tidyup entry */
+ .ri_flags = ri_notransport
},
#endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, 0 }
+{ US"" }
};
@@ -339,91 +337,94 @@ router_info routers_available[] = {
transport_info transports_available[] = {
#ifdef TRANSPORT_APPENDFILE
{
- US"appendfile", /* driver name */
- appendfile_transport_options, /* local options table */
- &appendfile_transport_options_count, /* number of entries */
- &appendfile_transport_option_defaults, /* private options defaults */
- sizeof(appendfile_transport_options_block), /* size of private block */
- appendfile_transport_init, /* init entry point */
- appendfile_transport_entry, /* main entry point */
- NULL, /* no tidyup entry */
- NULL, /* no closedown entry */
- TRUE, /* local flag */
+ .driver_name = US"appendfile",
+ .options = appendfile_transport_options,
+ .options_count = &appendfile_transport_options_count,
+ .options_block = &appendfile_transport_option_defaults, /* private options defaults */
+ .options_len = sizeof(appendfile_transport_options_block),
+ .init = appendfile_transport_init,
+ .code = appendfile_transport_entry,
+ .tidyup = NULL,
+ .closedown = NULL,
+ .local = TRUE
},
#endif
#ifdef TRANSPORT_AUTOREPLY
{
- US"autoreply", /* driver name */
- autoreply_transport_options, /* local options table */
- &autoreply_transport_options_count, /* number of entries */
- &autoreply_transport_option_defaults, /* private options defaults */
- sizeof(autoreply_transport_options_block), /* size of private block */
- autoreply_transport_init, /* init entry point */
- autoreply_transport_entry, /* main entry point */
- NULL, /* no tidyup entry */
- NULL, /* no closedown entry */
- TRUE /* local flag */
+ .driver_name = US"autoreply",
+ .options = autoreply_transport_options,
+ .options_count = &autoreply_transport_options_count,
+ .options_block = &autoreply_transport_option_defaults,
+ .options_len = sizeof(autoreply_transport_options_block),
+ .init = autoreply_transport_init,
+ .code = autoreply_transport_entry,
+ .tidyup = NULL,
+ .closedown = NULL,
+ .local = TRUE
},
#endif
#ifdef TRANSPORT_LMTP
{
- US"lmtp", /* driver name */
- lmtp_transport_options, /* local options table */
- &lmtp_transport_options_count, /* number of entries */
- &lmtp_transport_option_defaults, /* private options defaults */
- sizeof(lmtp_transport_options_block), /* size of private block */
- lmtp_transport_init, /* init entry point */
- lmtp_transport_entry, /* main entry point */
- NULL, /* no tidyup entry */
- NULL, /* no closedown entry */
- TRUE /* local flag */
+ .driver_name = US"lmtp",
+ .options = lmtp_transport_options,
+ .options_count = &lmtp_transport_options_count,
+ .options_block = &lmtp_transport_option_defaults,
+ .options_len = sizeof(lmtp_transport_options_block),
+ .init = lmtp_transport_init,
+ .code = lmtp_transport_entry,
+ .tidyup = NULL,
+ .closedown = NULL,
+ .local = TRUE
},
#endif
#ifdef TRANSPORT_PIPE
{
- US"pipe", /* driver name */
- pipe_transport_options, /* local options table */
- &pipe_transport_options_count, /* number of entries */
- &pipe_transport_option_defaults, /* private options defaults */
- sizeof(pipe_transport_options_block), /* size of private block */
- pipe_transport_init, /* init entry point */
- pipe_transport_entry, /* main entry point */
- NULL, /* no tidyup entry */
- NULL, /* no closedown entry */
- TRUE /* local flag */
+ .driver_name = US"pipe",
+ .options = pipe_transport_options,
+ .options_count = &pipe_transport_options_count,
+ .options_block = &pipe_transport_option_defaults,
+ .options_len = sizeof(pipe_transport_options_block),
+ .init = pipe_transport_init,
+ .code = pipe_transport_entry,
+ .tidyup = NULL,
+ .closedown = NULL,
+ .local = TRUE
},
#endif
#ifdef EXPERIMENTAL_QUEUEFILE
{
- US"queuefile", /* driver name */
- queuefile_transport_options, /* local options table */
- &queuefile_transport_options_count, /* number of entries */
- &queuefile_transport_option_defaults, /* private options defaults */
- sizeof(queuefile_transport_options_block), /* size of private block */
- queuefile_transport_init, /* init entry point */
- queuefile_transport_entry, /* main entry point */
- NULL, /* no tidyup entry */
- NULL, /* no closedown entry */
- TRUE /* local flag */
+ .driver_name = US"queuefile",
+ .options = queuefile_transport_options,
+ .options_count = &queuefile_transport_options_count,
+ .options_block = &queuefile_transport_option_defaults,
+ .options_len = sizeof(queuefile_transport_options_block),
+ .init = queuefile_transport_init,
+ .code = queuefile_transport_entry,
+ .tidyup = NULL,
+ .closedown = NULL,
+ .local = TRUE
},
#endif
#ifdef TRANSPORT_SMTP
{
- US"smtp", /* driver name */
- smtp_transport_options, /* local options table */
- &smtp_transport_options_count, /* number of entries */
- &smtp_transport_option_defaults, /* private options defaults */
- sizeof(smtp_transport_options_block), /* size of private block */
- smtp_transport_init, /* init entry point */
- smtp_transport_entry, /* main entry point */
- NULL, /* no tidyup entry */
- smtp_transport_closedown, /* close down passed channel */
- FALSE /* local flag */
+ .driver_name = US"smtp",
+ .options = smtp_transport_options,
+ .options_count = &smtp_transport_options_count,
+ .options_block = &smtp_transport_option_defaults,
+ .options_len = sizeof(smtp_transport_options_block),
+ .init = smtp_transport_init,
+ .code = smtp_transport_entry,
+ .tidyup = NULL,
+ .closedown = smtp_transport_closedown,
+ .local = FALSE
},
#endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, FALSE }
+{ US"" }
};
+
+#ifndef MACRO_PREDEF
+
struct lookupmodulestr
{
void *dl;
@@ -545,10 +546,12 @@ init_lookup_list(void)
int moduleerrors = 0;
#endif
struct lookupmodulestr *p;
+ static BOOL lookup_list_init_done = FALSE;
+
if (lookup_list_init_done)
return;
- lookup_list_init_done = 1;
+ lookup_list_init_done = TRUE;
#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
addlookupmodule(NULL, &cdb_lookup_module_info);
@@ -721,4 +724,5 @@ init_lookup_list(void)
lookupmodules = NULL;
}
+#endif /*!MACRO_PREDEF*/
/* End of drtables.c */
diff --git a/src/src/exigrep.src b/src/src/exigrep.src
index faa5cb73b..1899267be 100644
--- a/src/src/exigrep.src
+++ b/src/src/exigrep.src
@@ -4,6 +4,9 @@ use warnings;
use strict;
BEGIN { pop @INC if $INC[-1] eq '.' };
+use Pod::Usage;
+use Getopt::Long;
+
# Copyright (c) 2007-2015 University of Cambridge.
# See the file NOTICE for conditions of use and distribution.
@@ -33,7 +36,6 @@ BEGIN { pop @INC if $INC[-1] eq '.' };
# Typical run time acceleration: 4 times
-use Getopt::Std qw(getopts);
use POSIX qw(mktime);
@@ -43,7 +45,7 @@ use POSIX qw(mktime);
sub seconds {
my($year,$month,$day,$hour,$min,$sec,$tzs,$tzh,$tzm) =
- $_[0] =~ /^(\d{4})-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)(?>\s([+-])(\d\d)(\d\d))?/o;
+ $_[0] =~ /^(\d{4})-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)(?:.\d+)?(?>\s([+-])(\d\d)(\d\d))?/o;
my $seconds = mktime $sec, $min, $hour, $day, $month - 1, $year - 1900;
@@ -60,10 +62,17 @@ return $seconds;
# This subroutine processes a single line (in $_) from a log file. Program
# defensively against short lines finding their way into the log.
-my (%saved, %id_list, $pattern, $queue_time, $insensitive, $invert);
+my (%saved, %id_list, $pattern);
+
+my $queue_time = -1;
+my $insensitive = 1;
+my $invert = 0;
+my $related = 0;
+my $use_pager = 1;
+my $literal = 0;
+
# If using "related" option, have to track extra message IDs
-my $related;
my $related_re='';
my @Mids = ();
@@ -74,7 +83,7 @@ sub do_line {
if (!/^\d{4}-/o) { $_ =~ s/^.*? exim\b.*?: //o; }
return unless
- my($date,$id) = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d (?:[+-]\d{4} )?)(?:\[\d+\] )?(\w{6}\-\w{6}\-\w{2})?/o;
+ my($date,$id) = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?(\w{6}\-\w{6}\-\w{2})?/o;
# Handle the case when the log line belongs to a specific message. We save
# lines for specific messages until the message is complete. Then either print
@@ -115,7 +124,7 @@ if (defined $id)
if (index($_, 'Completed') != -1 ||
index($_, 'SMTP data timeout') != -1 ||
(index($_, 'rejected') != -1 &&
- /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d (?:[+-]\d{4} )?)(?:\[\d+\] )?\w{6}\-\w{6}\-\w{2} rejected/o))
+ /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?\w{6}\-\w{6}\-\w{2} rejected/o))
{
if ($queue_time != -1 &&
$saved{$id} =~ /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d ([+-]\d{4} )?)/o)
@@ -205,18 +214,37 @@ sub get_related_ids {
# which is an additional condition. The -M flag will also display "related"
# loglines (msgid from matched lines is searched in following lines).
-getopts('Ilvt:M',\my %args);
-$queue_time = $args{'t'}? $args{'t'} : -1;
-$insensitive = $args{'I'}? 0 : 1;
-$invert = $args{'v'}? 1 : 0;
-$related = $args{'M'}? 1 : 0;
-
-die "usage: exigrep [-I] [-l] [-M] [-t <seconds>] [-v] <pattern> [<log file>]...\n"
- if ($#ARGV < 0);
+GetOptions(
+ 'I|sensitive' => sub { $insensitive = 0 },
+ 'l|literal' => \$literal,
+ 'M|related' => \$related,
+ 't|queue-time=i' => \$queue_time,
+ 'pager!' => \$use_pager,
+ 'v|invert' => \$invert,
+ 'h|help' => sub { pod2usage(-exit => 0, -verbose => 1) },
+ 'm|man' => sub {
+ pod2usage(
+ -exit => 0,
+ -verbose => 2,
+ -noperldoc => system('perldoc -V 2>/dev/null >&2')
+ );
+ },
+) and @ARGV or pod2usage;
$pattern = shift @ARGV;
-$pattern = quotemeta $pattern if $args{l};
+$pattern = quotemeta $pattern if $literal;
+# Start a pager if output goes to a terminal
+if (-t 1 and $use_pager)
+ {
+ foreach ($ENV{PAGER}//(), 'less', 'more')
+ {
+ local $ENV{LESS} .= ' --no-init --quit-if-one-screen';
+ open(my $pager, '|-', $_) or next;
+ select $pager;
+ last;
+ }
+ }
# If file arguments are given, open each one and process according as it is
# is compressed or not.
@@ -256,4 +284,83 @@ for (keys %id_list)
print "+++ $_ has not completed +++\n$saved{$_}\n";
}
-# End of exigrep
+__END__
+
+=head1 NAME
+
+exigrep - search Exim's main log
+
+=head1 SYNOPSIS
+
+B<exigrep> [options] pattern [log] ...
+
+=head1 DESCRIPTION
+
+The B<exigrep> utility is a Perl script that searches one or more main log
+files for entries that match a given pattern. When it finds a match,
+it extracts all the log entries for the relevant message, not just
+those that match the pattern. Thus, B<exigrep> can extract complete log
+entries for a given message, or all mail for a given user, or for a
+given host, for example.
+
+If no file names are given on the command line, the standard input is read.
+
+For known file extensions indicating compression (F<.gz>, F<.bz2>, F<.xz>, and F<.lzma>)
+a suitable de-compressor is used, if available.
+
+The output is sent through a pager if a terminal is connected to STDOUT. As
+pager are considered: C<$ENV{PAGER}>, C<less>, C<more>.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-l>|B<--literal>
+
+This means 'literal', that is, treat all characters in the
+pattern as standing for themselves. Otherwise the pattern must be a
+Perl regular expression. The pattern match is case-insensitive.
+
+=item B<-t>|B<--queue-time> I<seconds>
+
+Limit the output to messages that spent at least I<seconds> in the
+queue.
+
+=item B<-I>|B<--sensitive>
+
+Do a case sensitive search.
+
+=item B<-v>|B<--invert>
+
+Invert the meaning of the search pattern. That is, print message log
+entries that are not related to that pattern.
+
+=item B<-M>|B<--related>
+
+Search for related messages too.
+
+=item B<--no-pager>
+
+Do not use a pager, even if STDOUT is connected to a terminal.
+
+=item B<-h>|B<--help>
+
+Print a short reference help. For more detailed help try L<exigrep(8)>,
+or C<exigrep -m>.
+
+=item B<-m>|B<--man>
+
+Print this manual page of B<exigrep>.
+
+=back
+
+=head1 SEE ALSO
+
+L<exim(8)>, L<perlre(1)>, L<Exim|http://exim.org/>
+
+=head1 AUTHOR
+
+This manual page was stitched together from spec.txt by Andreas Metzler L<ametzler at downhill.at.eu.org>
+and updated by Heiko Schlittermann L<hs@schlittermann.de>.
+
+=cut
diff --git a/src/src/exim.c b/src/src/exim.c
index fd08cc780..f09b26902 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -212,8 +212,7 @@ int fd;
os_restarting_signal(sig, usr1_handler);
-fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE);
-if (fd < 0)
+if ((fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE)) < 0)
{
/* If we are already running as the Exim user, try to create it in the
current process (assuming spool_directory exists). Otherwise, if we are
@@ -345,7 +344,7 @@ Arguments:
Returns: -1, 0, or +1
*/
-int
+static int
exim_tvcmp(struct timeval *t1, struct timeval *t2)
{
if (t1->tv_sec > t2->tv_sec) return +1;
@@ -1443,10 +1442,9 @@ for (m = macros; m; m = m->next) if (m->command_line)
}
if (!found)
return FALSE;
- if (m->replacement == NULL)
+ if (!m->replacement)
continue;
- len = Ustrlen(m->replacement);
- if (len == 0)
+ if ((len = m->replen) == 0)
continue;
n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len,
0, PCRE_EOPT, NULL, 0);
@@ -2457,7 +2455,7 @@ for (i = 1; i < argc; i++)
exit(EXIT_FAILURE);
}
- m = macro_create(name, s, TRUE, FALSE);
+ m = macro_create(string_copy(name), string_copy(s), TRUE);
if (clmacro_count >= MAX_CLMACROS)
{
@@ -2710,7 +2708,7 @@ for (i = 1; i < argc; i++)
/* Set up $sending_ip_address and $sending_port, unless proxied */
- if (!continue_proxy)
+ if (!continue_proxy_cipher)
if (getsockname(fileno(stdin), (struct sockaddr *)(&interface_sock),
&size) == 0)
sending_ip_address = host_ntoa(-1, &interface_sock, NULL,
@@ -2739,7 +2737,7 @@ for (i = 1; i < argc; i++)
/* -MCD: set the smtp_use_dsn flag; this indicates that the host
that exim is connected to supports the esmtp extension DSN */
- case 'D': smtp_peer_options |= PEER_OFFERED_DSN; break;
+ case 'D': smtp_peer_options |= OPTION_DSN; break;
/* -MCG: set the queue name, to a non-default value */
@@ -2749,12 +2747,12 @@ for (i = 1; i < argc; i++)
/* -MCK: the peer offered CHUNKING. Must precede -MC */
- case 'K': smtp_peer_options |= PEER_OFFERED_CHUNKING; break;
+ case 'K': smtp_peer_options |= OPTION_CHUNKING; break;
/* -MCP: set the smtp_use_pipelining flag; this is useful only when
it preceded -MC (see above) */
- case 'P': smtp_peer_options |= PEER_OFFERED_PIPE; break;
+ case 'P': smtp_peer_options |= OPTION_PIPE; break;
/* -MCQ: pass on the pid of the queue-running process that started
this chain of deliveries and the fd of its synchronizing pipe; this
@@ -2769,25 +2767,27 @@ for (i = 1; i < argc; i++)
/* -MCS: set the smtp_use_size flag; this is useful only when it
precedes -MC (see above) */
- case 'S': smtp_peer_options |= PEER_OFFERED_SIZE; break;
+ case 'S': smtp_peer_options |= OPTION_SIZE; break;
#ifdef SUPPORT_TLS
/* -MCt: similar to -MCT below but the connection is still open
via a proxy proces which handles the TLS context and coding.
- Require two arguments for the proxied local address and port. */
+ Require three arguments for the proxied local address and port,
+ and the TLS cipher. */
- case 't': continue_proxy = TRUE;
- if (++i < argc) sending_ip_address = argv[i];
+ case 't': if (++i < argc) sending_ip_address = argv[i];
else badarg = TRUE;
if (++i < argc) sending_port = (int)(Uatol(argv[i]));
else badarg = TRUE;
+ if (++i < argc) continue_proxy_cipher = argv[i];
+ else badarg = TRUE;
/*FALLTHROUGH*/
/* -MCT: set the tls_offered flag; this is useful only when it
precedes -MC (see above). The flag indicates that the host to which
Exim is connected has offered TLS support. */
- case 'T': smtp_peer_options |= PEER_OFFERED_TLS; break;
+ case 'T': smtp_peer_options |= OPTION_TLS; break;
#endif
default: badarg = TRUE; break;
@@ -3104,7 +3104,14 @@ for (i = 1; i < argc; i++)
/* -oMr: Received protocol */
- else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i];
+ else if (Ustrcmp(argrest, "Mr") == 0)
+
+ if (received_protocol)
+ {
+ fprintf(stderr, "received_protocol is set already\n");
+ exit(EXIT_FAILURE);
+ }
+ else received_protocol = argv[++i];
/* -oMs: Set sender host name */
@@ -3200,7 +3207,15 @@ for (i = 1; i < argc; i++)
if (*argrest != 0)
{
- uschar *hn = Ustrchr(argrest, ':');
+ uschar *hn;
+
+ if (received_protocol)
+ {
+ fprintf(stderr, "received_protocol is set already\n");
+ exit(EXIT_FAILURE);
+ }
+
+ hn = Ustrchr(argrest, ':');
if (hn == NULL)
{
received_protocol = argrest;
@@ -3809,6 +3824,10 @@ defined) */
readconf_main(checking || list_options);
+if (builtin_macros_create_trigger) DEBUG(D_any)
+ debug_printf("Builtin macros created (expensive) due to config line '%.*s'\n",
+ Ustrlen(builtin_macros_create_trigger)-1, builtin_macros_create_trigger);
+
/* Now in directory "/" */
if (cleanup_environment() == FALSE)
@@ -3828,17 +3847,13 @@ if (real_uid == root_uid || real_uid == exim_uid || real_gid == exim_gid)
else
{
int i, j;
- for (i = 0; i < group_count; i++)
- {
- if (group_list[i] == exim_gid) admin_user = TRUE;
- else if (admin_groups != NULL)
- {
- for (j = 1; j <= (int)(admin_groups[0]); j++)
+ for (i = 0; i < group_count && !admin_user; i++)
+ if (group_list[i] == exim_gid)
+ admin_user = TRUE;
+ else if (admin_groups)
+ for (j = 1; j <= (int)admin_groups[0] && !admin_user; j++)
if (admin_groups[j] == group_list[i])
- { admin_user = TRUE; break; }
- }
- if (admin_user) break;
- }
+ admin_user = TRUE;
}
/* Another group of privileged users are the trusted users. These are root,
@@ -3852,29 +3867,28 @@ else
{
int i, j;
- if (trusted_users != NULL)
- {
- for (i = 1; i <= (int)(trusted_users[0]); i++)
+ if (trusted_users)
+ for (i = 1; i <= (int)trusted_users[0] && !trusted_caller; i++)
if (trusted_users[i] == real_uid)
- { trusted_caller = TRUE; break; }
- }
+ trusted_caller = TRUE;
- if (!trusted_caller && trusted_groups != NULL)
- {
- for (i = 1; i <= (int)(trusted_groups[0]); i++)
- {
+ if (trusted_groups)
+ for (i = 1; i <= (int)trusted_groups[0] && !trusted_caller; i++)
if (trusted_groups[i] == real_gid)
trusted_caller = TRUE;
- else for (j = 0; j < group_count; j++)
- {
+ else for (j = 0; j < group_count && !trusted_caller; j++)
if (trusted_groups[i] == group_list[j])
- { trusted_caller = TRUE; break; }
- }
- if (trusted_caller) break;
- }
- }
+ trusted_caller = TRUE;
}
+/* At this point, we know if the user is privileged and some command-line
+options become possibly imperssible, depending upon the configuration file. */
+
+if (checking && commandline_checks_require_admin && !admin_user) {
+ fprintf(stderr, "exim: those command-line flags are set to require admin\n");
+ exit(EXIT_FAILURE);
+}
+
/* Handle the decoding of logging options. */
decode_bits(log_selector, log_selector_size, log_notall,
@@ -4117,9 +4131,8 @@ if (((debug_selector & D_any) != 0 || LOGGING(arguments))
quote = US"";
while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; }
}
- sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size -
+ p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size -
(p - big_buffer) - 4), printing, quote);
- while (*p) p++;
}
if (LOGGING(arguments))
@@ -4140,6 +4153,7 @@ if (Uchdir(spool_directory) != 0)
int dummy;
(void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
dummy = /* quieten compiler */ Uchdir(spool_directory);
+ dummy = dummy; /* yet more compiler quietening, sigh */
}
/* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
@@ -4350,11 +4364,8 @@ if (!unprivileged && /* originally had root AND */
(msg_action_arg < 0 || /* and */
msg_action != MSG_DELIVER) && /* not delivering and */
(!checking || !address_test_mode) /* not address checking */
- )
- ))
- {
+ ) ) )
exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed");
- }
/* When we are retaining a privileged uid, we still change to the exim gid. */
@@ -4368,7 +4379,6 @@ else
there's no security risk. For me, it's { exim -bV } on a just-built binary,
no need to complain then. */
if (rv == -1)
- {
if (!(unprivileged || removed_privilege))
{
fprintf(stderr,
@@ -4378,7 +4388,6 @@ else
else
DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n",
(long int)exim_gid, strerror(errno));
- }
}
/* Handle a request to scan a file for malware */
@@ -4528,8 +4537,9 @@ if (test_retry_arg >= 0)
}
}
- yield = retry_find_config(s1, s2, basic_errno, more_errno);
- if (yield == NULL) printf("No retry information found\n"); else
+ if (!(yield = retry_find_config(s1, s2, basic_errno, more_errno)))
+ printf("No retry information found\n");
+ else
{
retry_rule *r;
more_errno = yield->more_errno;
@@ -4561,7 +4571,7 @@ if (test_retry_arg >= 0)
printf("auth_failed ");
else printf("* ");
- for (r = yield->rules; r != NULL; r = r->next)
+ for (r = yield->rules; r; r = r->next)
{
printf("%c,%s", r->rule, readconf_printtime(r->timeout)); /* Do not */
printf(",%s", readconf_printtime(r->p1)); /* amalgamate */
@@ -5327,15 +5337,13 @@ if (smtp_input)
else
{
thismessage_size_limit = expand_string_integer(message_size_limit, TRUE);
- if (expand_string_message != NULL)
- {
+ if (expand_string_message)
if (thismessage_size_limit == -1)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand "
"message_size_limit: %s", expand_string_message);
else
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for "
"message_size_limit: %s", expand_string_message);
- }
}
/* Loop for several messages when reading SMTP input. If we fork any child
@@ -5432,6 +5440,7 @@ while (more)
more = receive_msg(extract_recipients);
if (message_id[0] == 0)
{
+ cancel_cutthrough_connection(TRUE, US"receive dropped");
if (more) goto moreloop;
smtp_log_no_mail(); /* Log no mail if configured */
exim_exit(EXIT_FAILURE);
@@ -5439,6 +5448,7 @@ while (more)
}
else
{
+ cancel_cutthrough_connection(TRUE, US"message setup dropped");
smtp_log_no_mail(); /* Log no mail if configured */
exim_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
}
@@ -5582,7 +5592,7 @@ while (more)
if (!receive_timeout)
{
- struct timeval t = { 30*60, 0 }; /* 30 minutes */
+ struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 }; /* 30 minutes */
fd_set r;
FD_ZERO(&r); FD_SET(0, &r);
@@ -5714,21 +5724,28 @@ while (more)
not if queue_only is set (case 0). Case 1 doesn't happen here (too many
connections). */
- if (local_queue_only) switch(queue_only_reason)
+ if (local_queue_only)
{
- case 2:
- log_write(L_delay_delivery,
- LOG_MAIN, "no immediate delivery: more than %d messages "
- "received in one connection", smtp_accept_queue_per_connection);
- break;
+ cancel_cutthrough_connection(TRUE, US"no delivery; queueing");
+ switch(queue_only_reason)
+ {
+ case 2:
+ log_write(L_delay_delivery,
+ LOG_MAIN, "no immediate delivery: more than %d messages "
+ "received in one connection", smtp_accept_queue_per_connection);
+ break;
- case 3:
- log_write(L_delay_delivery,
- LOG_MAIN, "no immediate delivery: load average %.2f",
- (double)load_average/1000.0);
- break;
+ case 3:
+ log_write(L_delay_delivery,
+ LOG_MAIN, "no immediate delivery: load average %.2f",
+ (double)load_average/1000.0);
+ break;
+ }
}
+ else if (queue_only_policy || deliver_freeze)
+ cancel_cutthrough_connection(TRUE, US"no delivery; queueing");
+
/* Else do the delivery unless the ACL or local_scan() called for queue only
or froze the message. Always deliver in a separate process. A fork failure is
not a disaster, as the delivery will eventually happen on a subsequent queue
@@ -5737,7 +5754,7 @@ while (more)
thereby defer the delivery if it tries to use (for example) a cached ldap
connection that the parent has called unbind on. */
- else if (!queue_only_policy && !deliver_freeze)
+ else
{
pid_t pid;
search_tidyup();
@@ -5753,8 +5770,7 @@ while (more)
if (geteuid() != root_uid && !deliver_drop_privilege && !unprivileged)
{
- (void)child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE,
- 2, US"-Mc", message_id);
+ delivery_re_exec(CEE_EXEC_EXIT);
/* Control does not return here. */
}
@@ -5768,22 +5784,27 @@ while (more)
if (pid < 0)
{
+ cancel_cutthrough_connection(TRUE, US"delivery fork failed");
log_write(0, LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery "
"process: %s", strerror(errno));
}
+ else
+ {
+ release_cutthrough_connection(US"msg passed for delivery");
- /* In the parent, wait if synchronous delivery is required. This will
- always be the case in MUA wrapper mode. */
+ /* In the parent, wait if synchronous delivery is required. This will
+ always be the case in MUA wrapper mode. */
- else if (synchronous_delivery)
- {
- int status;
- while (wait(&status) != pid);
- if ((status & 0x00ff) != 0)
- log_write(0, LOG_MAIN|LOG_PANIC,
- "process %d crashed with signal %d while delivering %s",
- (int)pid, status & 0x00ff, message_id);
- if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE);
+ if (synchronous_delivery)
+ {
+ int status;
+ while (wait(&status) != pid);
+ if ((status & 0x00ff) != 0)
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "process %d crashed with signal %d while delivering %s",
+ (int)pid, status & 0x00ff, message_id);
+ if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE);
+ }
}
}
@@ -5818,4 +5839,50 @@ exim_exit(EXIT_SUCCESS); /* Never returns */
return 0; /* To stop compiler warning */
}
+/*************************************************
+* read as much as requested *
+*************************************************/
+
+/* The syscall read(2) doesn't always returns as much as we want. For
+several reasons it might get less. (Not talking about signals, as syscalls
+are restartable). When reading from a network or pipe connection the sender
+might send in smaller chunks, with delays between these chunks. The read(2)
+may return such a chunk.
+
+The more the writer writes and the smaller the pipe between write and read is,
+the more we get the chance of reading leass than requested. (See bug 2130)
+
+This function read(2)s until we got all the data we *requested*.
+
+Note: This function may block. Use it only if you're sure about the
+amount of data you will get.
+
+Argument:
+ fd the file descriptor to read from
+ buffer pointer to a buffer of size len
+ len the requested(!) amount of bytes
+
+Returns: the amount of bytes read
+*/
+ssize_t
+readn(int fd, void *buffer, size_t len)
+{
+ void *next = buffer;
+ void *end = buffer + len;
+
+ while (next < end)
+ {
+ ssize_t got = read(fd, next, end - next);
+
+ /* I'm not sure if there are signals that can interrupt us,
+ for now I assume the worst */
+ if (got == -1 && errno == EINTR) continue;
+ if (got <= 0) return next - buffer;
+ next += got;
+ }
+
+ return len;
+}
+
+
/* End of exim.c */
diff --git a/src/src/exim.h b/src/src/exim.h
index d03b48c66..f8dd9a9ba 100644
--- a/src/src/exim.h
+++ b/src/src/exim.h
@@ -492,6 +492,7 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
#include "macros.h"
#include "dbstuff.h"
#include "structs.h"
+#include "blob.h"
#include "globals.h"
#include "hash.h"
#include "functions.h"
@@ -596,5 +597,9 @@ default to EDQUOT if it exists, otherwise ENOSPC. */
# undef DISABLE_DNSSEC
#endif
+/* Wrapper around read(2) to read all the data we requested (BLOCKING) */
+ssize_t
+readn(int fd, void *buffer, size_t len);
+
#endif
/* End of exim.h */
diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c
index 85ae9012b..7431bbc03 100644
--- a/src/src/exim_dbmbuild.c
+++ b/src/src/exim_dbmbuild.c
@@ -30,6 +30,7 @@ characters. */
#include "exim.h"
+uschar * spool_directory = NULL; /* dummy for dbstuff.h */
#define max_insize 20000
#define max_outsize 100000
@@ -151,6 +152,7 @@ uschar *bptr;
uschar keybuffer[256];
uschar temp_dbmname[512];
uschar real_dbmname[512];
+uschar dirname[512];
uschar *buffer = malloc(max_outsize);
uschar *line = malloc(max_insize);
@@ -205,10 +207,14 @@ if (strlen(argv[arg+1]) > sizeof(temp_dbmname) - 20)
Ustrcpy(temp_dbmname, argv[arg+1]);
Ustrcat(temp_dbmname, ".dbmbuild_temp");
+Ustrcpy(dirname, temp_dbmname);
+if ((bptr = Ustrrchr(dirname, '/')))
+ *bptr = '\0';
+
/* It is apparently necessary to open with O_RDWR for this to work
with gdbm-1.7.3, though no reading is actually going to be done. */
-EXIM_DBOPEN(temp_dbmname, O_RDWR|O_CREAT|O_EXCL, 0644, &d);
+EXIM_DBOPEN(temp_dbmname, dirname, O_RDWR|O_CREAT|O_EXCL, 0644, &d);
if (d == NULL)
{
diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c
index c710772ed..fb455bbd3 100644
--- a/src/src/exim_dbutil.c
+++ b/src/src/exim_dbutil.c
@@ -253,18 +253,19 @@ dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof)
int rc;
struct flock lock_data;
BOOL read_only = flags == O_RDONLY;
-uschar buffer[256];
+uschar dirname[256], filename[256];
/* The first thing to do is to open a separate file on which to lock. This
ensures that Exim has exclusive use of the database before it even tries to
open it. If there is a database, there should be a lock file in existence. */
-sprintf(CS buffer, "%s/db/%.200s.lockfile", spool_directory, name);
+snprintf(CS dirname, sizeof(dirname), "%s/db", spool_directory);
+snprintf(CS filename, sizeof(filename), "%s/%.200s.lockfile", dirname, name);
-dbblock->lockfd = Uopen(buffer, flags, 0);
+dbblock->lockfd = Uopen(filename, flags, 0);
if (dbblock->lockfd < 0)
{
- printf("** Failed to open database lock file %s: %s\n", buffer,
+ printf("** Failed to open database lock file %s: %s\n", filename,
strerror(errno));
return NULL;
}
@@ -286,7 +287,7 @@ if (rc < 0)
{
printf("** Failed to get %s lock for %s: %s",
flags & O_WRONLY ? "write" : "read",
- buffer,
+ filename,
errno == ETIMEDOUT ? "timed out" : strerror(errno));
(void)close(dbblock->lockfd);
return NULL;
@@ -295,12 +296,12 @@ if (rc < 0)
/* At this point we have an opened and locked separate lock file, that is,
exclusive access to the database, so we can go ahead and open it. */
-sprintf(CS buffer, "%s/db/%s", spool_directory, name);
-EXIM_DBOPEN(buffer, flags, 0, &(dbblock->dbptr));
+sprintf(CS filename, "%s/%s", dirname, name);
+EXIM_DBOPEN(filename, dirname, flags, 0, &(dbblock->dbptr));
if (dbblock->dbptr == NULL)
{
- printf("** Failed to open DBM file %s for %s:\n %s%s\n", buffer,
+ printf("** Failed to open DBM file %s for %s:\n %s%s\n", filename,
read_only? "reading" : "writing", strerror(errno),
#ifdef USE_DB
" (or Berkeley DB error while opening)"
@@ -516,15 +517,16 @@ uschar keybuffer[1024];
dbdata_type = check_args(argc, argv, US"dumpdb", US"");
spool_directory = argv[1];
-dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE);
-if (dbm == NULL) exit(1);
+if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE)))
+ exit(1);
/* Scan the file, formatting the information for each entry. Note
that data is returned in a malloc'ed block, in order that it be
correctly aligned. */
-key = dbfn_scan(dbm, TRUE, &cursor);
-while (key != NULL)
+for (key = dbfn_scan(dbm, TRUE, &cursor);
+ key;
+ key = dbfn_scan(dbm, FALSE, &cursor))
{
dbdata_retry *retry;
dbdata_wait *wait;
@@ -546,9 +548,8 @@ while (key != NULL)
return 1;
}
Ustrcpy(keybuffer, key);
- value = dbfn_read_with_length(dbm, keybuffer, &length);
- if (value == NULL)
+ if (!(value = dbfn_read_with_length(dbm, keybuffer, &length)))
fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record "
"was not found in the file - something is wrong!\n",
CS keybuffer);
@@ -668,7 +669,6 @@ while (key != NULL)
}
store_reset(value);
}
- key = dbfn_scan(dbm, FALSE, &cursor);
}
dbfn_close(dbm);
@@ -775,8 +775,9 @@ for(;;)
{
int verify = 1;
spool_directory = argv[1];
- dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE);
- if (dbm == NULL) continue;
+
+ if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE)))
+ continue;
if (Ustrcmp(field, "d") == 0)
{
@@ -972,11 +973,10 @@ for(;;)
/* Handle a read request, or verify after an update. */
spool_directory = argv[1];
- dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE);
- if (dbm == NULL) continue;
+ if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE)))
+ continue;
- record = dbfn_read_with_length(dbm, name, &oldlength);
- if (record == NULL)
+ if (!(record = dbfn_read_with_length(dbm, name, &oldlength)))
{
printf("record %s not found\n", name);
name[0] = 0;
@@ -1159,8 +1159,8 @@ oldest = time(NULL) - maxkeep;
printf("Tidying Exim hints database %s/db/%s\n", argv[1], argv[2]);
spool_directory = argv[1];
-dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE);
-if (dbm == NULL) exit(1);
+if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE)))
+ exit(1);
/* Prepare for building file names */
@@ -1173,14 +1173,14 @@ to the file while scanning it. Pity the man page doesn't warn you about that.
Therefore, we scan and build a list of all the keys. Then we use that to
read the records and possibly update them. */
-key = dbfn_scan(dbm, TRUE, &cursor);
-while (key != NULL)
+for (key = dbfn_scan(dbm, TRUE, &cursor);
+ key;
+ key = dbfn_scan(dbm, FALSE, &cursor))
{
key_item *k = store_get(sizeof(key_item) + Ustrlen(key));
k->next = keychain;
keychain = k;
Ustrcpy(k->key, key);
- key = dbfn_scan(dbm, FALSE, &cursor);
}
/* Now scan the collected keys and operate on the records, resetting
@@ -1188,7 +1188,7 @@ the store each time round. */
reset_point = store_get(0);
-while (keychain != NULL)
+while (keychain)
{
dbdata_generic *value;
diff --git a/src/src/eximstats.src b/src/src/eximstats.src
index a2113f106..727ee44b9 100644
--- a/src/src/eximstats.src
+++ b/src/src/eximstats.src
@@ -896,6 +896,7 @@ sub unformat_time {
# POSIX::mktime. We expect the timestamp to be of the form
# "$year-$mon-$day $hour:$min:$sec", with month going from 1 to 12,
# and the year to be absolute (we do the necessary conversions). The
+# seconds value can be followed by decimals, which we ignore. The
# timestamp may be followed with an offset from UTC like "+$hh$mm"; if the
# offset is not present, and we have not been told that the log is in UTC
# (with the -utc option), then we adjust the time by the current local
@@ -919,7 +920,7 @@ sub seconds {
# Is the timestamp the same as the last one?
return $last_time if ($last_timestamp eq $timestamp);
- return 0 unless ($timestamp =~ /^((\d{4})\-(\d\d)-(\d\d))\s(\d\d):(\d\d):(\d\d)( ([+-])(\d\d)(\d\d))?/o);
+ return 0 unless ($timestamp =~ /^((\d{4})\-(\d\d)-(\d\d))\s(\d\d):(\d\d):(\d\d)(?:\.\d+)?( ([+-])(\d\d)(\d\d))?/o);
unless ($last_date eq $1) {
$last_date = $1;
@@ -931,7 +932,7 @@ sub seconds {
my $time = $date_seconds + ($5 * 3600) + ($6 * 60) + $7;
# SC. Use caching. Also note we want seconds not minutes.
- #my($this_offset) = ($10 * 60 + $11) * ($9 . "1") if defined $8;
+ #my($this_offset) = ($10 * 60 + $12) * ($9 . "1") if defined $8;
if (defined $8 && ($8 ne $last_offset)) {
$last_offset = $8;
$offset_seconds = ($10 * 60 + $11) * 60;
@@ -939,7 +940,7 @@ sub seconds {
}
- if (defined $7) {
+ if (defined $8) {
#$time -= $this_offset;
$time -= $offset_seconds;
} elsif (defined $localtime_offset) {
@@ -1853,12 +1854,23 @@ sub generate_parser {
$length = length($_);
next if ($length < 38);
- next unless /^(\\d{4}\\-\\d\\d-\\d\\d\\s(\\d\\d):(\\d\\d):\\d\\d( [-+]\\d\\d\\d\\d)?)( \\[\\d+\\])?/o;
-
- ($tod,$m_hour,$m_min) = ($1,$2,$3);
+ next unless /^
+ (\\d{4}\\-\\d\\d-\\d\\d\\s # 1: YYYYMMDD HHMMSS
+ (\\d\\d) # 2: HH
+ :
+ (\\d\\d) # 3: MM
+ :\\d\\d
+ )
+ (\\.\\d+)? # 4: subseconds
+ (\s[-+]\\d\\d\\d\\d)? # 5: tz-offset
+ (\s\\[\\d+\\])? # 6: pid
+ /ox;
+
+ $tod = defined($5) ? $1 . $5 : $1;
+ ($m_hour,$m_min) = ($2,$3);
# PH - watch for GMT offsets in the timestamp.
- if (defined($4)) {
+ if (defined($5)) {
$extra = 6;
next if ($length < 44);
}
@@ -1866,9 +1878,15 @@ sub generate_parser {
$extra = 0;
}
+ # watch for subsecond precision
+ if (defined($4)) {
+ $extra += length($4);
+ next if ($length < 38 + $extra);
+ }
+
# PH - watch for PID added after the timestamp.
- if (defined($5)) {
- $extra += length($5);
+ if (defined($6)) {
+ $extra += length($6);
next if ($length < 38 + $extra);
}
diff --git a/src/src/exipick.src b/src/src/exipick.src
index 4999d843f..4751f7657 100644
--- a/src/src/exipick.src
+++ b/src/src/exipick.src
@@ -42,6 +42,7 @@ $| = 1; # unbuffer STDOUT
Getopt::Long::Configure("bundling_override");
GetOptions(
'spool=s' => \$G::spool, # exim spool dir
+ 'C|Config=s' => \$G::config, # use alternative Exim configuration file
'input-dir=s' => \$G::input_dir, # name of the "input" dir
'finput' => \$G::finput, # same as "--input-dir Finput"
'bp' => \$G::mailq_bp, # List the queue (noop - default)
@@ -115,8 +116,8 @@ $G::msg_ids = {}; # short circuit when crit is only MID
$G::caseless = $G::caseful ? 0 : 1; # nocase by default, case if both
@G::recipients_crit = (); # holds per-recip criteria
$spool = defined $G::spool ? $G::spool
- : do { chomp($_ = `$exim -n -bP spool_directory`);
- $_ // $spool };
+ : do { chomp($_ = `$exim @{[defined $G::config ? "-C $G::config" : '']} -n -bP spool_directory`)
+ and $_ or $spool };
my $input_dir = $G::input_dir || ($G::finput ? "Finput" : "input");
my $count_only = 1 if ($G::mailq_bpc || $G::qgrep_c);
my $unsorted = 1 if ($G::mailq_bpr || $G::mailq_bpra ||
@@ -1354,6 +1355,11 @@ Same as '-bpu --unsorted' (exim)
Same as -bp, but only show undelivered messages (exim)
+=item -C | --config <config>
+
+Use <config> to determine the proper spool directory. (See C<--spool>
+or C<--input> for alternative ways to specify the directories to operate on.)
+
=item -c
Show a count of matching messages (exiqgrep)
@@ -1432,8 +1438,7 @@ Same as '$shown_message_size eq <string>' (exiqgrep)
=item --spool <path>
-Set the path to the exim spool to use. This value will have the argument to --input or 'input' appended, or be ignored if --input is a full path. If not specified, exipick uses the value from C<exim -bP spool_directory>, and if this fails, the F<SPOOL_DIRECTORY>
-from build time (F<Local/Makefile>) is used.
+Set the path to the exim spool to use. This value will have the argument to --input or 'input' appended, or be ignored if --input is a full path. If not specified, exipick uses the value from C<exim [-C config] -n -bP spool_directory>, and if this call fails, the F</opt/exim/spool> from build time (F<Local/Makefile>) is used. See also --config.
=item --show-rules
diff --git a/src/src/expand.c b/src/src/expand.c
index b96b2897a..353b8ea56 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -642,7 +642,7 @@ static var_entry var_table[] = {
{ "received_ip_address", vtype_stringptr, &interface_address },
{ "received_port", vtype_int, &interface_port },
{ "received_protocol", vtype_stringptr, &received_protocol },
- { "received_time", vtype_int, &received_time },
+ { "received_time", vtype_int, &received_time.tv_sec },
{ "recipient_data", vtype_stringptr, &recipient_data },
{ "recipient_verify_failure",vtype_stringptr,&recipient_verify_failure },
{ "recipients", vtype_string_func, &fn_recipients },
@@ -680,6 +680,7 @@ static var_entry var_table[] = {
{ "smtp_active_hostname", vtype_stringptr, &smtp_active_hostname },
{ "smtp_command", vtype_stringptr, &smtp_cmd_buffer },
{ "smtp_command_argument", vtype_stringptr, &smtp_cmd_argument },
+ { "smtp_command_history", vtype_string_func, &smtp_cmd_hist },
{ "smtp_count_at_connection_start", vtype_int, &smtp_accept_count },
{ "smtp_notquit_reason", vtype_stringptr, &smtp_notquit_reason },
{ "sn0", vtype_filter_int, &filter_sn[0] },
@@ -1483,9 +1484,7 @@ while (*s != 0)
/* If value2 is unset, just compute one number */
if (value2 < 0)
- {
s = string_sprintf("%d", total % value1);
- }
/* Otherwise do a div/mod hash */
@@ -1554,11 +1553,9 @@ for (i = 0; i < 2; i++)
int size = 0;
header_line *h;
- for (h = header_list; size < header_insert_maxlen && h != NULL; h = h->next)
- {
- if (h->type != htype_old && h->text != NULL) /* NULL => Received: placeholder */
- {
- if (name == NULL || (len <= h->slen && strncmpic(name, h->text, len) == 0))
+ for (h = header_list; size < header_insert_maxlen && h; h = h->next)
+ if (h->type != htype_old && h->text) /* NULL => Received: placeholder */
+ if (!name || (len <= h->slen && strncmpic(name, h->text, len) == 0))
{
int ilen;
uschar *t;
@@ -1580,7 +1577,7 @@ for (i = 0; i < 2; i++)
that contains an address list, except when asked for raw headers. Only
need to do this once. */
- if (!want_raw && name != NULL && comma == 0 &&
+ if (!want_raw && name && comma == 0 &&
Ustrchr("BCFRST", h->type) != NULL)
comma = 1;
@@ -1613,8 +1610,6 @@ for (i = 0; i < 2; i++)
}
}
}
- }
- }
/* At end of first pass, return NULL if no header found. Then truncate size
if necessary, and get the buffer to hold the data, returning the buffer size.
@@ -1632,9 +1627,7 @@ for (i = 0; i < 2; i++)
/* That's all we do for raw header expansion. */
if (want_raw)
- {
*ptr = 0;
- }
/* Otherwise, remove a final newline and a redundant added comma. Then we do
RFC 2047 decoding, translating the charset if requested. The rfc2047_decode2()
@@ -1838,7 +1831,7 @@ switch (vp->type)
case vtype_msgbody: /* Pointer to msgbody string */
case vtype_msgbody_end: /* Ditto, the end of the msg */
ss = (uschar **)(val);
- if (*ss == NULL && deliver_datafile >= 0) /* Read body when needed */
+ if (!*ss && deliver_datafile >= 0) /* Read body when needed */
{
uschar *body;
off_t start_offset = SPOOL_DATA_START_OFFSET;
@@ -1871,7 +1864,7 @@ switch (vp->type)
{ if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; }
}
}
- return (*ss == NULL)? US"" : *ss;
+ return *ss ? *ss : US"";
case vtype_todbsdin: /* BSD inbox time of day */
return tod_stamp(tod_bsdin);
@@ -2384,8 +2377,10 @@ switch(cond_type)
case 3: return NULL;
}
- *resetok = FALSE; /* eval_acl() might allocate; do not reclaim */
- if (yield != NULL) switch(eval_acl(sub, nelem(sub), &user_msg))
+ if (yield != NULL)
+ {
+ *resetok = FALSE; /* eval_acl() might allocate; do not reclaim */
+ switch(eval_acl(sub, nelem(sub), &user_msg))
{
case OK:
cond = TRUE;
@@ -2406,6 +2401,7 @@ switch(cond_type)
expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]);
return NULL;
}
+ }
return s;
}
@@ -4712,8 +4708,7 @@ while (*s != 0)
/* Open the file and read it */
- f = Ufopen(sub_arg[0], "rb");
- if (f == NULL)
+ if (!(f = Ufopen(sub_arg[0], "rb")))
{
expand_string_message = string_open_failed(errno, "%s", sub_arg[0]);
goto EXPAND_FAILED;
@@ -4724,7 +4719,8 @@ while (*s != 0)
continue;
}
- /* Handle "readsocket" to insert data from a Unix domain socket */
+ /* Handle "readsocket" to insert data from a socket, either
+ Inet or Unix domain */
case EITEM_READSOCK:
{
@@ -4732,10 +4728,10 @@ while (*s != 0)
int timeout = 5;
int save_ptr = ptr;
FILE *f;
- struct sockaddr_un sockun; /* don't call this "sun" ! */
uschar *arg;
uschar *sub_arg[4];
BOOL do_shutdown = TRUE;
+ blob reqstr;
if (expand_forbid & RDO_READSOCK)
{
@@ -4753,6 +4749,11 @@ while (*s != 0)
case 3: goto EXPAND_FAILED;
}
+ /* Grab the request string, if any */
+
+ reqstr.data = sub_arg[1];
+ reqstr.len = Ustrlen(sub_arg[1]);
+
/* Sort out timeout, if given. The second arg is a list with the first element
being a time value. Any more are options of form "name=value". Currently the
only option recognised is "shutdown". */
@@ -4787,12 +4788,12 @@ while (*s != 0)
if (Ustrncmp(sub_arg[0], "inet:", 5) == 0)
{
int port;
- uschar *server_name = sub_arg[0] + 5;
- uschar *port_name = Ustrrchr(server_name, ':');
+ uschar * server_name = sub_arg[0] + 5;
+ uschar * port_name = Ustrrchr(server_name, ':');
/* Sort out the port */
- if (port_name == NULL)
+ if (!port_name)
{
expand_string_message =
string_sprintf("missing port for readsocket %s", sub_arg[0]);
@@ -4814,7 +4815,7 @@ while (*s != 0)
else
{
struct servent *service_info = getservbyname(CS port_name, "tcp");
- if (service_info == NULL)
+ if (!service_info)
{
expand_string_message = string_sprintf("unknown port \"%s\"",
port_name);
@@ -4824,17 +4825,20 @@ while (*s != 0)
}
fd = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
- timeout, NULL, &expand_string_message);
+ timeout, NULL, &expand_string_message, &reqstr);
callout_address = NULL;
if (fd < 0)
goto SOCK_FAIL;
+ reqstr.len = 0;
}
/* Handle a Unix domain socket */
else
{
+ struct sockaddr_un sockun; /* don't call this "sun" ! */
int rc;
+
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
{
expand_string_message = string_sprintf("failed to create socket: %s",
@@ -4868,14 +4872,13 @@ while (*s != 0)
/* Allow sequencing of test actions */
if (running_in_test_harness) millisleep(100);
- /* Write the request string, if not empty */
+ /* Write the request string, if not empty or already done */
- if (sub_arg[1][0] != 0)
+ if (reqstr.len)
{
- int len = Ustrlen(sub_arg[1]);
DEBUG(D_expand) debug_printf_indent("writing \"%s\" to socket\n",
- sub_arg[1]);
- if (write(fd, sub_arg[1], len) != len)
+ reqstr.data);
+ if (write(fd, reqstr.data, reqstr.len) != reqstr.len)
{
expand_string_message = string_sprintf("request write to socket "
"failed: %s", strerror(errno));
@@ -5991,7 +5994,9 @@ while (*s != 0)
{
uschar * dstitem;
uschar * newlist = NULL;
+ int size = 0, len = 0;
uschar * newkeylist = NULL;
+ int ksize = 0, klen = 0;
uschar * srcfield;
DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem);
@@ -6036,33 +6041,33 @@ while (*s != 0)
/* New-item sorts before this dst-item. Append new-item,
then dst-item, then remainder of dst list. */
- newlist = string_append_listele(newlist, sep, srcitem);
- newkeylist = string_append_listele(newkeylist, sep, srcfield);
+ newlist = string_append_listele(newlist, &size, &len, sep, srcitem);
+ newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield);
srcitem = NULL;
- newlist = string_append_listele(newlist, sep, dstitem);
- newkeylist = string_append_listele(newkeylist, sep, dstfield);
+ newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
+ newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0)))
{
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
goto sort_mismatch;
- newlist = string_append_listele(newlist, sep, dstitem);
- newkeylist = string_append_listele(newkeylist, sep, dstfield);
+ newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
+ newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
}
break;
}
- newlist = string_append_listele(newlist, sep, dstitem);
- newkeylist = string_append_listele(newkeylist, sep, dstfield);
+ newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
+ newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
}
/* If we ran out of dstlist without consuming srcitem, append it */
if (srcitem)
{
- newlist = string_append_listele(newlist, sep, srcitem);
- newkeylist = string_append_listele(newkeylist, sep, srcfield);
+ newlist = string_append_listele(newlist, &size, &len, sep, srcitem);
+ newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield);
}
dstlist = newlist;
@@ -6466,7 +6471,7 @@ while (*s != 0)
blob b;
char st[3];
- if (!exim_sha_init(&h, HASH_SHA256))
+ if (!exim_sha_init(&h, HASH_SHA2_256))
{
expand_string_message = US"unrecognised sha256 variant";
goto EXPAND_FAILED;
@@ -6660,19 +6665,19 @@ while (*s != 0)
char * cp;
char tok[3];
tok[0] = sep; tok[1] = ':'; tok[2] = 0;
- while ((cp= strpbrk((const char *)item, tok)))
+ while ((cp= strpbrk(CCS item, tok)))
{
- yield = string_catn(yield, &size, &ptr, item, cp-(char *)item);
+ yield = string_catn(yield, &size, &ptr, item, cp-CS item);
if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */
{
yield = string_catn(yield, &size, &ptr, US"::", 2);
- item = (uschar *)cp;
+ item = US cp;
}
else /* sep in item; should already be doubled; emit once */
{
- yield = string_catn(yield, &size, &ptr, (uschar *)tok, 1);
+ yield = string_catn(yield, &size, &ptr, US tok, 1);
if (*cp == sep) cp++;
- item = (uschar *)cp;
+ item = US cp;
}
}
}
diff --git a/src/src/filter.c b/src/src/filter.c
index a5c3b5dfa..86232c187 100644
--- a/src/src/filter.c
+++ b/src/src/filter.c
@@ -91,7 +91,7 @@ static const char *mailargs[] = { /* "to" must be first, and */
/* The count of string arguments */
-#define MAILARGS_STRING_COUNT (sizeof(mailargs)/sizeof(uschar *))
+#define MAILARGS_STRING_COUNT (nelem(mailargs))
/* The count of string arguments that are actually passed over as strings
(once_repeat is converted to an int). */
@@ -185,7 +185,7 @@ static const char *cond_words[] = {
"match",
"matches"};
-static int cond_word_count = (sizeof(cond_words)/sizeof(uschar *));
+static int cond_word_count = nelem(cond_words);
static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS,
cond_CONTAINS, cond_ENDS, cond_ENDS, cond_IS, cond_MATCHES, cond_MATCHES,
@@ -207,7 +207,7 @@ static const char *command_list[] = {
"noerror", "pipe", "save", "seen", "testprint", "unseen", "vacation"
};
-static int command_list_count = sizeof(command_list)/sizeof(uschar *);
+static int command_list_count = nelem(command_list);
/* This table contains the number of expanded arguments in the bottom 4 bits.
If the top bit is set, it means that the default for the command is "seen". */
@@ -1815,7 +1815,7 @@ while (commands != NULL)
addr = deliver_make_addr(expargs[0], TRUE); /* TRUE => copy s */
addr->prop.errors_address = (s == NULL)?
s : string_copy(s); /* Default is NULL */
- if (commands->noerror) setflag(addr, af_ignore_error);
+ if (commands->noerror) addr->prop.ignore_error = TRUE;
addr->next = *generated;
*generated = addr;
}
@@ -1855,8 +1855,9 @@ while (commands != NULL)
mode value. */
addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
- setflag(addr, af_pfr|af_file);
- if (commands->noerror) setflag(addr, af_ignore_error);
+ setflag(addr, af_pfr);
+ setflag(addr, af_file);
+ if (commands->noerror) addr->prop.ignore_error = TRUE;
addr->mode = mode;
addr->next = *generated;
*generated = addr;
@@ -1884,8 +1885,9 @@ while (commands != NULL)
has been split up into separate arguments. */
addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
- setflag(addr, af_pfr|af_expand_pipe);
- if (commands->noerror) setflag(addr, af_ignore_error);
+ setflag(addr, af_pfr);
+ setflag(addr, af_expand_pipe);
+ if (commands->noerror) addr->prop.ignore_error = TRUE;
addr->next = *generated;
*generated = addr;
@@ -2220,7 +2222,7 @@ while (commands != NULL)
uschar *to = commands->args[mailarg_index_to].u;
int size = 0;
int ptr = 0;
- int badflag = 0;
+ BOOL badflag;
if (to == NULL) to = expand_string(US"$reply_address");
while (isspace(*to)) to++;
@@ -2292,16 +2294,15 @@ while (commands != NULL)
while (isspace(*tt)) tt++;
}
- if (log_addr == NULL)
- {
+ if ((badflag = !log_addr))
log_addr = string_sprintf(">**bad-reply**");
- badflag = af_bad_reply;
- }
- else log_addr[ptr] = 0;
+ else
+ log_addr[ptr] = 0;
addr = deliver_make_addr(log_addr, FALSE);
- setflag(addr, (af_pfr|badflag));
- if (commands->noerror) setflag(addr, af_ignore_error);
+ setflag(addr, af_pfr);
+ if (badflag) setflag(addr, af_bad_reply);
+ if (commands->noerror) addr->prop.ignore_error = TRUE;
addr->next = *generated;
*generated = addr;
addr->reply = store_get(sizeof(reply_item));
diff --git a/src/src/functions.h b/src/src/functions.h
index a7d9c1116..9d1f6dc6e 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -14,7 +14,7 @@ are in in fact in separate headers. */
#ifdef EXIM_PERL
extern uschar *call_perl_cat(uschar *, int *, int *, uschar **, uschar *,
- uschar **);
+ uschar **) WARN_UNUSED_RESULT;
extern void cleanup_perl(void);
extern uschar *init_perl(uschar *);
#endif
@@ -51,18 +51,20 @@ extern int tls_client_start(int, host_item *, address_item *,
# endif
uschar **);
extern void tls_close(BOOL, BOOL);
+extern BOOL tls_could_read(void);
extern int tls_export_cert(uschar *, size_t, void *);
extern int tls_feof(void);
extern int tls_ferror(void);
extern void tls_free_cert(void **);
extern int tls_getc(unsigned);
+extern uschar *tls_getbuf(unsigned *);
extern void tls_get_cache(void);
extern int tls_import_cert(const uschar *, void **);
extern int tls_read(BOOL, uschar *, size_t);
extern int tls_server_start(const uschar *, uschar **);
extern BOOL tls_smtp_buffered(void);
extern int tls_ungetc(int);
-extern int tls_write(BOOL, const uschar *, size_t);
+extern int tls_write(BOOL, const uschar *, size_t, BOOL);
extern uschar *tls_validate_require_cipher(void);
extern void tls_version_report(FILE *);
# ifndef USE_GNUTLS
@@ -102,26 +104,28 @@ extern uschar *auth_xtextencode(uschar *, int);
extern int auth_xtextdecode(uschar *, uschar **);
extern uschar *b64encode(uschar *, int);
-extern int b64decode(uschar *, uschar **);
+extern int b64decode(const uschar *, uschar **);
extern int bdat_getc(unsigned);
+extern uschar *bdat_getbuf(unsigned *);
extern int bdat_ungetc(int);
extern void bdat_flush_data(void);
extern void bits_clear(unsigned int *, size_t, int *);
extern void bits_set(unsigned int *, size_t, int *);
-extern void cancel_cutthrough_connection(const char *);
+extern void cancel_cutthrough_connection(BOOL, const uschar *);
extern int check_host(void *, const uschar *, const uschar **, uschar **);
extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...);
extern pid_t child_open_uid(const uschar **, const uschar **, int,
uid_t *, gid_t *, int *, int *, uschar *, BOOL);
extern BOOL cleanup_environment(void);
+extern void cutthrough_data_puts(uschar *, int);
+extern void cutthrough_data_put_nl(void);
extern uschar *cutthrough_finaldot(void);
extern BOOL cutthrough_flush_send(void);
extern BOOL cutthrough_headers_send(void);
extern BOOL cutthrough_predata(void);
-extern BOOL cutthrough_puts(uschar *, int);
-extern BOOL cutthrough_put_nl(void);
+extern void release_cutthrough_connection(const uschar *);
extern void daemon_go(void);
@@ -149,10 +153,11 @@ extern int deliver_split_address(address_item *);
extern void deliver_succeeded(address_item *);
extern uschar *deliver_get_sender_address (uschar *id);
+extern void delivery_re_exec(int);
extern BOOL directory_make(const uschar *, const uschar *, int, BOOL);
#ifndef DISABLE_DKIM
-extern BOOL dkim_transport_write_message(int, transport_ctx *,
+extern BOOL dkim_transport_write_message(transport_ctx *,
struct ob_dkim *, const uschar ** errstr);
#endif
extern dns_address *dns_address_from_rr(dns_answer *, dns_record *);
@@ -179,7 +184,6 @@ extern const uschar * exim_errstr(int);
extern void exim_exit(int);
extern void exim_nullstd(void);
extern void exim_setugid(uid_t, gid_t, BOOL, uschar *);
-extern int exim_tvcmp(struct timeval *, struct timeval *);
extern void exim_wait_tick(struct timeval *, int);
extern int exp_bool(address_item *addr,
uschar *mtype, uschar *mname, unsigned dgb_opt, uschar *oname, BOOL bvalue,
@@ -231,9 +235,9 @@ extern uschar *imap_utf7_encode(uschar *, const uschar *,
extern void invert_address(uschar *, uschar *);
extern int ip_addr(void *, int, const uschar *, int);
extern int ip_bind(int, int, uschar *, int);
-extern int ip_connect(int, int, const uschar *, int, int, BOOL);
+extern int ip_connect(int, int, const uschar *, int, int, const blob *);
extern int ip_connectedsocket(int, const uschar *, int, int,
- int, host_item *, uschar **);
+ int, host_item *, uschar **, const blob *);
extern int ip_get_address_family(int);
extern void ip_keepalive(int, const uschar *, BOOL);
extern int ip_recv(int, uschar *, int, int);
@@ -250,7 +254,7 @@ extern int log_create(uschar *);
extern int log_create_as_exim(uschar *);
extern void log_close_all(void);
-extern macro_item * macro_create(const uschar *, const uschar *, BOOL, BOOL);
+extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
extern void mainlog_close(void);
#ifdef WITH_CONTENT_SCAN
extern int malware(const uschar *, int);
@@ -259,6 +263,7 @@ extern void malware_init(void);
#endif
extern int match_address_list(const uschar *, BOOL, BOOL, const uschar **,
unsigned int *, int, int, const uschar **);
+extern int match_address_list_basic(const uschar *, const uschar **, int);
extern int match_check_list(const uschar **, int, tree_node **, unsigned int **,
int(*)(void *, const uschar *, const uschar **, uschar **), void *, int,
const uschar *, const uschar **);
@@ -323,8 +328,6 @@ extern void readconf_driver_init(uschar *, driver_instance **,
extern uschar *readconf_find_option(void *);
extern void readconf_main(BOOL);
extern void readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *);
-extern void readconf_options_routers(void);
-extern void readconf_options_transports(void);
extern void readconf_print(uschar *, uschar *, BOOL);
extern uschar *readconf_printtime(int);
extern uschar *readconf_readname(uschar *, int, uschar *);
@@ -390,10 +393,11 @@ extern int sieve_interpret(uschar *, int, uschar *, uschar *, uschar *,
extern void sigalrm_handler(int);
extern BOOL smtp_buffered(void);
extern void smtp_closedown(uschar *);
-extern int smtp_connect(host_item *, int, int, uschar *, int,
+extern uschar *smtp_cmd_hist(void);
+extern int smtp_connect(host_item *, int, uschar *, int,
transport_instance *);
extern int smtp_sock_connect(host_item *, int, int, uschar *,
- transport_instance * tb, int);
+ transport_instance * tb, int, const blob *);
extern int smtp_feof(void);
extern int smtp_ferror(void);
extern uschar *smtp_get_connection_info(void);
@@ -401,22 +405,25 @@ extern BOOL smtp_get_interface(uschar *, int, address_item *,
uschar **, uschar *);
extern BOOL smtp_get_port(uschar *, address_item *, int *, uschar *);
extern int smtp_getc(unsigned);
+extern uschar *smtp_getbuf(unsigned *);
extern void smtp_get_cache(void);
extern int smtp_handle_acl_fail(int, int, uschar *, uschar *);
extern void smtp_log_no_mail(void);
extern void smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
+extern void smtp_proxy_tls(uschar *, size_t, int, int);
extern BOOL smtp_read_response(smtp_inblock *, uschar *, int, int, int);
extern void smtp_respond(uschar *, int, BOOL, uschar *);
extern void smtp_notquit_exit(uschar *, uschar *, uschar *, ...);
+extern void smtp_port_for_connect(host_item *, int);
extern void smtp_send_prohibition_message(int, uschar *);
extern int smtp_setup_msg(void);
extern BOOL smtp_start_session(void);
extern int smtp_ungetc(int);
extern BOOL smtp_verify_helo(void);
-extern int smtp_write_command(smtp_outblock *, BOOL, const char *, ...) PRINTF_FUNCTION(3,4);
+extern int smtp_write_command(smtp_outblock *, int, const char *, ...) PRINTF_FUNCTION(3,4);
#ifdef WITH_CONTENT_SCAN
extern int spam(const uschar **);
-extern FILE *spool_mbox(unsigned long *, const uschar *);
+extern FILE *spool_mbox(unsigned long *, const uschar *, uschar **);
#endif
extern BOOL spool_move_message(uschar *, uschar *, uschar *, uschar *);
extern uschar *spool_dname(const uschar *, uschar *);
@@ -430,12 +437,12 @@ extern int stdin_getc(unsigned);
extern int stdin_feof(void);
extern int stdin_ferror(void);
extern int stdin_ungetc(int);
-extern uschar *string_append(uschar *, int *, int *, int, ...);
-extern uschar *string_append_listele(uschar *, uschar, const uschar *);
-extern uschar *string_append_listele_n(uschar *, uschar, const uschar *, unsigned);
+extern uschar *string_append(uschar *, int *, int *, int, ...) WARN_UNUSED_RESULT;
+extern uschar *string_append_listele(uschar *, int *, int *, uschar, const uschar *) WARN_UNUSED_RESULT;
+extern uschar *string_append_listele_n(uschar *, int *, int *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT;
extern uschar *string_base62(unsigned long int);
-extern uschar *string_cat(uschar *, int *, int *, const uschar *);
-extern uschar *string_catn(uschar *, int *, int *, const uschar *, int);
+extern uschar *string_cat(uschar *, int *, int *, const uschar *) WARN_UNUSED_RESULT;
+extern uschar *string_catn(uschar *, int *, int *, const uschar *, int) WARN_UNUSED_RESULT;
extern int string_compare_by_pointer(const void *, const void *);
extern uschar *string_copy_dnsdomain(uschar *);
extern uschar *string_copy_malloc(const uschar *);
@@ -453,6 +460,7 @@ extern uschar *string_nextinlist(const uschar **, int *, uschar *, int);
extern uschar *string_open_failed(int, const char *, ...) PRINTF_FUNCTION(2,3);
extern const uschar *string_printing2(const uschar *, BOOL);
extern uschar *string_split_message(uschar *);
+extern uschar *string_timesince(struct timeval *);
extern uschar *string_unprinting(uschar *);
#ifdef SUPPORT_I18N
extern uschar *string_address_utf8_to_alabel(const uschar *, uschar **);
@@ -466,23 +474,27 @@ extern int strcmpic(const uschar *, const uschar *);
extern int strncmpic(const uschar *, const uschar *, int);
extern uschar *strstric(uschar *, uschar *, BOOL);
+extern void timesince(struct timeval * diff, struct timeval * then);
+extern void tls_modify_variables(tls_support *);
extern uschar *tod_stamp(int);
-extern void tls_modify_variables(tls_support *);
extern BOOL transport_check_waiting(const uschar *, const uschar *, int, uschar *,
BOOL *, oicf, void*);
extern void transport_init(void);
+extern void transport_do_pass_socket(const uschar *, const uschar *,
+ const uschar *, uschar *, int);
extern BOOL transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *,
int);
extern uschar *transport_rcpt_address(address_item *, BOOL);
extern BOOL transport_set_up_command(const uschar ***, uschar *,
BOOL, int, address_item *, uschar *, uschar **);
extern void transport_update_waiting(host_item *, uschar *);
-extern BOOL transport_write_block(int, uschar *, int);
+extern BOOL transport_write_block(transport_ctx *, uschar *, int, BOOL);
+extern void transport_write_reset(int);
extern BOOL transport_write_string(int, const char *, ...);
-extern BOOL transport_headers_send(int, transport_ctx *,
- BOOL (*)(int, transport_ctx *, uschar *, int));
-extern BOOL transport_write_message(int, transport_ctx *, int);
+extern BOOL transport_headers_send(transport_ctx *,
+ BOOL (*)(transport_ctx *, uschar *, int));
+extern BOOL transport_write_message(transport_ctx *, int);
extern void tree_add_duplicate(uschar *, address_item *);
extern void tree_add_nonrecipient(uschar *);
extern void tree_add_unusable(host_item *);
@@ -516,6 +528,7 @@ extern BOOL verify_sender(int *, uschar **);
extern BOOL verify_sender_preliminary(int *, uschar **);
extern void version_init(void);
+extern BOOL write_chunk(transport_ctx *, uschar *, int);
extern ssize_t write_to_fd_buf(int, const uschar *, size_t);
/* vi: aw
diff --git a/src/src/globals.c b/src/src/globals.c
index f3e4bad96..57041fc4e 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -101,38 +101,38 @@ cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. */
tls_support tls_in = {
- -1, /* tls_active */
- 0, /* tls_bits */
- FALSE,/* tls_certificate_verified */
+ .active = -1,
+ .bits = 0,
+ .certificate_verified = FALSE,
#ifdef EXPERIMENTAL_DANE
- FALSE,/* dane_verified */
- 0, /* tlsa_usage */
+ .dane_verified = FALSE,
+ .tlsa_usage = 0,
#endif
- NULL, /* tls_cipher */
- FALSE,/* tls_on_connect */
- NULL, /* tls_on_connect_ports */
- NULL, /* tls_ourcert */
- NULL, /* tls_peercert */
- NULL, /* tls_peerdn */
- NULL, /* tls_sni */
- 0 /* tls_ocsp */
+ .cipher = NULL,
+ .on_connect = FALSE,
+ .on_connect_ports = NULL,
+ .ourcert = NULL,
+ .peercert = NULL,
+ .peerdn = NULL,
+ .sni = NULL,
+ .ocsp = OCSP_NOT_REQ
};
tls_support tls_out = {
- -1, /* tls_active */
- 0, /* tls_bits */
- FALSE,/* tls_certificate_verified */
+ .active = -1,
+ .bits = 0,
+ .certificate_verified = FALSE,
#ifdef EXPERIMENTAL_DANE
- FALSE,/* dane_verified */
- 0, /* tlsa_usage */
+ .dane_verified = FALSE,
+ .tlsa_usage = 0,
#endif
- NULL, /* tls_cipher */
- FALSE,/* tls_on_connect */
- NULL, /* tls_on_connect_ports */
- NULL, /* tls_ourcert */
- NULL, /* tls_peercert */
- NULL, /* tls_peerdn */
- NULL, /* tls_sni */
- 0 /* tls_ocsp */
+ .cipher = NULL,
+ .on_connect = FALSE,
+ .on_connect_ports = NULL,
+ .ourcert = NULL,
+ .peercert = NULL,
+ .peerdn = NULL,
+ .sni = NULL,
+ .ocsp = OCSP_NOT_REQ
};
uschar *dsn_envid = NULL;
@@ -182,10 +182,12 @@ const pcre *regex_UTF8 = NULL;
incoming TCP/IP. The defaults use stdin. We never need these for any
stand-alone tests. */
-#ifndef STAND_ALONE
+#if !defined(STAND_ALONE) && !defined(MACRO_PREDEF)
int (*lwr_receive_getc)(unsigned) = stdin_getc;
+uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
int (*lwr_receive_ungetc)(int) = stdin_ungetc;
int (*receive_getc)(unsigned) = stdin_getc;
+uschar * (*receive_getbuf)(unsigned *) = NULL;
void (*receive_get_cache)(void)= NULL;
int (*receive_ungetc)(int) = stdin_ungetc;
int (*receive_feof)(void) = stdin_feof;
@@ -326,78 +328,82 @@ uschar *add_environment = NULL;
address_item *addr_duplicate = NULL;
address_item address_defaults = {
- NULL, /* next */
- NULL, /* parent */
- NULL, /* first */
- NULL, /* dupof */
- NULL, /* start_router */
- NULL, /* router */
- NULL, /* transport */
- NULL, /* host_list */
- NULL, /* host_used */
- NULL, /* fallback_hosts */
- NULL, /* reply */
- NULL, /* retries */
- NULL, /* address */
- NULL, /* unique */
- NULL, /* cc_local_part */
- NULL, /* lc_local_part */
- NULL, /* local_part */
- NULL, /* prefix */
- NULL, /* suffix */
- NULL, /* domain */
- NULL, /* address_retry_key */
- NULL, /* domain_retry_key */
- NULL, /* current_dir */
- NULL, /* home_dir */
- NULL, /* message */
- NULL, /* user_message */
- NULL, /* onetime_parent */
- NULL, /* pipe_expandn */
- NULL, /* return_filename */
- NULL, /* self_hostname */
- NULL, /* shadow_message */
+ .next = NULL,
+ .parent = NULL,
+ .first = NULL,
+ .dupof = NULL,
+ .start_router = NULL,
+ .router = NULL,
+ .transport = NULL,
+ .host_list = NULL,
+ .host_used = NULL,
+ .fallback_hosts = NULL,
+ .reply = NULL,
+ .retries = NULL,
+ .address = NULL,
+ .unique = NULL,
+ .cc_local_part = NULL,
+ .lc_local_part = NULL,
+ .local_part = NULL,
+ .prefix = NULL,
+ .suffix = NULL,
+ .domain = NULL,
+ .address_retry_key = NULL,
+ .domain_retry_key = NULL,
+ .current_dir = NULL,
+ .home_dir = NULL,
+ .message = NULL,
+ .user_message = NULL,
+ .onetime_parent = NULL,
+ .pipe_expandn = NULL,
+ .return_filename = NULL,
+ .self_hostname = NULL,
+ .shadow_message = NULL,
#ifdef SUPPORT_TLS
- NULL, /* cipher */
- NULL, /* ourcert */
- NULL, /* peercert */
- NULL, /* peerdn */
- OCSP_NOT_REQ, /* ocsp */
+ .cipher = NULL,
+ .ourcert = NULL,
+ .peercert = NULL,
+ .peerdn = NULL,
+ .ocsp = OCSP_NOT_REQ,
#endif
#ifdef EXPERIMENTAL_DSN_INFO
- NULL, /* smtp_greeting */
- NULL, /* helo_response */
+ .smtp_greeting = NULL,
+ .helo_response = NULL,
#endif
- NULL, /* authenticator */
- NULL, /* auth_id */
- NULL, /* auth_sndr */
- NULL, /* dsn_orcpt */
- 0, /* dsn_flags */
- 0, /* dsn_aware */
- (uid_t)(-1), /* uid */
- (gid_t)(-1), /* gid */
- 0, /* flags */
- { 0 }, /* domain_cache - any larger array should be zeroed */
- { 0 }, /* localpart_cache - ditto */
- -1, /* mode */
- 0, /* more_errno */
- ERRNO_UNKNOWNERROR, /* basic_errno */
- 0, /* child_count */
- -1, /* return_file */
- SPECIAL_NONE, /* special_action */
- DEFER, /* transport_return */
- { /* fields that are propagated to children */
- NULL, /* address_data */
- NULL, /* domain_data */
- NULL, /* localpart_data */
- NULL, /* errors_address */
- NULL, /* extra_headers */
- NULL, /* remove_headers */
+ .authenticator = NULL,
+ .auth_id = NULL,
+ .auth_sndr = NULL,
+ .dsn_orcpt = NULL,
+ .dsn_flags = 0,
+ .dsn_aware = 0,
+ .uid = (uid_t)(-1),
+ .gid = (gid_t)(-1),
+ .flags = { 0 },
+ .domain_cache = { 0 }, /* domain_cache - any larger array should be zeroed */
+ .localpart_cache = { 0 }, /* localpart_cache - ditto */
+ .mode = -1,
+ .more_errno = 0,
+ .delivery_usec = 0,
+ .basic_errno = ERRNO_UNKNOWNERROR,
+ .child_count = 0,
+ .return_file = -1,
+ .special_action = SPECIAL_NONE,
+ .transport_return = DEFER,
+ .prop = { /* fields that are propagated to children */
+ .address_data = NULL,
+ .domain_data = NULL,
+ .localpart_data = NULL,
+ .errors_address = NULL,
+ .extra_headers = NULL,
+ .remove_headers = NULL,
#ifdef EXPERIMENTAL_SRS
- NULL, /* srs_sender */
+ .srs_sender = NULL,
#endif
+ .ignore_error = FALSE,
#ifdef SUPPORT_I18N
- FALSE, /* utf8 */
+ .utf8_msg = FALSE,
+ .utf8_downcvt = FALSE,
+ .utf8_downcvt_maybe = FALSE
#endif
}
};
@@ -422,22 +428,22 @@ BOOL authentication_failed = FALSE;
auth_instance *auths = NULL;
uschar *auth_advertise_hosts = US"*";
auth_instance auth_defaults = {
- NULL, /* chain pointer */
- NULL, /* name */
- NULL, /* info */
- NULL, /* private options block pointer */
- NULL, /* driver_name */
- NULL, /* advertise_condition */
- NULL, /* client_condition */
- NULL, /* public_name */
- NULL, /* set_id */
- NULL, /* set_client_id */
- NULL, /* server_mail_auth_condition */
- NULL, /* server_debug_string */
- NULL, /* server_condition */
- FALSE, /* client */
- FALSE, /* server */
- FALSE /* advertised */
+ .next = NULL,
+ .name = NULL,
+ .info = NULL,
+ .options_block = NULL,
+ .driver_name = NULL,
+ .advertise_condition = NULL,
+ .client_condition = NULL,
+ .public_name = NULL,
+ .set_id = NULL,
+ .set_client_id = NULL,
+ .mail_auth_condition = NULL,
+ .server_debug_string = NULL,
+ .server_condition = NULL,
+ .client = FALSE,
+ .server = FALSE,
+ .advertised = FALSE
};
uschar *auth_defer_msg = US"reason not recorded";
@@ -470,6 +476,7 @@ int bmi_deliver = 1;
int bmi_run = 0;
uschar *bmi_verdicts = NULL;
#endif
+int bsmtp_transaction_linecount = 0;
int body_8bitmime = 0;
int body_linecount = 0;
int body_zerocount = 0;
@@ -481,7 +488,7 @@ int bounce_return_linesize_limit = 998;
BOOL bounce_return_message = TRUE;
int bounce_return_size_limit = 100*1024;
uschar *bounce_sender_authentication = NULL;
-int bsmtp_transaction_linecount = 0;
+uschar *builtin_macros_create_trigger = NULL;
uschar *callout_address = NULL;
int callout_cache_domain_positive_expire = 7*24*60*60;
@@ -508,6 +515,7 @@ uschar *client_authenticated_id = NULL;
uschar *client_authenticated_sender = NULL;
int clmacro_count = 0;
uschar *clmacros[MAX_CLMACROS];
+BOOL commandline_checks_require_admin = FALSE;
BOOL config_changed = FALSE;
FILE *config_file = NULL;
const uschar *config_filename = NULL;
@@ -529,19 +537,21 @@ uid_t config_uid = 0;
#endif
int connection_max_messages= -1;
+uschar *continue_proxy_cipher = NULL;
uschar *continue_hostname = NULL;
uschar *continue_host_address = NULL;
BOOL continue_more = FALSE;
int continue_sequence = 1;
-BOOL continue_proxy = FALSE;
uschar *continue_transport = NULL;
uschar *csa_status = NULL;
cut_t cutthrough = {
- FALSE, /* delivery: when to attempt */
- FALSE, /* on defer: spool locally */
- -1, /* fd: open connection */
- 0, /* nrcpt: number of addresses */
+ .callout_hold_only = FALSE, /* verify-only: normal delivery */
+ .delivery = FALSE, /* when to attempt */
+ .defer_pass = FALSE, /* on defer: spool locally */
+ .is_tls = FALSE, /* not a TLS conn yet */
+ .fd = -1, /* open connection */
+ .nrcpt = 0, /* number of addresses */
};
BOOL daemon_listen = FALSE;
@@ -757,19 +767,20 @@ int header_maxsize = HEADER_MAXSIZE;
int header_line_maxsize = 0;
header_name header_names[] = {
- { US"bcc", 3, TRUE, htype_bcc },
- { US"cc", 2, TRUE, htype_cc },
- { US"date", 4, TRUE, htype_date },
- { US"delivery-date", 13, FALSE, htype_delivery_date },
- { US"envelope-to", 11, FALSE, htype_envelope_to },
- { US"from", 4, TRUE, htype_from },
- { US"message-id", 10, TRUE, htype_id },
- { US"received", 8, FALSE, htype_received },
- { US"reply-to", 8, FALSE, htype_reply_to },
- { US"return-path", 11, FALSE, htype_return_path },
- { US"sender", 6, TRUE, htype_sender },
- { US"subject", 7, FALSE, htype_subject },
- { US"to", 2, TRUE, htype_to }
+ /* name len allow_resent htype */
+ { US"bcc", 3, TRUE, htype_bcc },
+ { US"cc", 2, TRUE, htype_cc },
+ { US"date", 4, TRUE, htype_date },
+ { US"delivery-date", 13, FALSE, htype_delivery_date },
+ { US"envelope-to", 11, FALSE, htype_envelope_to },
+ { US"from", 4, TRUE, htype_from },
+ { US"message-id", 10, TRUE, htype_id },
+ { US"received", 8, FALSE, htype_received },
+ { US"reply-to", 8, FALSE, htype_reply_to },
+ { US"return-path", 11, FALSE, htype_return_path },
+ { US"sender", 6, TRUE, htype_sender },
+ { US"subject", 7, FALSE, htype_subject },
+ { US"to", 2, TRUE, htype_to }
};
int header_names_size = sizeof(header_names)/sizeof(header_name);
@@ -887,6 +898,7 @@ bit_table log_options[] = { /* must be in alphabetical order */
BIT_TABLE(L, incoming_interface),
BIT_TABLE(L, incoming_port),
BIT_TABLE(L, lost_incoming_connection),
+ BIT_TABLE(L, millisec),
BIT_TABLE(L, outgoing_interface),
BIT_TABLE(L, outgoing_port),
BIT_TABLE(L, pid),
@@ -933,9 +945,6 @@ uschar *lookup_dnssec_authenticated = NULL;
int lookup_open_max = 25;
uschar *lookup_value = NULL;
-macro_item *macros = NULL;
-macro_item *mlast = NULL;
-BOOL macros_builtin_created = FALSE;
uschar *mailstore_basename = NULL;
#ifdef WITH_CONTENT_SCAN
uschar *malware_name = NULL; /* Virus Name */
@@ -1103,7 +1112,7 @@ uschar *received_header_text = US
int received_headers_max = 30;
uschar *received_protocol = NULL;
-int received_time = 0;
+struct timeval received_time = { 0, 0 };
uschar *recipient_data = NULL;
uschar *recipient_unqualified_hosts = NULL;
uschar *recipient_verify_failure = NULL;
@@ -1146,83 +1155,83 @@ uid_t root_uid = ROOT_UID;
router_instance *routers = NULL;
router_instance router_defaults = {
- NULL, /* chain pointer */
- NULL, /* name */
- NULL, /* info */
- NULL, /* private options block pointer */
- NULL, /* driver name */
+ .next = NULL,
+ .name = NULL,
+ .info = NULL,
+ .options_block = NULL,
+ .driver_name = NULL,
- NULL, /* address_data */
+ .address_data = NULL,
#ifdef EXPERIMENTAL_BRIGHTMAIL
- NULL, /* bmi_rule */
+ .bmi_rule = NULL,
#endif
- NULL, /* cannot_route_message */
- NULL, /* condition */
- NULL, /* current_directory */
- NULL, /* debug_string */
- NULL, /* domains */
- NULL, /* errors_to */
- NULL, /* expand_gid */
- NULL, /* expand_uid */
- NULL, /* expand_more */
- NULL, /* expand_unseen */
- NULL, /* extra_headers */
- NULL, /* fallback_hosts */
- NULL, /* home_directory */
- NULL, /* ignore_target_hosts */
- NULL, /* local_parts */
- NULL, /* pass_router_name */
- NULL, /* prefix */
- NULL, /* redirect_router_name */
- NULL, /* remove_headers */
- NULL, /* require_files */
- NULL, /* router_home_directory */
- US"freeze", /* self */
- NULL, /* senders */
- NULL, /* suffix */
- NULL, /* translate_ip_address */
- NULL, /* transport_name */
-
- TRUE, /* address_test */
+ .cannot_route_message = NULL,
+ .condition = NULL,
+ .current_directory = NULL,
+ .debug_string = NULL,
+ .domains = NULL,
+ .errors_to = NULL,
+ .expand_gid = NULL,
+ .expand_uid = NULL,
+ .expand_more = NULL,
+ .expand_unseen = NULL,
+ .extra_headers = NULL,
+ .fallback_hosts = NULL,
+ .home_directory = NULL,
+ .ignore_target_hosts = NULL,
+ .local_parts = NULL,
+ .pass_router_name = NULL,
+ .prefix = NULL,
+ .redirect_router_name = NULL,
+ .remove_headers = NULL,
+ .require_files = NULL,
+ .router_home_directory = NULL,
+ .self = US"freeze",
+ .senders = NULL,
+ .suffix = NULL,
+ .translate_ip_address = NULL,
+ .transport_name = NULL,
+
+ .address_test = TRUE,
#ifdef EXPERIMENTAL_BRIGHTMAIL
- FALSE, /* bmi_deliver_alternate */
- FALSE, /* bmi_deliver_default */
- FALSE, /* bmi_dont_deliver */
+ .bmi_deliver_alternate = FALSE,
+ .bmi_deliver_default = FALSE,
+ .bmi_dont_deliver = FALSE,
#endif
- TRUE, /* expn */
- FALSE, /* caseful_local_part */
- FALSE, /* check_local_user */
- FALSE, /* disable_logging */
- FALSE, /* fail_verify_recipient */
- FALSE, /* fail_verify_sender */
- FALSE, /* gid_set */
- FALSE, /* initgroups */
- TRUE_UNSET, /* log_as_local */
- TRUE, /* more */
- FALSE, /* pass_on_timeout */
- FALSE, /* prefix_optional */
- TRUE, /* repeat_use */
- TRUE_UNSET, /* retry_use_local_part - fudge "unset" */
- FALSE, /* same_domain_copy_routing */
- FALSE, /* self_rewrite */
- FALSE, /* suffix_optional */
- FALSE, /* verify_only */
- TRUE, /* verify_recipient */
- TRUE, /* verify_sender */
- FALSE, /* uid_set */
- FALSE, /* unseen */
- FALSE, /* dsn_lasthop */
-
- self_freeze, /* self_code */
- (uid_t)(-1), /* uid */
- (gid_t)(-1), /* gid */
-
- NULL, /* fallback_hostlist */
- NULL, /* transport instance */
- NULL, /* pass_router */
- NULL, /* redirect_router */
-
- { NULL, NULL }, /* dnssec_domains {require,request} */
+ .expn = TRUE,
+ .caseful_local_part = FALSE,
+ .check_local_user = FALSE,
+ .disable_logging = FALSE,
+ .fail_verify_recipient = FALSE,
+ .fail_verify_sender = FALSE,
+ .gid_set = FALSE,
+ .initgroups = FALSE,
+ .log_as_local = TRUE_UNSET,
+ .more = TRUE,
+ .pass_on_timeout = FALSE,
+ .prefix_optional = FALSE,
+ .repeat_use = TRUE,
+ .retry_use_local_part = TRUE_UNSET,
+ .same_domain_copy_routing = FALSE,
+ .self_rewrite = FALSE,
+ .suffix_optional = FALSE,
+ .verify_only = FALSE,
+ .verify_recipient = TRUE,
+ .verify_sender = TRUE,
+ .uid_set = FALSE,
+ .unseen = FALSE,
+ .dsn_lasthop = FALSE,
+
+ .self_code = self_freeze,
+ .uid = (uid_t)(-1),
+ .gid = (gid_t)(-1),
+
+ .fallback_hostlist = NULL,
+ .transport = NULL,
+ .pass_router = NULL,
+ .redirect_router = NULL,
+
+ .dnssec = { NULL, NULL }, /* dnssec_domains {require,request} */
};
uschar *router_name = NULL;
@@ -1303,7 +1312,7 @@ BOOL smtp_check_spool_space = TRUE;
int smtp_ch_index = 0;
uschar *smtp_cmd_argument = NULL;
uschar *smtp_cmd_buffer = NULL;
-time_t smtp_connection_start = 0;
+struct timeval smtp_connection_start = {0,0};
uschar smtp_connection_had[SMTP_HBUFF_SIZE];
int smtp_connect_backlog = 20;
double smtp_delay_mail = 0.0;
@@ -1360,6 +1369,8 @@ uschar *spf_smtp_comment = NULL;
BOOL split_spool_directory = FALSE;
uschar *spool_directory = US SPOOL_DIRECTORY
"\0<--------------Space to patch spool_directory->";
+BOOL spool_file_wireformat = FALSE;
+BOOL spool_wireformat = FALSE;
#ifdef EXPERIMENTAL_SRS
uschar *srs_config = NULL;
uschar *srs_db_address = NULL;
@@ -1406,7 +1417,12 @@ BOOL system_filter_uid_set = FALSE;
BOOL system_filtering = FALSE;
BOOL tcp_fastopen_ok = FALSE;
+blob tcp_fastopen_nodata = { .data = NULL, .len = 0 };
+BOOL tcp_in_fastopen = FALSE;
+BOOL tcp_in_fastopen_logged = FALSE;
BOOL tcp_nodelay = TRUE;
+BOOL tcp_out_fastopen = FALSE;
+BOOL tcp_out_fastopen_logged= FALSE;
#ifdef USE_TCP_WRAPPERS
uschar *tcp_wrappers_daemon_name = US TCP_WRAPPERS_DAEMON_NAME;
#endif
@@ -1418,59 +1434,59 @@ BOOL timestamps_utc = FALSE;
transport_instance *transports = NULL;
transport_instance transport_defaults = {
- NULL, /* chain pointer */
- NULL, /* name */
- NULL, /* info */
- NULL, /* private options block pointer */
- NULL, /* driver name */
- NULL, /* setup entry point */
- 1, /* batch_max */
- NULL, /* batch_id */
- NULL, /* home_dir */
- NULL, /* current_dir */
- NULL, /* expand-multi-domain */
- TRUE, /* multi-domain */
- FALSE, /* overrides_hosts */
- 100, /* max_addresses */
- 500, /* connection_max_messages */
- FALSE, /* deliver_as_creator */
- FALSE, /* disable_logging */
- FALSE, /* initgroups */
- FALSE, /* uid_set */
- FALSE, /* gid_set */
- (uid_t)(-1), /* uid */
- (gid_t)(-1), /* gid */
- NULL, /* expand_uid */
- NULL, /* expand_gid */
- NULL, /* warn_message */
- NULL, /* shadow */
- NULL, /* shadow_condition */
- NULL, /* filter_command */
- NULL, /* add_headers */
- NULL, /* remove_headers */
- NULL, /* return_path */
- NULL, /* debug_string */
- NULL, /* max_parallel */
- NULL, /* message_size_limit */
- NULL, /* headers_rewrite */
- NULL, /* rewrite_rules */
- 0, /* rewrite_existflags */
- 300, /* filter_timeout */
- FALSE, /* body_only */
- FALSE, /* delivery_date_add */
- FALSE, /* envelope_to_add */
- FALSE, /* headers_only */
- FALSE, /* rcpt_include_affixes */
- FALSE, /* return_path_add */
- FALSE, /* return_output */
- FALSE, /* return_fail_output */
- FALSE, /* log_output */
- FALSE, /* log_fail_output */
- FALSE, /* log_defer_output */
- TRUE_UNSET /* retry_use_local_part: BOOL, but set neither
- 1 nor 0 so can detect unset */
+ .next = NULL,
+ .name = NULL,
+ .info = NULL,
+ .options_block = NULL,
+ .driver_name = NULL,
+ .setup = NULL,
+ .batch_max = 1,
+ .batch_id = NULL,
+ .home_dir = NULL,
+ .current_dir = NULL,
+ .expand_multi_domain = NULL,
+ .multi_domain = TRUE,
+ .overrides_hosts = FALSE,
+ .max_addresses = 100,
+ .connection_max_messages = 500,
+ .deliver_as_creator = FALSE,
+ .disable_logging = FALSE,
+ .initgroups = FALSE,
+ .uid_set = FALSE,
+ .gid_set = FALSE,
+ .uid = (uid_t)(-1),
+ .gid = (gid_t)(-1),
+ .expand_uid = NULL,
+ .expand_gid = NULL,
+ .warn_message = NULL,
+ .shadow = NULL,
+ .shadow_condition = NULL,
+ .filter_command = NULL,
+ .add_headers = NULL,
+ .remove_headers = NULL,
+ .return_path = NULL,
+ .debug_string = NULL,
+ .max_parallel = NULL,
+ .message_size_limit = NULL,
+ .headers_rewrite = NULL,
+ .rewrite_rules = NULL,
+ .rewrite_existflags = 0,
+ .filter_timeout = 300,
+ .body_only = FALSE,
+ .delivery_date_add = FALSE,
+ .envelope_to_add = FALSE,
+ .headers_only = FALSE,
+ .rcpt_include_affixes = FALSE,
+ .return_path_add = FALSE,
+ .return_output = FALSE,
+ .return_fail_output = FALSE,
+ .log_output = FALSE,
+ .log_fail_output = FALSE,
+ .log_defer_output = FALSE,
+ .retry_use_local_part = TRUE_UNSET, /* retry_use_local_part: BOOL, but set neither
+ 1 nor 0 so can detect unset */
#ifndef DISABLE_EVENT
- ,NULL /* event_action */
+ .event_action = NULL
#endif
};
diff --git a/src/src/globals.h b/src/src/globals.h
index 750a960eb..2957587b0 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -137,8 +137,10 @@ extern uschar *dsn_advertise_hosts; /* host for which TLS is advertised */
incoming TCP/IP. */
extern int (*lwr_receive_getc)(unsigned);
+extern uschar * (*lwr_receive_getbuf)(unsigned *);
extern int (*lwr_receive_ungetc)(int);
extern int (*receive_getc)(unsigned);
+extern uschar * (*receive_getbuf)(unsigned *);
extern void (*receive_get_cache)(void);
extern int (*receive_ungetc)(int);
extern int (*receive_feof)(void);
@@ -246,6 +248,7 @@ extern int bmi_deliver; /* Flag that determines if the message sh
extern int bmi_run; /* Flag that determines if message should be run through Brightmail server */
extern uschar *bmi_verdicts; /* BASE64-encoded verdicts with recipient lists */
#endif
+extern int bsmtp_transaction_linecount; /* Start of last transaction */
extern int body_8bitmime; /* sender declared BODY= ; 7=7BIT, 8=8BITMIME */
extern uschar *bounce_message_file; /* Template file */
extern uschar *bounce_message_text; /* One-liner */
@@ -255,7 +258,7 @@ extern int bounce_return_linesize_limit; /* Max line length in return */
extern BOOL bounce_return_message; /* Include message in bounce */
extern int bounce_return_size_limit; /* Max amount to return */
extern uschar *bounce_sender_authentication; /* AUTH address for bounces */
-extern int bsmtp_transaction_linecount; /* Start of last transaction */
+extern uschar *builtin_macros_create_trigger; /* config file line causing lazy-create */
extern uschar *callout_address; /* Address used for a malware/spamd/verify etc. callout */
extern int callout_cache_domain_positive_expire; /* Time for positive domain callout cache records to expire */
@@ -279,6 +282,7 @@ extern uschar *client_authenticated_id; /* "login" name used for SMTP AUTH *
extern uschar *client_authenticated_sender; /* AUTH option to SMTP MAIL FROM (not yet used) */
extern int clmacro_count; /* Number of command line macros */
extern uschar *clmacros[]; /* Copy of them, for re-exec */
+extern BOOL commandline_checks_require_admin; /* belt and braces for insecure setups */
extern int connection_max_messages;/* Max down one SMTP connection */
extern BOOL config_changed; /* True if -C used */
extern FILE *config_file; /* Configuration file */
@@ -289,21 +293,27 @@ extern uschar *config_main_filelist; /* List of possible config files */
extern uschar *config_main_filename; /* File name actually used */
extern uschar *config_main_directory; /* Directory where the main config file was found */
extern uid_t config_uid; /* Additional owner */
+extern uschar *continue_proxy_cipher; /* TLS cipher for proxied continued delivery */
extern uschar *continue_hostname; /* Host for continued delivery */
extern uschar *continue_host_address; /* IP address for ditto */
extern BOOL continue_more; /* Flag more addresses waiting */
extern int continue_sequence; /* Sequence num for continued delivery */
-extern BOOL continue_proxy; /* Continued delivery is proxied for TLS */
extern uschar *continue_transport; /* Transport for continued delivery */
extern uschar *csa_status; /* Client SMTP Authorization result */
typedef struct {
+ unsigned callout_hold_only:1; /* Conn is only for verify callout */
unsigned delivery:1; /* When to attempt */
unsigned defer_pass:1; /* Pass 4xx to caller rather than spooling */
+ unsigned is_tls:1; /* Conn has TLS active */
int fd; /* Open connection */
int nrcpt; /* Count of addresses */
+ uschar * transport; /* Name of transport */
uschar * interface; /* (address of) */
+ uschar * snd_ip; /* sending_ip_address */
+ int snd_port; /* sending_port */
+ unsigned peer_options; /* smtp_peer_options */
host_item host; /* Host used */
address_item addr; /* (Chain of) addresses */
} cut_t;
@@ -555,7 +565,6 @@ extern uschar *lookup_value; /* Value looked up from file */
extern macro_item *macros; /* Configuration macros */
extern macro_item *mlast; /* Last item in macro list */
-extern BOOL macros_builtin_created; /* Flag for lazy-create */
extern uschar *mailstore_basename; /* For mailstore deliveries */
#ifdef WITH_CONTENT_SCAN
extern uschar *malware_name; /* Name of virus or malware ("W32/Klez-H") */
@@ -712,7 +721,7 @@ extern int received_count; /* Count of Received: headers */
extern uschar *received_for; /* For "for" field */
extern uschar *received_header_text; /* Definition of Received: header */
extern int received_headers_max; /* Max count of Received: headers */
-extern int received_time; /* Time the message was received */
+extern struct timeval received_time; /* Time the message was received */
extern uschar *recipient_data; /* lookup data for recipients */
extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */
extern uschar *recipient_verify_failure; /* What went wrong */
@@ -811,7 +820,7 @@ extern BOOL smtp_check_spool_space; /* TRUE to check SMTP SIZE value */
extern int smtp_ch_index; /* Index in smtp_connection_had */
extern uschar *smtp_cmd_argument; /* For all SMTP commands */
extern uschar *smtp_cmd_buffer; /* SMTP command buffer */
-extern time_t smtp_connection_start; /* Start time of SMTP connection */
+extern struct timeval smtp_connection_start; /* Start time of SMTP connection */
extern uschar smtp_connection_had[]; /* Recent SMTP commands */
extern int smtp_connect_backlog; /* Max backlog permitted */
extern double smtp_delay_mail; /* Current MAIL delay */
@@ -865,6 +874,8 @@ extern uschar *spf_smtp_comment; /* spf comment to include in SMTP reply *
#endif
extern BOOL split_spool_directory; /* TRUE to use multiple subdirs */
extern uschar *spool_directory; /* Name of spool directory */
+extern BOOL spool_file_wireformat; /* current -D file has CRLF rather than NL */
+extern BOOL spool_wireformat; /* can write wireformat -D files */
#ifdef EXPERIMENTAL_SRS
extern uschar *srs_config; /* SRS config secret:max age:hash length:use timestamp:use hash */
extern uschar *srs_db_address; /* SRS db address */
@@ -911,7 +922,12 @@ extern BOOL system_filter_uid_set; /* TRUE if uid set */
extern BOOL system_filtering; /* TRUE when running system filter */
extern BOOL tcp_fastopen_ok; /* appears to be supported by kernel */
+extern blob tcp_fastopen_nodata; /* for zero-data TFO connect requests */
+extern BOOL tcp_in_fastopen; /* conn used fastopen */
+extern BOOL tcp_in_fastopen_logged; /* one-time logging */
extern BOOL tcp_nodelay; /* Controls TCP_NODELAY on daemon */
+extern BOOL tcp_out_fastopen; /* conn used fastopen */
+extern BOOL tcp_out_fastopen_logged; /* one-time logging */
#ifdef USE_TCP_WRAPPERS
extern uschar *tcp_wrappers_daemon_name; /* tcpwrappers daemon lookup name */
#endif
diff --git a/src/src/hash.c b/src/src/hash.c
index 7590d55b7..19ab1efd0 100644
--- a/src/src/hash.c
+++ b/src/src/hash.c
@@ -33,11 +33,14 @@ sha1;
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
- case HASH_SHA1: h->hashlen = 20; SHA1_Init (&h->u.sha1); break;
- case HASH_SHA256: h->hashlen = 32; SHA256_Init(&h->u.sha2); break;
- default: h->hashlen = 0; return FALSE;
+ case HASH_SHA1: h->hashlen = 20; SHA1_Init (&h->u.sha1); break;
+ case HASH_SHA2_256: h->hashlen = 32; SHA256_Init(&h->u.sha2_256); break;
+ case HASH_SHA2_384: h->hashlen = 48; SHA384_Init(&h->u.sha2_512); break;
+ case HASH_SHA2_512: h->hashlen = 64; SHA512_Init(&h->u.sha2_512); break;
+ default: h->hashlen = 0; return FALSE;
}
return TRUE;
}
@@ -48,10 +51,12 @@ exim_sha_update(hctx * h, const uschar * data, int len)
{
switch (h->method)
{
- case HASH_SHA1: SHA1_Update (&h->u.sha1, data, len); break;
- case HASH_SHA256: SHA256_Update(&h->u.sha2, data, len); break;
+ case HASH_SHA1: SHA1_Update (&h->u.sha1, data, len); break;
+ case HASH_SHA2_256: SHA256_Update(&h->u.sha2_256, data, len); break;
+ case HASH_SHA2_384: SHA384_Update(&h->u.sha2_512, data, len); break;
+ case HASH_SHA2_512: SHA512_Update(&h->u.sha2_512, data, len); break;
/* should be blocked by init not handling these, but be explicit to
- * guard against accidents later (and hush up clang -Wswitch) */
+ guard against accidents later (and hush up clang -Wswitch) */
default: assert(0);
}
}
@@ -63,8 +68,10 @@ exim_sha_finish(hctx * h, blob * b)
b->data = store_get(b->len = h->hashlen);
switch (h->method)
{
- case HASH_SHA1: SHA1_Final (b->data, &h->u.sha1); break;
- case HASH_SHA256: SHA256_Final(b->data, &h->u.sha2); break;
+ case HASH_SHA1: SHA1_Final (b->data, &h->u.sha1); break;
+ case HASH_SHA2_256: SHA256_Final(b->data, &h->u.sha2_256); break;
+ case HASH_SHA2_384: SHA384_Final(b->data, &h->u.sha2_512); break;
+ case HASH_SHA2_512: SHA512_Final(b->data, &h->u.sha2_512); break;
default: assert(0);
}
}
@@ -77,12 +84,17 @@ switch (h->method)
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
- case HASH_SHA1: h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break;
- case HASH_SHA256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break;
+ case HASH_SHA1: h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break;
+ case HASH_SHA2_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break;
+ case HASH_SHA2_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA384); break;
+ case HASH_SHA2_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA512); break;
#ifdef EXIM_HAVE_SHA3
case HASH_SHA3_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_256); break;
+ case HASH_SHA3_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_384); break;
+ case HASH_SHA3_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_512); break;
#endif
default: h->hashlen = 0; return FALSE;
}
@@ -112,10 +124,16 @@ gnutls_hash_output(h->sha, b->data);
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
- case HASH_SHA1: h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break;
- case HASH_SHA256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break;
+ case HASH_SHA1: h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break;
+ case HASH_SHA2_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break;
+ case HASH_SHA2_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA384, 0); break;
+ case HASH_SHA2_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA512, 0); break;
+ case HASH_SHA3_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA3_256, 0); break;
+ case HASH_SHA3_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA3_384, 0); break;
+ case HASH_SHA3_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA3_512, 0); break;
default: h->hashlen = 0; return FALSE;
}
return TRUE;
@@ -145,10 +163,11 @@ memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
BOOL
exim_sha_init(hctx * h, hashmethod m)
{
+/*XXX extend for sha512 */
switch (h->method = m)
{
case HASH_SHA1: h->hashlen = 20; sha1_starts(&h->u.sha1); break;
- case HASH_SHA256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break;
+ case HASH_SHA2_256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break;
default: h->hashlen = 0; return FALSE;
}
return TRUE;
@@ -161,7 +180,7 @@ exim_sha_update(hctx * h, const uschar * data, int len)
switch (h->method)
{
case HASH_SHA1: sha1_update(h->u.sha1, US data, len); break;
- case HASH_SHA256: sha2_update(h->u.sha2, US data, len); break;
+ case HASH_SHA2_256: sha2_update(h->u.sha2, US data, len); break;
}
}
@@ -173,7 +192,7 @@ b->data = store_get(b->len = h->hashlen);
switch (h->method)
{
case HASH_SHA1: sha1_finish(h->u.sha1, b->data); break;
- case HASH_SHA256: sha2_finish(h->u.sha2, b->data); break;
+ case HASH_SHA2_256: sha2_finish(h->u.sha2, b->data); break;
}
}
@@ -417,16 +436,6 @@ native_sha1_end(&h->sha1, NULL, 0, b->data);
#endif
-/******************************************************************************/
-
-/* Common to all library versions */
-int
-exim_sha_hashlen(hctx * h)
-{
-return h->method == HASH_SHA1 ? 20
- : h->method == HASH_SHA256 ? 32
- : 0;
-}
/******************************************************************************/
@@ -776,7 +785,7 @@ int main(void)
sha1 base;
int j;
int i = 0x01020304;
-uschar *ctest = (uschar *)(&i);
+uschar *ctest = US (&i);
uschar buffer[256];
uschar digest[20];
uschar s[41];
diff --git a/src/src/hash.h b/src/src/hash.h
index 09b65944d..337dc9910 100644
--- a/src/src/hash.h
+++ b/src/src/hash.h
@@ -12,7 +12,6 @@
#define HASH_H
#include "sha_ver.h"
-#include "blob.h"
#ifdef SHA_OPENSSL
# include <openssl/sha.h>
@@ -32,7 +31,11 @@
typedef enum hashmethod {
HASH_BADTYPE,
HASH_SHA1,
- HASH_SHA256,
+
+ HASH_SHA2_256,
+ HASH_SHA2_384,
+ HASH_SHA2_512,
+
HASH_SHA3_224,
HASH_SHA3_256,
HASH_SHA3_384,
@@ -46,7 +49,8 @@ typedef struct {
#ifdef SHA_OPENSSL
union {
SHA_CTX sha1; /* SHA1 block */
- SHA256_CTX sha2; /* SHA256 block */
+ SHA256_CTX sha2_256; /* SHA256 or 224 block */
+ SHA512_CTX sha2_512; /* SHA512 or 384 block */
} u;
#elif defined(SHA_GNUTLS)
@@ -70,7 +74,6 @@ typedef struct {
extern BOOL exim_sha_init(hctx *, hashmethod);
extern void exim_sha_update(hctx *, const uschar *a, int);
extern void exim_sha_finish(hctx *, blob *);
-extern int exim_sha_hashlen(hctx *);
#endif
/* End of File */
diff --git a/src/src/host.c b/src/src/host.c
index b5af8f92b..ec262805e 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -737,16 +737,14 @@ host_build_ifacelist(const uschar *list, uschar *name)
{
int sep = 0;
uschar *s;
-uschar buffer[64];
-ip_address_item *yield = NULL;
-ip_address_item *last = NULL;
-ip_address_item *next;
+ip_address_item * yield = NULL, * last = NULL, * next;
-while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
+while ((s = string_nextinlist(&list, &sep, NULL, 0)))
{
int ipv;
int port = host_address_extract_port(s); /* Leaves just the IP address */
- if ((ipv = string_is_ip_address(s, NULL)) == 0)
+
+ if (!(ipv = string_is_ip_address(s, NULL)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s",
s, name);
@@ -764,7 +762,9 @@ while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
next->port = port;
next->v6_include_v4 = FALSE;
- if (yield == NULL) yield = last = next; else
+ if (!yield)
+ yield = last = next;
+ else
{
last->next = next;
last = next;
@@ -919,21 +919,21 @@ if (type < 0)
if (family == AF_INET6)
{
struct sockaddr_in6 *sk = (struct sockaddr_in6 *)arg;
- yield = (uschar *)inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
+ yield = US inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
sizeof(addr_buffer));
if (portptr != NULL) *portptr = ntohs(sk->sin6_port);
}
else
{
struct sockaddr_in *sk = (struct sockaddr_in *)arg;
- yield = (uschar *)inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
+ yield = US inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
sizeof(addr_buffer));
if (portptr != NULL) *portptr = ntohs(sk->sin_port);
}
}
else
{
- yield = (uschar *)inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
+ yield = US inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
}
/* If the result is a mapped IPv4 address, show it in V4 format. */
@@ -1160,10 +1160,7 @@ tt--; /* lose final separator */
if (mask < 0)
*tt = 0;
else
- {
- sprintf(CS tt, "/%d", mask);
- while (*tt) tt++;
- }
+ tt += sprintf(CS tt, "/%d", mask);
return tt - buffer;
}
@@ -1587,7 +1584,7 @@ if (hosts->h_name == NULL || hosts->h_name[0] == 0 || hosts->h_name[0] == '.')
/* Copy and lowercase the name, which is in static storage in many systems.
Put it in permanent memory. */
-s = (uschar *)hosts->h_name;
+s = US hosts->h_name;
len = Ustrlen(s) + 1;
t = sender_host_name = store_get_perm(len);
while (*s != 0) *t++ = tolower(*s++);
@@ -1742,7 +1739,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
truncated and dn_expand may fail. */
if (dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen,
- (uschar *)(rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0)
+ US (rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0)
{
log_write(0, LOG_MAIN, "host name alias list truncated for %s",
sender_host_address);
@@ -2099,7 +2096,7 @@ for (i = 1; i <= times;
if (hostdata->h_name[0] != 0 &&
Ustrcmp(host->name, hostdata->h_name) != 0)
- host->name = string_copy_dnsdomain((uschar *)hostdata->h_name);
+ host->name = string_copy_dnsdomain(US hostdata->h_name);
if (fully_qualified_name != NULL) *fully_qualified_name = host->name;
/* Get the list of addresses. IPv4 and IPv6 addresses can be distinguished
diff --git a/src/src/ip.c b/src/src/ip.c
index bf564662d..266eaf414 100644
--- a/src/src/ip.c
+++ b/src/src/ip.c
@@ -175,14 +175,15 @@ Arguments:
address the remote address, in text form
port the remote port
timeout a timeout (zero for indefinite timeout)
- fastopen TRUE iff TCP_FASTOPEN can be used
+ fastopen non-null iff TCP_FASTOPEN can be used; may indicate early-data to
+ be sent in SYN segment
Returns: 0 on success; -1 on failure, with errno set
*/
int
ip_connect(int sock, int af, const uschar *address, int port, int timeout,
- BOOL fastopen)
+ const blob * fastopen)
{
struct sockaddr_in s_in4;
struct sockaddr *s_ptr;
@@ -228,25 +229,47 @@ if (timeout > 0) alarm(timeout);
/* TCP Fast Open, if the system has a cookie from a previous call to
this peer, can send data in the SYN packet. The peer can send data
before it gets our ACK of its SYN,ACK - the latter is useful for
-the SMTP banner. Is there any usage where the former might be?
-We might extend the ip_connect() args for data if so. For now,
-connect in FASTOPEN mode but with zero data.
-*/
+the SMTP banner. Other (than SMTP) cases of TCP connections can
+possibly use the data-on-syn, so support that too. */
if (fastopen)
{
- if ( (rc = sendto(sock, NULL, 0, MSG_FASTOPEN, s_ptr, s_len)) < 0
- && errno == EOPNOTSUPP
- )
+ if ((rc = sendto(sock, fastopen->data, fastopen->len,
+ MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
+ {
+ DEBUG(D_transport|D_v)
+ debug_printf("TCP_FASTOPEN mode connection, with data\n");
+ tcp_out_fastopen = TRUE;
+ }
+ else if (errno == EINPROGRESS) /* expected for nonready peer */
+ {
+ if (!fastopen->data)
+ {
+ DEBUG(D_transport|D_v)
+ debug_printf("TCP_FASTOPEN mode connection, no data\n");
+ tcp_out_fastopen = TRUE;
+ rc = 0;
+ }
+ else if ( (rc = send(sock, fastopen->data, fastopen->len, 0)) < 0
+ && errno == EINPROGRESS) /* expected for nonready peer */
+ rc = 0;
+ }
+ else if(errno == EOPNOTSUPP)
{
DEBUG(D_transport)
debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
- rc = connect(sock, s_ptr, s_len);
+ goto legacy_connect;
}
}
else
#endif
- rc = connect(sock, s_ptr, s_len);
+ {
+legacy_connect:
+ if ((rc = connect(sock, s_ptr, s_len)) >= 0)
+ if ( fastopen && fastopen->data && fastopen->len
+ && send(sock, fastopen->data, fastopen->len, 0) < 0)
+ rc = -1;
+ }
save_errno = errno;
alarm(0);
@@ -289,21 +312,22 @@ Arguments:
address the remote address, in text form
portlo,porthi the remote port range
timeout a timeout
- connhost if not NULL, host_item filled in with connection details
+ connhost if not NULL, host_item to be filled in with connection details
errstr pointer for allocated string on error
+ fastopen with SOCK_STREAM, if non-null, request TCP Fast Open.
+ Additionally, optional early-data to send
Return:
socket fd, or -1 on failure (having allocated an error string)
*/
int
ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
- int timeout, host_item * connhost, uschar ** errstr)
+ int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen)
{
int namelen, port;
host_item shost;
host_item *h;
int af = 0, fd, fd4 = -1, fd6 = -1;
-BOOL fastopen = tcp_fastopen_ok && type == SOCK_STREAM;
shost.next = NULL;
shost.address = NULL;
@@ -381,6 +405,7 @@ bad:
}
+/*XXX TFO? */
int
ip_tcpsocket(const uschar * hostport, uschar ** errstr, int tmo)
{
@@ -401,7 +426,7 @@ if (scan != 3)
}
return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
- tmo, NULL, errstr);
+ tmo, NULL, errstr, NULL);
}
int
@@ -457,7 +482,7 @@ ip_keepalive(int sock, const uschar *address, BOOL torf)
{
int fodder = 1;
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
- (uschar *)(&fodder), sizeof(fodder)) != 0)
+ US (&fodder), sizeof(fodder)) != 0)
log_write(0, LOG_MAIN, "setsockopt(SO_KEEPALIVE) on connection %s %s "
"failed: %s", torf? "to":"from", address, strerror(errno));
}
@@ -492,7 +517,7 @@ if (time_left <= 0)
do
{
- struct timeval tv = { time_left, 0 };
+ struct timeval tv = { .tv_sec = time_left, .tv_usec = 0 };
FD_ZERO (&select_inset);
FD_SET (fd, &select_inset);
diff --git a/src/src/local_scan.h b/src/src/local_scan.h
index bc4fc8e25..c03d87032 100644
--- a/src/src/local_scan.h
+++ b/src/src/local_scan.h
@@ -186,8 +186,8 @@ extern void receive_add_recipient(uschar *, int);
extern BOOL receive_remove_recipient(uschar *);
extern uschar *rfc2047_decode(uschar *, BOOL, uschar *, int, int *, uschar **);
extern int smtp_fflush(void);
-extern void smtp_printf(const char *, ...) PRINTF_FUNCTION(1,2);
-extern void smtp_vprintf(const char *, va_list);
+extern void smtp_printf(const char *, BOOL, ...) PRINTF_FUNCTION(1,3);
+extern void smtp_vprintf(const char *, BOOL, va_list);
extern uschar *string_copy(const uschar *);
extern uschar *string_copyn(const uschar *, int);
extern uschar *string_sprintf(const char *, ...) ALMOST_PRINTF(1,2);
diff --git a/src/src/log.c b/src/src/log.c
index ddd71377e..fd72bb1ad 100644
--- a/src/src/log.c
+++ b/src/src/log.c
@@ -147,7 +147,7 @@ int linecount = 0;
if (running_in_test_harness) return;
-if (!syslog_timestamp) s += log_timezone? 26 : 20;
+if (!syslog_timestamp) s += log_timezone ? 26 : 20;
if (!syslog_pid && LOGGING(pid))
memmove(s + pid_position[0], s + pid_position[1], pid_position[1] - pid_position[0]);
@@ -223,10 +223,10 @@ Returns: The function does not return
static void
die(uschar *s1, uschar *s2)
{
-if (s1 != NULL)
+if (s1)
{
write_syslog(LOG_CRIT, s1);
- if (debug_file != NULL) debug_printf("%s\n", s1);
+ if (debug_file) debug_printf("%s\n", s1);
if (log_stderr != NULL && log_stderr != debug_file)
fprintf(log_stderr, "%s\n", s1);
}
@@ -272,7 +272,7 @@ if (fd < 0 && errno == ENOENT)
*lastslash = 0;
created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
DEBUG(D_any) debug_printf("%s log directory %s\n",
- created? "created" : "failed to create", name);
+ created ? "created" : "failed to create", name);
*lastslash = '/';
if (created) fd = Uopen(name,
#ifdef O_CLOEXEC
@@ -391,7 +391,7 @@ it gets statted to see if it has been cycled. With a datestamp, the datestamp
will be compared. The static slot for saving it is the same size as buffer,
and the text has been checked above to fit, so this use of strcpy() is OK. */
-if (type == lt_main)
+if (type == lt_main && string_datestamp_offset >= 0)
{
Ustrcpy(mainlog_name, buffer);
mainlog_datestamp = mainlog_name + string_datestamp_offset;
@@ -399,7 +399,7 @@ if (type == lt_main)
/* Ditto for the reject log */
-else if (type == lt_reject)
+else if (type == lt_reject && string_datestamp_offset >= 0)
{
Ustrcpy(rejectlog_name, buffer);
rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
@@ -446,10 +446,8 @@ else if (string_datestamp_offset >= 0)
/* If the file name is too long, it is an unrecoverable disaster */
if (!ok)
- {
die(US"exim: log file path too long: aborting",
US"Logging failure; please try later");
- }
/* We now have the file name. Try to open an existing file. After a successful
open, arrange for automatic closure on exec(), and then return. */
@@ -559,10 +557,7 @@ if ((flags & (LOG_CONFIG_FOR & ~LOG_CONFIG)) != 0)
}
if ((flags & (LOG_CONFIG_IN & ~LOG_CONFIG)) != 0)
- {
- sprintf(CS ptr, " in line %d of %s", config_lineno, config_filename);
- while (*ptr) ptr++;
- }
+ ptr += sprintf(CS ptr, " in line %d of %s", config_lineno, config_filename);
Ustrcpy(ptr, ":\n ");
return ptr + 4;
@@ -736,7 +731,7 @@ Returns: nothing
void
log_write(unsigned int selector, int flags, const char *format, ...)
{
-uschar *ptr;
+uschar * ptr;
int length;
int paniclogfd;
ssize_t written_len;
@@ -862,13 +857,12 @@ DEBUG(D_any|D_v)
}
}
- sprintf(CS ptr, "%s%s%s%s\n ",
+ ptr += sprintf(CS ptr, "%s%s%s%s\n ",
((flags & LOG_MAIN) != 0)? " MAIN" : "",
((flags & LOG_PANIC) != 0)? " PANIC" : "",
((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE)? " DIE" : "",
((flags & LOG_REJECT) != 0)? " REJECT" : "");
- while(*ptr) ptr++;
if ((flags & LOG_CONFIG) != 0) ptr = log_config_info(ptr, flags);
va_start(ap, format);
@@ -903,22 +897,17 @@ if (!write_rejectlog) flags &= ~LOG_REJECT;
when called by a utility. */
ptr = log_buffer;
-sprintf(CS ptr, "%s ", tod_stamp(tod_log));
-while(*ptr) ptr++;
+ptr += sprintf(CS ptr, "%s ", tod_stamp(tod_log));
if (LOGGING(pid))
{
- sprintf(CS ptr, "[%d] ", (int)getpid());
if (!syslog_pid) pid_position[0] = ptr - log_buffer; /* remember begin … */
- while (*ptr) ptr++;
+ ptr += sprintf(CS ptr, "[%d] ", (int)getpid());
if (!syslog_pid) pid_position[1] = ptr - log_buffer; /* … and end+1 of the PID */
}
if (really_exim && message_id[0] != 0)
- {
- sprintf(CS ptr, "%s ", message_id);
- while(*ptr) ptr++;
- }
+ ptr += sprintf(CS ptr, "%s ", message_id);
if ((flags & LOG_CONFIG) != 0) ptr = log_config_info(ptr, flags);
@@ -933,10 +922,7 @@ this way because it kind of fits with LOG_RECIPIENTS. */
if ((flags & LOG_SENDER) != 0 &&
ptr < log_buffer + LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender))
- {
- sprintf(CS ptr, " from <%s>", raw_sender);
- while (*ptr) ptr++;
- }
+ ptr += sprintf(CS ptr, " from <%s>", raw_sender);
/* Add list of recipients to the message if required; the raw list,
before rewriting, was saved in raw_recipients. There may be none, if an ACL
@@ -946,19 +932,16 @@ if ((flags & LOG_RECIPIENTS) != 0 && ptr < log_buffer + LOG_BUFFER_SIZE - 6 &&
raw_recipients_count > 0)
{
int i;
- sprintf(CS ptr, " for");
- while (*ptr) ptr++;
+ ptr += sprintf(CS ptr, " for");
for (i = 0; i < raw_recipients_count; i++)
{
- uschar *s = raw_recipients[i];
+ uschar * s = raw_recipients[i];
if (log_buffer + LOG_BUFFER_SIZE - ptr < Ustrlen(s) + 3) break;
- sprintf(CS ptr, " %s", s);
- while (*ptr) ptr++;
+ ptr += sprintf(CS ptr, " %s", s);
}
}
-sprintf(CS ptr, "\n");
-while(*ptr) ptr++;
+ptr += sprintf(CS ptr, "\n");
length = ptr - log_buffer;
/* Handle loggable errors when running a utility, or when address testing.
@@ -1000,7 +983,7 @@ if ( flags & LOG_MAIN
operation. This happens at midnight, at which point we want to roll over
the file. Closing it has the desired effect. */
- if (mainlog_datestamp != NULL)
+ if (mainlog_datestamp)
{
uschar *nowstamp = tod_stamp(string_datestamp_type);
if (Ustrncmp (mainlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
@@ -1084,11 +1067,9 @@ if ((flags & LOG_REJECT) != 0)
/* A header with a NULL text is an unfilled in Received: header */
- for (h = header_list; h != NULL; h = h->next)
+ for (h = header_list; h; h = h->next) if (h->text)
{
- BOOL fitted;
- if (h->text == NULL) continue;
- fitted = string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
+ BOOL fitted = string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
"%c %s", h->type, h->text);
while(*ptr) ptr++;
if (!fitted) /* Buffer is full; truncate */
@@ -1118,7 +1099,7 @@ if ((flags & LOG_REJECT) != 0)
{
struct stat statbuf;
- if (rejectlog_datestamp != NULL)
+ if (rejectlog_datestamp)
{
uschar *nowstamp = tod_stamp(string_datestamp_type);
if (Ustrncmp (rejectlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
@@ -1175,9 +1156,7 @@ if ((flags & LOG_PANIC) != 0)
fprintf(log_stderr, "%s", CS log_buffer);
if ((logging_mode & LOG_MODE_SYSLOG) != 0)
- {
write_syslog(LOG_ALERT, log_buffer);
- }
/* If this panic logging was caused by a failure to open the main log,
the original log line is in panic_save_buffer. Make an attempt to write it. */
diff --git a/src/src/lookups/cdb.c b/src/src/lookups/cdb.c
index bc610467c..153fcf24f 100644
--- a/src/src/lookups/cdb.c
+++ b/src/src/lookups/cdb.c
@@ -390,8 +390,8 @@ for (loop = 0; (loop < hash_offlen); ++loop)
{
uschar packbuf[8];
- if (lseek(cdbp->fileno, (off_t) cur_offset,SEEK_SET) == -1) return DEFER;
- if (cdb_bread(cdbp->fileno, packbuf,8) == -1) return DEFER;
+ if (lseek(cdbp->fileno, (off_t) cur_offset, SEEK_SET) == -1) return DEFER;
+ if (cdb_bread(cdbp->fileno, packbuf, 8) == -1) return DEFER;
item_hash = cdb_unpack(packbuf);
item_posn = cdb_unpack(packbuf + 4);
diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c
index b8c42d596..4b03c35f1 100644
--- a/src/src/lookups/dbmdb.c
+++ b/src/src/lookups/dbmdb.c
@@ -18,8 +18,12 @@
static void *
dbmdb_open(uschar *filename, uschar **errmsg)
{
+uschar * dirname = string_copy(filename);
+uschar * s;
EXIM_DB *yield = NULL;
-EXIM_DBOPEN(filename, O_RDONLY, 0, &yield);
+
+if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
+EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
if (yield == NULL)
{
int save_errno = errno;
diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c
index c4b5b53ec..bf3acd6ef 100644
--- a/src/src/lookups/dnsdb.c
+++ b/src/src/lookups/dnsdb.c
@@ -410,7 +410,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
if (outsep2 == NULL)
{
/* output only the first item of data */
- yield = string_catn(yield, &size, &ptr, (uschar *)(rr->data+1),
+ yield = string_catn(yield, &size, &ptr, US (rr->data+1),
(rr->data)[0]);
}
else
diff --git a/src/src/lookups/ibase.c b/src/src/lookups/ibase.c
index b29fccca7..7f1775c1f 100644
--- a/src/src/lookups/ibase.c
+++ b/src/src/lookups/ibase.c
@@ -291,35 +291,35 @@ has the password removed. This copy is also used for debugging output. */
(char *) store_get(sizeof(char) * var->sqllen);
break;
case SQL_SHORT:
- var->sqldata = (char *) store_get(sizeof(short));
+ var->sqldata = CS store_get(sizeof(short));
break;
case SQL_LONG:
- var->sqldata = (char *) store_get(sizeof(ISC_LONG));
+ var->sqldata = CS store_get(sizeof(ISC_LONG));
break;
#ifdef SQL_INT64
case SQL_INT64:
- var->sqldata = (char *) store_get(sizeof(ISC_INT64));
+ var->sqldata = CS store_get(sizeof(ISC_INT64));
break;
#endif
case SQL_FLOAT:
- var->sqldata = (char *) store_get(sizeof(float));
+ var->sqldata = CS store_get(sizeof(float));
break;
case SQL_DOUBLE:
- var->sqldata = (char *) store_get(sizeof(double));
+ var->sqldata = CS store_get(sizeof(double));
break;
#ifdef SQL_TIMESTAMP
case SQL_DATE:
- var->sqldata = (char *) store_get(sizeof(ISC_QUAD));
+ var->sqldata = CS store_get(sizeof(ISC_QUAD));
break;
#else
case SQL_TIMESTAMP:
- var->sqldata = (char *) store_get(sizeof(ISC_TIMESTAMP));
+ var->sqldata = CS store_get(sizeof(ISC_TIMESTAMP));
break;
case SQL_TYPE_DATE:
- var->sqldata = (char *) store_get(sizeof(ISC_DATE));
+ var->sqldata = CS store_get(sizeof(ISC_DATE));
break;
case SQL_TYPE_TIME:
- var->sqldata = (char *) store_get(sizeof(ISC_TIME));
+ var->sqldata = CS store_get(sizeof(ISC_TIME));
break;
#endif
}
diff --git a/src/src/lookups/lmdb.c b/src/src/lookups/lmdb.c
index a6888d5a9..55f273fd9 100644
--- a/src/src/lookups/lmdb.c
+++ b/src/src/lookups/lmdb.c
@@ -85,7 +85,7 @@ Lmdbstrct * lmdb_p = handle;
dbkey.mv_data = CS keystring;
dbkey.mv_size = length;
-DEBUG(D_lookup) debug_printf("LMDB: lookup key: %s\n", (char *)keystring);
+DEBUG(D_lookup) debug_printf("LMDB: lookup key: %s\n", CS keystring);
if ((ret = mdb_get(lmdb_p->txn, lmdb_p->db_dbi, &dbkey, &data)) == 0)
{
diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c
index 5cf15af3a..ddc7dc841 100644
--- a/src/src/lookups/mysql.c
+++ b/src/src/lookups/mysql.c
@@ -13,6 +13,7 @@ functions. */
#include "lf_functions.h"
#include <mysql.h> /* The system header */
+#include <mysql_version.h>
/* Structure and anchor for caching connections. */
diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c
index 6e7b015bc..0b01fdbce 100644
--- a/src/src/lookups/sqlite.c
+++ b/src/src/lookups/sqlite.c
@@ -23,7 +23,7 @@ sqlite_open(uschar *filename, uschar **errmsg)
sqlite3 *db = NULL;
int ret;
-ret = sqlite3_open((char *)filename, &db);
+ret = sqlite3_open(CS filename, &db);
if (ret != 0)
{
*errmsg = (void *)sqlite3_errmsg(db);
@@ -86,7 +86,7 @@ sqlite_find(void *handle, uschar *filename, const uschar *query, int length,
int ret;
struct strbuf res = { NULL, 0, 0 };
-ret = sqlite3_exec(handle, (char *)query, sqlite_callback, &res, (char **)errmsg);
+ret = sqlite3_exec(handle, CS query, sqlite_callback, &res, (char **)errmsg);
if (ret != SQLITE_OK)
{
debug_printf("sqlite3_exec failed: %s\n", *errmsg);
diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c
new file mode 100644
index 000000000..6b3157fbe
--- /dev/null
+++ b/src/src/macro_predef.c
@@ -0,0 +1,279 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2017 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Create a static data structure with the predefined macros, to be
+included in the main Exim build */
+
+#include "exim.h"
+#include "macro_predef.h"
+
+unsigned mp_index = 0;
+
+/* Global dummy variables */
+
+void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {}
+uschar * syslog_facility_str;
+
+/******************************************************************************/
+
+void
+builtin_macro_create(const uschar * name)
+{
+printf ("static macro_item p%d = { ", mp_index);
+if (mp_index == 0)
+ printf(".next=NULL,");
+else
+ printf(".next=&p%d,", mp_index-1);
+
+printf(" .command_line=FALSE, .namelen=%d, .replen=1,"
+ " .name=US\"%s\", .replacement=US\"y\" };\n",
+ Ustrlen(name), CS name);
+mp_index++;
+}
+
+void
+spf(uschar * buf, int len, const uschar * fmt, ...)
+{
+va_list ap;
+va_start(ap, fmt);
+
+while (*fmt && len > 1)
+ if (*fmt == '%' && fmt[1] == 'T')
+ {
+ uschar * s = va_arg(ap, uschar *);
+ while (*s && len-- > 1)
+ *buf++ = toupper(*s++);
+ fmt += 2;
+ }
+ else
+ {
+ *buf++ = *fmt++; len--;
+ }
+*buf = '\0';
+va_end(ap);
+}
+
+void
+options_from_list(optionlist * opts, unsigned nopt,
+ const uschar * section, uschar * group)
+{
+int i;
+const uschar * s;
+uschar buf[64];
+
+/* The 'previously-defined-substring' rule for macros in config file
+lines is done thus for these builtin macros: we know that the table
+we source from is in strict alpha order, hence the builtins portion
+of the macros list is in reverse-alpha (we prepend them) - so longer
+macros that have substrings are always discovered first during
+expansion. */
+
+for (i = 0; i < nopt; i++) if (*(s = US opts[i].name) && *s != '*')
+ {
+ if (group)
+ spf(buf, sizeof(buf), CUS"_OPT_%T_%T_%T", section, group, s);
+ else
+ spf(buf, sizeof(buf), CUS"_OPT_%T_%T", section, s);
+ builtin_macro_create(buf);
+ }
+}
+
+
+/******************************************************************************/
+
+
+/* Create compile-time feature macros */
+static void
+features(void)
+{
+/* Probably we could work out a static initialiser for wherever
+macros are stored, but this will do for now. Some names are awkward
+due to conflicts with other common macros. */
+
+#ifdef SUPPORT_CRYPTEQ
+ builtin_macro_create(US"_HAVE_CRYPTEQ");
+#endif
+#if HAVE_ICONV
+ builtin_macro_create(US"_HAVE_ICONV");
+#endif
+#if HAVE_IPV6
+ builtin_macro_create(US"_HAVE_IPV6");
+#endif
+#ifdef HAVE_SETCLASSRESOURCES
+ builtin_macro_create(US"_HAVE_SETCLASSRESOURCES");
+#endif
+#ifdef SUPPORT_PAM
+ builtin_macro_create(US"_HAVE_PAM");
+#endif
+#ifdef EXIM_PERL
+ builtin_macro_create(US"_HAVE_PERL");
+#endif
+#ifdef EXPAND_DLFUNC
+ builtin_macro_create(US"_HAVE_DLFUNC");
+#endif
+#ifdef USE_TCP_WRAPPERS
+ builtin_macro_create(US"_HAVE_TCPWRAPPERS");
+#endif
+#ifdef SUPPORT_TLS
+ builtin_macro_create(US"_HAVE_TLS");
+# ifdef USE_GNUTLS
+ builtin_macro_create(US"_HAVE_GNUTLS");
+# else
+ builtin_macro_create(US"_HAVE_OPENSSL");
+# endif
+#endif
+#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
+ builtin_macro_create(US"_HAVE_TRANSLATE_IP_ADDRESS");
+#endif
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+ builtin_macro_create(US"_HAVE_MOVE_FROZEN_MESSAGES");
+#endif
+#ifdef WITH_CONTENT_SCAN
+ builtin_macro_create(US"_HAVE_CONTENT_SCANNING");
+#endif
+#ifndef DISABLE_DKIM
+ builtin_macro_create(US"_HAVE_DKIM");
+#endif
+#ifndef DISABLE_DNSSEC
+ builtin_macro_create(US"_HAVE_DNSSEC");
+#endif
+#ifndef DISABLE_EVENT
+ builtin_macro_create(US"_HAVE_EVENT");
+#endif
+#ifdef SUPPORT_I18N
+ builtin_macro_create(US"_HAVE_I18N");
+#endif
+#ifndef DISABLE_OCSP
+ builtin_macro_create(US"_HAVE_OCSP");
+#endif
+#ifndef DISABLE_PRDR
+ builtin_macro_create(US"_HAVE_PRDR");
+#endif
+#ifdef SUPPORT_PROXY
+ builtin_macro_create(US"_HAVE_PROXY");
+#endif
+#ifdef SUPPORT_SOCKS
+ builtin_macro_create(US"_HAVE_SOCKS");
+#endif
+#ifdef TCP_FASTOPEN
+ builtin_macro_create(US"_HAVE_TCP_FASTOPEN");
+#endif
+#ifdef EXPERIMENTAL_LMDB
+ builtin_macro_create(US"_HAVE_LMDB");
+#endif
+#ifdef EXPERIMENTAL_SPF
+ builtin_macro_create(US"_HAVE_SPF");
+#endif
+#ifdef EXPERIMENTAL_SRS
+ builtin_macro_create(US"_HAVE_SRS");
+#endif
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+ builtin_macro_create(US"_HAVE_BRIGHTMAIL");
+#endif
+#ifdef EXPERIMENTAL_DANE
+ builtin_macro_create(US"_HAVE_DANE");
+#endif
+#ifdef EXPERIMENTAL_DCC
+ builtin_macro_create(US"_HAVE_DCC");
+#endif
+#ifdef EXPERIMENTAL_DMARC
+ builtin_macro_create(US"_HAVE_DMARC");
+#endif
+#ifdef EXPERIMENTAL_DSN_INFO
+ builtin_macro_create(US"_HAVE_DSN_INFO");
+#endif
+
+#ifdef LOOKUP_LSEARCH
+ builtin_macro_create(US"_HAVE_LOOKUP_LSEARCH");
+#endif
+#ifdef LOOKUP_CDB
+ builtin_macro_create(US"_HAVE_LOOKUP_CDB");
+#endif
+#ifdef LOOKUP_DBM
+ builtin_macro_create(US"_HAVE_LOOKUP_DBM");
+#endif
+#ifdef LOOKUP_DNSDB
+ builtin_macro_create(US"_HAVE_LOOKUP_DNSDB");
+#endif
+#ifdef LOOKUP_DSEARCH
+ builtin_macro_create(US"_HAVE_LOOKUP_DSEARCH");
+#endif
+#ifdef LOOKUP_IBASE
+ builtin_macro_create(US"_HAVE_LOOKUP_IBASE");
+#endif
+#ifdef LOOKUP_LDAP
+ builtin_macro_create(US"_HAVE_LOOKUP_LDAP");
+#endif
+#ifdef EXPERIMENTAL_LMDB
+ builtin_macro_create(US"_HAVE_LOOKUP_LMDB");
+#endif
+#ifdef LOOKUP_MYSQL
+ builtin_macro_create(US"_HAVE_LOOKUP_MYSQL");
+#endif
+#ifdef LOOKUP_NIS
+ builtin_macro_create(US"_HAVE_LOOKUP_NIS");
+#endif
+#ifdef LOOKUP_NISPLUS
+ builtin_macro_create(US"_HAVE_LOOKUP_NISPLUS");
+#endif
+#ifdef LOOKUP_ORACLE
+ builtin_macro_create(US"_HAVE_LOOKUP_ORACLE");
+#endif
+#ifdef LOOKUP_PASSWD
+ builtin_macro_create(US"_HAVE_LOOKUP_PASSWD");
+#endif
+#ifdef LOOKUP_PGSQL
+ builtin_macro_create(US"_HAVE_LOOKUP_PGSQL");
+#endif
+#ifdef LOOKUP_REDIS
+ builtin_macro_create(US"_HAVE_LOOKUP_REDIS");
+#endif
+#ifdef LOOKUP_SQLITE
+ builtin_macro_create(US"_HAVE_LOOKUP_SQLITE");
+#endif
+#ifdef LOOKUP_TESTDB
+ builtin_macro_create(US"_HAVE_LOOKUP_TESTDB");
+#endif
+#ifdef LOOKUP_WHOSON
+ builtin_macro_create(US"_HAVE_LOOKUP_WHOSON");
+#endif
+
+#ifdef TRANSPORT_APPENDFILE
+# ifdef SUPPORT_MAILDIR
+ builtin_macro_create(US"_HAVE_TRANSPORT_APPEND_MAILDIR");
+# endif
+# ifdef SUPPORT_MAILSTORE
+ builtin_macro_create(US"_HAVE_TRANSPORT_APPEND_MAILSTORE");
+# endif
+# ifdef SUPPORT_MBX
+ builtin_macro_create(US"_HAVE_TRANSPORT_APPEND_MBX");
+# endif
+#endif
+}
+
+
+static void
+options(void)
+{
+options_main();
+options_routers();
+options_transports();
+options_auths();
+}
+
+
+int
+main(void)
+{
+printf("#include \"exim.h\"\n");
+features();
+options();
+
+printf("macro_item * macros = &p%d;\n", mp_index-1);
+printf("macro_item * mlast = &p0;\n");
+exit(0);
+}
diff --git a/src/src/macro_predef.h b/src/src/macro_predef.h
new file mode 100644
index 000000000..1d3ba7f74
--- /dev/null
+++ b/src/src/macro_predef.h
@@ -0,0 +1,18 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2017 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Global functions */
+
+extern void spf(uschar *, int, const uschar *, ...);
+extern void builtin_macro_create(const uschar *);
+extern void options_from_list(optionlist *, unsigned, const uschar *, uschar *);
+
+extern void options_main(void);
+extern void options_routers(void);
+extern void options_transports(void);
+extern void options_auths(void);
+
diff --git a/src/src/macros.h b/src/src/macros.h
index 004d6dfd7..eaa7f21ef 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -27,20 +27,16 @@ a string as a text string. This is sometimes useful for debugging output. */
(running_in_test_harness? (test_harness_load_avg += 10) : os_getloadavg())
-/* The address_item structure has a word full of 1-bit flags. These macros
+/* The address_item structure has a struct full of 1-bit flags. These macros
manipulate them. */
-#define setflag(addr,flag) addr->flags |= (flag)
-#define clearflag(addr,flag) addr->flags &= ~(flag)
+#define setflag(addr, flagname) addr->flags.flagname = TRUE
+#define clearflag(addr, flagname) addr->flags.flagname = FALSE
-#define testflag(addr,flag) ((addr->flags & (flag)) != 0)
-#define testflagsall(addr,flag) ((addr->flags & (flag)) == (flag))
+#define testflag(addr, flagname) (addr->flags.flagname)
-#define copyflag(addrnew,addrold,flag) \
- addrnew->flags = (addrnew->flags & ~(flag)) | (addrold->flags & (flag))
-
-#define orflag(addrnew,addrold,flag) \
- addrnew->flags |= addrold->flags & (flag)
+#define copyflag(addrnew, addrold, flagname) \
+ addrnew->flags.flagname = addrold->flags.flagname
/* For almost all calls to convert things to printing characters, we want to
@@ -467,6 +463,7 @@ enum {
Li_ident_timeout,
Li_incoming_interface,
Li_incoming_port,
+ Li_millisec,
Li_outgoing_interface,
Li_outgoing_port,
Li_pid,
@@ -721,7 +718,8 @@ enum { v_none, v_sender, v_recipient, v_expn };
#define vopt_callout_no_cache 0x0040 /* disable callout cache */
#define vopt_callout_recipsender 0x0080 /* use real sender to verify recip */
#define vopt_callout_recippmaster 0x0100 /* use postmaster to verify recip */
-#define vopt_success_on_redirect 0x0200
+#define vopt_callout_hold 0x0200 /* lazy close connection */
+#define vopt_success_on_redirect 0x0400
/* Values for fields in callout cache records */
@@ -853,6 +851,16 @@ enum {
#define topt_no_body 0x040 /* Omit body */
#define topt_escape_headers 0x080 /* Apply escape check to headers */
#define topt_use_bdat 0x100 /* prepend chunks with RFC3030 BDAT header */
+#define topt_output_string 0x200 /* create string rather than write to fd */
+#define topt_continuation 0x400 /* do not reset buffer */
+
+/* Options for smtp_write_command */
+
+enum {
+ SCMD_FLUSH = 0, /* write to kernel */
+ SCMD_MORE, /* write to kernel, but likely more soon */
+ SCMD_BUFFER /* stash in application cmd output buffer */
+};
/* Flags for recipient_block, used in DSN support */
@@ -961,14 +969,14 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE };
/* Codes for ESMTP facilities offered by peer */
-#define PEER_OFFERED_TLS BIT(0)
-#define PEER_OFFERED_IGNQ BIT(1)
-#define PEER_OFFERED_PRDR BIT(2)
-#define PEER_OFFERED_UTF8 BIT(3)
-#define PEER_OFFERED_DSN BIT(4)
-#define PEER_OFFERED_PIPE BIT(5)
-#define PEER_OFFERED_SIZE BIT(6)
-#define PEER_OFFERED_CHUNKING BIT(7)
+#define OPTION_TLS BIT(0)
+#define OPTION_IGNQ BIT(1)
+#define OPTION_PRDR BIT(2)
+#define OPTION_UTF8 BIT(3)
+#define OPTION_DSN BIT(4)
+#define OPTION_PIPE BIT(5)
+#define OPTION_SIZE BIT(6)
+#define OPTION_CHUNKING BIT(7)
/* Argument for *_getc */
diff --git a/src/src/malware.c b/src/src/malware.c
index f9c4c414f..32f2e9e49 100644
--- a/src/src/malware.c
+++ b/src/src/malware.c
@@ -104,7 +104,7 @@ static inline int
test_byte_order()
{
short int word = 0x0001;
- char *byte = (char *) &word;
+ char *byte = CS &word;
return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
}
@@ -147,9 +147,10 @@ uses the returned in_addr to get a second connection to the same system.
*/
static inline int
m_tcpsocket(const uschar * hostname, unsigned int port,
- host_item * host, uschar ** errstr)
+ host_item * host, uschar ** errstr, const blob * fastopen)
{
-return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr);
+return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
+ host, errstr, fastopen);
}
static int
@@ -202,7 +203,11 @@ const pcre * cre = NULL;
if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
*errstr = US listerr;
else
+ {
+ DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
+ string_printing(list_ele));
cre = m_pcre_compile(CUS list_ele, errstr);
+ }
return cre;
}
@@ -413,16 +418,16 @@ is via malware(), or there's malware_in_file() used for testing/debugging.
Arguments:
malware_re match condition for "malware="
- eml_filename the file holding the email to be scanned
+ scan_filename the file holding the email to be scanned, if we're faking
+ this up for the -bmalware test, else NULL
timeout if nonzero, non-default timeoutl
- faking whether or not we're faking this up for the -bmalware test
Returns: Exim message processing code (OK, FAIL, DEFER, ...)
where true means malware was found (condition applies)
*/
static int
-malware_internal(const uschar * malware_re, const uschar * eml_filename,
- int timeout, BOOL faking)
+malware_internal(const uschar * malware_re, const uschar * scan_filename,
+ int timeout)
{
int sep = 0;
const uschar *av_scanner_work = av_scanner;
@@ -435,21 +440,24 @@ struct scan * scanent;
const uschar * scanner_options;
int sock = -1;
time_t tmo;
+uschar * eml_filename, * eml_dir;
+
+if (!malware_re)
+ return FAIL; /* empty means "don't match anything" */
-/* make sure the eml mbox file is spooled up */
-if (!(mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL)))
+/* Ensure the eml mbox file is spooled up */
+
+if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
return malware_errlog_defer(US"error while creating mbox spool file");
-/* none of our current scanners need the mbox
- file as a stream, so we can close it right away */
-(void)fclose(mbox_file);
+/* None of our current scanners need the mbox file as a stream (they use
+the name), so we can close it right away. Get the directory too. */
-if (!malware_re)
- return FAIL; /* empty means "don't match anything" */
+(void) fclose(mbox_file);
+eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
/* parse 1st option */
- if ( (strcmpic(malware_re, US"false") == 0) ||
- (Ustrcmp(malware_re,"0") == 0) )
+if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
return FAIL; /* explicitly no matching */
/* special cases (match anything except empty) */
@@ -469,9 +477,6 @@ if ( strcmpic(malware_re,US"true") == 0
else if (!(re = m_pcre_compile(malware_re, &errstr)))
return malware_errlog_defer(errstr);
-/* Reset sep that is set by previous string_nextinlist() call */
-sep = 0;
-
/* if av_scanner starts with a dollar, expand it first */
if (*av_scanner == '$')
{
@@ -503,10 +508,15 @@ if (!malware_ok)
scanner_name));
if (strcmpic(scanner_name, US scanent->name) != 0)
continue;
+ DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n",
+ scanner_name, readconf_printtime(timeout));
+
if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
scanner_options = scanent->options_default;
if (scanent->conn == MC_NONE)
break;
+
+ DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
switch(scanent->conn)
{
case MC_TCP: sock = ip_tcpsocket(scanner_options, &errstr, 5); break;
@@ -518,7 +528,6 @@ if (!malware_ok)
return m_errlog_defer(scanent, CUS callout_address, errstr);
break;
}
- DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo %s\n", scanner_name, readconf_printtime(timeout));
switch (scanent->scancode)
{
@@ -602,7 +611,8 @@ if (!malware_ok)
if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
{
- int err = errno;
+ int err;
+badseek: err = errno;
(void)close(drweb_fd);
return m_errlog_defer_3(scanent, NULL,
string_sprintf("can't seek spool file %s: %s",
@@ -619,7 +629,8 @@ if (!malware_ok)
sock);
}
drweb_slen = htonl(fsize);
- lseek(drweb_fd, 0, SEEK_SET);
+ if (lseek(drweb_fd, 0, SEEK_SET) < 0)
+ goto badseek;
DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
scanner_name, scanner_options);
@@ -780,7 +791,7 @@ if (!malware_ok)
if (buf[0] != '2') /* aveserver is having problems */
return m_errlog_defer_3(scanent, CUS callout_address,
string_sprintf("unavailable (Responded: %s).",
- ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
+ ((buf[0] != 0) ? buf : US "nothing") ),
sock);
/* prepare our command */
@@ -825,7 +836,7 @@ if (!malware_ok)
if (buf[0] != '2') /* aveserver is having problems */
return m_errlog_defer_3(scanent, CUS callout_address,
string_sprintf("unable to quit dialogue (Responded: %s).",
- ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
+ ((buf[0] != 0) ? buf : US "nothing") ),
sock);
if (result == DEFER)
@@ -1091,8 +1102,7 @@ if (!malware_ok)
}
scanner_fd = fileno(scanner_out);
- file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
- spool_directory, message_id, message_id);
+ file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
{
@@ -1245,6 +1255,7 @@ if (!malware_ok)
#else
uint32_t send_size, send_final_zeroblock;
#endif
+ blob cmd_str;
/*XXX if unixdomain socket, only one server supported. Needs fixing;
there's no reason we should not mix local and remote servers */
@@ -1340,6 +1351,19 @@ if (!malware_ok)
string_sprintf("local/SCAN mode incompatible with" \
" : in path to email filename [%s]", eml_filename));
+ /* Set up the very first data we will be sending */
+ if (!use_scan_command)
+#ifdef WITH_OLD_CLAMAV_STREAM
+ { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; }
+#else
+ { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
+#endif
+ else
+ {
+ cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
+ cmd_str.len = Ustrlen(cmd_str.data);
+ }
+
/* We have some network servers specified */
if (num_servers)
{
@@ -1349,7 +1373,7 @@ if (!malware_ok)
while (num_servers > 0)
{
- int i = random_number( num_servers );
+ int i = random_number(num_servers);
clamd_address * cd = cv[i];
DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
@@ -1359,11 +1383,12 @@ if (!malware_ok)
* on both connections (as one host could resolve to multiple ips) */
for (;;)
{
- sock= m_tcpsocket(cd->hostspec, cd->tcp_port, &connhost, &errstr);
- if (sock >= 0)
+ if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
+ &connhost, &errstr, &cmd_str)) >= 0)
{
/* Connection successfully established with a server */
hostname = cd->hostspec;
+ cmd_str.len = 0;
break;
}
if (cd->retry <= 0) break;
@@ -1412,9 +1437,10 @@ if (!malware_ok)
"Malware scan: issuing %s old-style remote scan (PORT)\n",
scanner_name);
- /* Pass the string to ClamAV (7 = "STREAM\n") */
- if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
- return m_errlog_defer(scanent, CUS callout_address, errstr);
+ /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */
+ if (cmd_str.len)
+ if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0)
+ return m_errlog_defer(scanent, CUS callout_address, errstr);
memset(av_buffer2, 0, sizeof(av_buffer2));
bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
@@ -1434,13 +1460,13 @@ if (!malware_ok)
"ClamAV returned null", sock);
av_buffer2[bread] = '\0';
- if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
+ if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1)
return m_errlog_defer_3(scanent, CUS callout_address,
string_sprintf("Expected port information from clamd, got '%s'",
av_buffer2),
sock);
- sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
+ sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL);
if (sockData < 0)
return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
@@ -1454,12 +1480,13 @@ if (!malware_ok)
"Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
scanner_name);
- /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
- if (send(sock, "zINSTREAM", 10, 0) < 0)
- return m_errlog_defer_3(scanent, CUS hostname,
- string_sprintf("unable to send zINSTREAM to socket (%s)",
- strerror(errno)),
- sock);
+ /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
+ if (cmd_str.len)
+ if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
+ return m_errlog_defer_3(scanent, CUS hostname,
+ string_sprintf("unable to send zINSTREAM to socket (%s)",
+ strerror(errno)),
+ sock);
# define CLOSE_SOCKDATA /**/
#endif
@@ -1476,7 +1503,8 @@ if (!malware_ok)
}
if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
{
- int err = errno;
+ int err;
+b_seek: err = errno;
CLOSE_SOCKDATA; (void)close(clam_fd);
return m_errlog_defer_3(scanent, NULL,
string_sprintf("can't seek spool file %s: %s",
@@ -1492,7 +1520,8 @@ if (!malware_ok)
eml_filename),
sock);
}
- lseek(clam_fd, 0, SEEK_SET);
+ if (lseek(clam_fd, 0, SEEK_SET) < 0)
+ goto b_seek;
if (!(clamav_fbuf = US malloc(fsize_uint)))
{
@@ -1558,17 +1587,17 @@ if (!malware_ok)
scanned twice, in the broken out files and from the original .eml.
Since ClamAV now handles emails (and has for quite some time) we can
just use the email file itself. */
- /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
- file_name = string_sprintf("SCAN %s\n", eml_filename);
+ /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
DEBUG(D_acl) debug_printf_indent(
"Malware scan: issuing %s local-path scan [%s]\n",
scanner_name, scanner_options);
- if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
- return m_errlog_defer_3(scanent, CUS callout_address,
- string_sprintf("unable to write to socket (%s)", strerror(errno)),
- sock);
+ if (cmd_str.len)
+ if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
+ return m_errlog_defer_3(scanent, CUS callout_address,
+ string_sprintf("unable to write to socket (%s)", strerror(errno)),
+ sock);
/* Do not shut down the socket for writing; a user report noted that
* clamd 0.70 does not react well to this. */
@@ -1695,8 +1724,10 @@ if (!malware_ok)
const pcre *sockline_name_re;
/* find scanner command line */
- if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
- NULL, 0)))
+ if ( (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
+ NULL, 0))
+ && *sockline_scanner
+ )
{ /* check for no expansions apart from one %s */
uschar * s = Ustrchr(sockline_scanner, '%');
if (s++)
@@ -1706,6 +1737,8 @@ if (!malware_ok)
}
else
sockline_scanner = sockline_scanner_default;
+ DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
+ string_printing(sockline_scanner));
/* find scanner output trigger */
sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
@@ -1720,9 +1753,9 @@ if (!malware_ok)
return m_errlog_defer_3(scanent, NULL, errstr, sock);
/* prepare scanner call - security depends on expansions check above */
- commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
- commandline = string_sprintf( CS sockline_scanner, CS commandline);
-
+ commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
+ DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
+ string_printing(commandline));
/* Pass the command string to the socket */
if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
@@ -1741,12 +1774,16 @@ if (!malware_ok)
US"buffer too small", sock);
av_buffer[bread] = '\0';
linebuffer = string_copy(av_buffer);
+ DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
+ string_printing(linebuffer));
/* try trigger match */
if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
{
if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
malware_name = US "unknown";
+ DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
+ string_printing(malware_name));
}
else /* no virus found */
malware_name = NULL;
@@ -1844,8 +1881,7 @@ if (!malware_ok)
}
else
{
- scanrequest = string_sprintf("SCAN %s/scan/%s\n",
- spool_directory, message_id);
+ scanrequest = string_sprintf("SCAN %s\n", eml_dir);
avast_stage = AVA_RSP; /* just sent command */
}
@@ -2000,14 +2036,9 @@ Returns: Exim message processing code (OK, FAIL, DEFER, ...)
int
malware(const uschar * malware_re, int timeout)
{
-uschar * scan_filename;
-int ret;
+int ret = malware_internal(malware_re, NULL, timeout);
-scan_filename = string_sprintf("%s/scan/%s/%s.eml",
- spool_directory, message_id, message_id);
-ret = malware_internal(malware_re, scan_filename, timeout, FALSE);
if (ret == DEFER) av_failed = TRUE;
-
return ret;
}
@@ -2045,7 +2076,7 @@ recipients_list = NULL;
receive_add_recipient(US"malware-victim@example.net", -1);
enable_dollar_recipients = TRUE;
-ret = malware_internal(US"*", eml_filename, 0, TRUE);
+ret = malware_internal(US"*", eml_filename, 0);
Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
spool_mbox_ok = 1;
diff --git a/src/src/match.c b/src/src/match.c
index fa42187dd..93777c6fe 100644
--- a/src/src/match.c
+++ b/src/src/match.c
@@ -1326,4 +1326,25 @@ return match_check_list(listptr, sep, &addresslist_anchor, &local_cache_bits,
valueptr);
}
+/* Simpler version of match_address_list; always caseless, expanding,
+no cache bits, no value-return.
+
+Arguments:
+ address address to test
+ listptr list to check against
+ sep separator character for the list;
+ may be 0 to get separator from the list;
+ may be UCHAR_MAX+1 for one-item list
+
+Returns: OK for a positive match, or end list after a negation;
+ FAIL for a negative match, or end list after non-negation;
+ DEFER if a lookup deferred
+*/
+
+int
+match_address_list_basic(const uschar *address, const uschar **listptr, int sep)
+{
+return match_address_list(address, TRUE, TRUE, listptr, NULL, -1, sep, NULL);
+}
+
/* End of match.c */
diff --git a/src/src/mime.c b/src/src/mime.c
index 821cb541d..61dabd2ac 100644
--- a/src/src/mime.c
+++ b/src/src/mime.c
@@ -16,6 +16,7 @@ FILE *mime_stream = NULL;
uschar *mime_current_boundary = NULL;
static mime_header mime_header_list[] = {
+ /* name namelen value */
{ US"content-type:", 13, &mime_content_type },
{ US"content-disposition:", 20, &mime_content_disposition },
{ US"content-transfer-encoding:", 26, &mime_content_transfer_encoding },
@@ -26,6 +27,7 @@ static mime_header mime_header_list[] = {
static int mime_header_list_size = nelem(mime_header_list);
static mime_parameter mime_parameter_list[] = {
+ /* name namelen value */
{ US"name=", 5, &mime_filename },
{ US"filename=", 9, &mime_filename },
{ US"charset=", 8, &mime_charset },
@@ -157,24 +159,16 @@ while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL)
{
/* Error from decoder. ipos is unchanged. */
mime_set_anomaly(MIME_ANOMALY_BROKEN_QP);
- *opos = '=';
- ++opos;
+ *opos++ = '=';
++ipos;
}
else if (decode_qp_result == -1)
break;
else if (decode_qp_result >= 0)
- {
- *opos = decode_qp_result;
- ++opos;
- }
+ *opos++ = decode_qp_result;
}
else
- {
- *opos = *ipos;
- ++opos;
- ++ipos;
- }
+ *opos++ = *ipos++;
}
/* something to write? */
len = opos - obuf;
@@ -225,9 +219,8 @@ mime_decode(const uschar **listptr)
{
int sep = 0;
const uschar *list = *listptr;
-uschar *option;
-uschar option_buffer[1024];
-uschar decode_path[1024];
+uschar * option;
+uschar * decode_path;
FILE *decode_file = NULL;
long f_pos = 0;
ssize_t size_counter = 0;
@@ -237,12 +230,10 @@ if (!mime_stream || (f_pos = ftell(mime_stream)) < 0)
return FAIL;
/* build default decode path (will exist since MBOX must be spooled up) */
-(void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id);
+decode_path = string_sprintf("%s/scan/%s", spool_directory, message_id);
/* try to find 1st option */
-if ((option = string_nextinlist(&list, &sep,
- option_buffer,
- sizeof(option_buffer))) != NULL)
+if ((option = string_nextinlist(&list, &sep, NULL, 0)))
{
/* parse 1st option */
if ((Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0))
diff --git a/src/src/mytypes.h b/src/src/mytypes.h
index b288a32cb..a74705739 100644
--- a/src/src/mytypes.h
+++ b/src/src/mytypes.h
@@ -30,11 +30,13 @@ local_scan.h includes it and exim.h includes them both (to get this earlier). */
the arguments of printf-like functions. This is done by a macro. */
#if defined(__GNUC__) || defined(__clang__)
-# define PRINTF_FUNCTION(A,B) __attribute__((format(printf,A,B)))
-# define ARG_UNUSED __attribute__((__unused__))
+# define PRINTF_FUNCTION(A,B) __attribute__((format(printf,A,B)))
+# define ARG_UNUSED __attribute__((__unused__))
+# define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
#else
# define PRINTF_FUNCTION(A,B)
# define ARG_UNUSED /**/
+# define WARN_UNUSED_RESULT /**/
#endif
#ifdef WANT_DEEPER_PRINTF_CHECKS
diff --git a/src/src/os.c b/src/src/os.c
index ca24e8dd2..6eadc38b1 100644
--- a/src/src/os.c
+++ b/src/src/os.c
@@ -6,9 +6,14 @@
/* See the file NOTICE for conditions of use and distribution. */
#ifdef STAND_ALONE
-#include <signal.h>
-#include <stdio.h>
-#include <time.h>
+# include <signal.h>
+# include <stdio.h>
+# include <time.h>
+#endif
+
+#ifndef CS
+# define CS (char *)
+# define US (unsigned char *)
#endif
/* This source file contains "default" system-dependent functions which
@@ -413,7 +418,7 @@ if (avg_kd < 0)
}
if (lseek (avg_kd, avg_offset, 0) == -1L
- || read (avg_kd, (char *)(&avg), sizeof (avg)) != sizeof(avg))
+ || read (avg_kd, CS (&avg), sizeof (avg)) != sizeof(avg))
return -1;
return (int)(((double)avg/FSCALE)*1000.0);
@@ -645,7 +650,7 @@ ifc.V_ifc_family = V_FAMILY_QUERY;
ifc.V_ifc_flags = 0;
#endif
-if (ioctl(vs, V_GIFCONF, (char *)&ifc) < 0)
+if (ioctl(vs, V_GIFCONF, CS &ifc) < 0)
log_write(0, LOG_PANIC_DIE, "Unable to get interface configuration: %d %s",
errno, strerror(errno));
@@ -680,7 +685,7 @@ find its length, and then recopy the correct length. */
for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
{
- memcpy((char *)&ifreq, cp, sizeof(ifreq));
+ memcpy(CS &ifreq, cp, sizeof(ifreq));
#ifndef HAVE_SA_LEN
len = sizeof(struct V_ifreq);
@@ -710,7 +715,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
interface hasn't been "plumbed" to any protocol (IPv4 or IPv6). Therefore,
we now just treat this case as "down" as well. */
- if (ioctl(vs, V_GIFFLAGS, (char *)&ifreq) < 0)
+ if (ioctl(vs, V_GIFFLAGS, CS &ifreq) < 0)
{
continue;
/*************
@@ -726,7 +731,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
GIFFLAGS may have wrecked the data. */
#ifndef SIOCGIFCONF_GIVES_ADDR
- if (ioctl(vs, V_GIFADDR, (char *)&ifreq) < 0)
+ if (ioctl(vs, V_GIFADDR, CS &ifreq) < 0)
log_write(0, LOG_PANIC_DIE, "Unable to get IP address for %s interface: "
"%d %s", ifreq.V_ifr_name, errno, strerror(errno));
addrp = &ifreq.V_ifr_addr;
@@ -846,7 +851,7 @@ os_get_dns_resolver_res(void)
int
os_unsetenv(const unsigned char * name)
{
-return unsetenv((char *)name);
+return unsetenv(CS name);
}
#endif
@@ -865,7 +870,7 @@ this, for all other systems we provide our own getcwd() */
unsigned char *
os_getcwd(unsigned char * buffer, size_t size)
{
-return (unsigned char *) getcwd((char *)buffer, size);
+return US getcwd(CS buffer, size);
}
#else
#ifndef PATH_MAX
@@ -874,7 +879,7 @@ return (unsigned char *) getcwd((char *)buffer, size);
unsigned char *
os_getcwd(unsigned char * buffer, size_t size)
{
-char * b = (char *)buffer;
+char * b = CS buffer;
if (!size) size = PATH_MAX;
if (!b && !(b = malloc(size))) return NULL;
diff --git a/src/src/parse.c b/src/src/parse.c
index 94a1af6ab..68a83b0e8 100644
--- a/src/src/parse.c
+++ b/src/src/parse.c
@@ -620,8 +620,8 @@ parse_extract_address(uschar *mailbox, uschar **errorptr, int *start, int *end,
{
uschar *yield = store_get(Ustrlen(mailbox) + 1);
uschar *startptr, *endptr;
-uschar *s = (uschar *)mailbox;
-uschar *t = (uschar *)yield;
+uschar *s = US mailbox;
+uschar *t = US yield;
*domain = 0;
@@ -745,7 +745,7 @@ if (*s == '<')
*errorptr = s[-1] == 0
? US"'>' missing at end of address"
: string_sprintf("malformed address: %.32s may not follow %.*s",
- s-1, s - (uschar *)mailbox - 1, mailbox);
+ s-1, s - US mailbox - 1, mailbox);
goto PARSE_FAILED;
}
@@ -798,13 +798,13 @@ if (*s != 0)
else
{
*errorptr = string_sprintf("malformed address: %.32s may not follow %.*s",
- s, s - (uschar *)mailbox, mailbox);
+ s, s - US mailbox, mailbox);
goto PARSE_FAILED;
}
}
-*start = startptr - (uschar *)mailbox; /* Return offsets */
+*start = startptr - US mailbox; /* Return offsets */
while (isspace(endptr[-1])) endptr--;
-*end = endptr - (uschar *)mailbox;
+*end = endptr - US mailbox;
/* Although this code has no limitation on the length of address extracted,
other parts of Exim may have limits, and in any case, RFC 2821 limits local
@@ -913,8 +913,7 @@ for (; len > 0; len--)
}
else
{
- sprintf(CS t, "=%02X", ch);
- while (*t != 0) t++;
+ t += sprintf(CS t, "=%02X", ch);
coded = TRUE;
first_byte = !first_byte;
}
diff --git a/src/src/pdkim/Makefile b/src/src/pdkim/Makefile
index c298568ea..10631ceaa 100644
--- a/src/src/pdkim/Makefile
+++ b/src/src/pdkim/Makefile
@@ -1,6 +1,6 @@
# Make file for building the pdkim library.
-OBJ = pdkim.o rsa.o
+OBJ = pdkim.o signing.o
pdkim.a: $(OBJ)
@$(RM_COMMAND) -f pdkim.a
@@ -13,6 +13,6 @@ pdkim.a: $(OBJ)
$(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -I. $*.c
pdkim.o: $(HDRS) crypt_ver.h pdkim.h pdkim.c
-rsa.o: $(HDRS) crypt_ver.h rsa.h rsa.c
+signing.o: $(HDRS) crypt_ver.h signing.h signing.c
# End
diff --git a/src/src/pdkim/crypt_ver.h b/src/src/pdkim/crypt_ver.h
index cd2171c82..439d99b3a 100644
--- a/src/src/pdkim/crypt_ver.h
+++ b/src/src/pdkim/crypt_ver.h
@@ -5,7 +5,7 @@
/* Copyright (c) Jeremy Harris 2016 */
/* See the file NOTICE for conditions of use and distribution. */
-/* RSA and SHA routine selection for PDKIM */
+/* Signing and hashing routine selection for PDKIM */
#include "../exim.h"
#include "../sha_ver.h"
@@ -15,12 +15,12 @@
# include <gnutls/gnutls.h>
# if GNUTLS_VERSION_NUMBER >= 0x30000
-# define RSA_GNUTLS
+# define SIGN_GNUTLS
# else
-# define RSA_GCRYPT
+# define SIGN_GCRYPT
# endif
#else
-# define RSA_OPENSSL
+# define SIGN_OPENSSL
#endif
diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c
index 5fc6045d0..695288162 100644
--- a/src/src/pdkim/pdkim.c
+++ b/src/src/pdkim/pdkim.c
@@ -32,17 +32,17 @@
#include "crypt_ver.h"
-#ifdef RSA_OPENSSL
+#ifdef SIGN_OPENSSL
# include <openssl/rsa.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
-#elif defined(RSA_GNUTLS)
+#elif defined(SIGN_GNUTLS)
# include <gnutls/gnutls.h>
# include <gnutls/x509.h>
#endif
#include "pdkim.h"
-#include "rsa.h"
+#include "signing.h"
#define PDKIM_SIGNATURE_VERSION "1"
#define PDKIM_PUB_RECORD_VERSION US "DKIM1"
@@ -73,24 +73,24 @@ const uschar * pdkim_querymethods[] = {
US"dns/txt",
NULL
};
-const uschar * pdkim_algos[] = {
- US"rsa-sha256",
- US"rsa-sha1",
- NULL
-};
const uschar * pdkim_canons[] = {
US"simple",
US"relaxed",
NULL
};
-const uschar * pdkim_hashes[] = {
- US"sha256",
- US"sha1",
- NULL
+
+typedef struct {
+ const uschar * dkim_hashname;
+ hashmethod exim_hashmethod;
+} pdkim_hashtype;
+static const pdkim_hashtype pdkim_hashes[] = {
+ { US"sha1", HASH_SHA1 },
+ { US"sha256", HASH_SHA2_256 },
+ { US"sha512", HASH_SHA2_512 }
};
+
const uschar * pdkim_keytypes[] = {
- US"rsa",
- NULL
+ US"rsa"
};
typedef struct pdkim_combined_canon_entry {
@@ -110,7 +110,20 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = {
};
+static blob lineending = {.data = US"\r\n", .len = 2};
+
/* -------------------------------------------------------------------------- */
+uschar *
+dkim_sig_to_a_tag(const pdkim_signature * sig)
+{
+if ( sig->keytype < 0 || sig->keytype > nelem(pdkim_keytypes)
+ || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes))
+ return US"err";
+return string_sprintf("%s-%s",
+ pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname);
+}
+
+
const char *
pdkim_verify_status_str(int status)
@@ -132,6 +145,7 @@ switch(ext_status)
{
case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
+ case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
@@ -155,7 +169,7 @@ switch(status)
case PDKIM_ERR_BUFFER_TOO_SMALL: return US"BUFFER_TOO_SMALL";
case PDKIM_SIGN_PRIVKEY_WRAP: return US"PRIVKEY_WRAP";
case PDKIM_SIGN_PRIVKEY_B64D: return US"PRIVKEY_B64D";
- default: return "(unknown)";
+ default: return US"(unknown)";
}
}
@@ -288,7 +302,7 @@ found:
/* Performs "relaxed" canonicalization of a header. */
static uschar *
-pdkim_relax_header(const uschar * header, int crlf)
+pdkim_relax_header(const uschar * header, BOOL append_crlf)
{
BOOL past_field_name = FALSE;
BOOL seen_wsp = FALSE;
@@ -299,8 +313,8 @@ uschar * q = relaxed;
for (p = header; *p; p++)
{
uschar c = *p;
- /* Ignore CR & LF */
- if (c == '\r' || c == '\n')
+
+ if (c == '\r' || c == '\n') /* Ignore CR & LF */
continue;
if (c == '\t' || c == ' ')
{
@@ -312,8 +326,8 @@ for (p = header; *p; p++)
else
if (!past_field_name && c == ':')
{
- if (seen_wsp) q--; /* This removes WSP before the colon */
- seen_wsp = TRUE; /* This removes WSP after the colon */
+ if (seen_wsp) q--; /* This removes WSP immediately before the colon */
+ seen_wsp = TRUE; /* This removes WSP immediately after the colon */
past_field_name = TRUE;
}
else
@@ -326,7 +340,7 @@ for (p = header; *p; p++)
if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
-if (crlf) { *q++ = '\r'; *q++ = '\n'; }
+if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
*q = '\0';
return relaxed;
}
@@ -335,10 +349,10 @@ return relaxed;
/* -------------------------------------------------------------------------- */
#define PDKIM_QP_ERROR_DECODE -1
-static uschar *
-pdkim_decode_qp_char(uschar *qp_p, int *c)
+static const uschar *
+pdkim_decode_qp_char(const uschar *qp_p, int *c)
{
-uschar *initial_pos = qp_p;
+const uschar *initial_pos = qp_p;
/* Advance one char */
qp_p++;
@@ -361,11 +375,11 @@ return initial_pos;
/* -------------------------------------------------------------------------- */
static uschar *
-pdkim_decode_qp(uschar * str)
+pdkim_decode_qp(const uschar * str)
{
int nchar = 0;
uschar * q;
-uschar * p = str;
+const uschar * p = str;
uschar * n = store_get(Ustrlen(str)+1);
*n = '\0';
@@ -393,7 +407,7 @@ return n;
/* -------------------------------------------------------------------------- */
static void
-pdkim_decode_base64(uschar *str, blob * b)
+pdkim_decode_base64(const uschar * str, blob * b)
{
int dlen;
dlen = b64decode(str, &b->data);
@@ -414,7 +428,7 @@ return b64encode(b->data, b->len);
#define PDKIM_HDR_VALUE 2
static pdkim_signature *
-pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
+pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
{
pdkim_signature * sig;
uschar *p, *q;
@@ -430,8 +444,9 @@ memset(sig, 0, sizeof(pdkim_signature));
sig->bodylength = -1;
/* Set so invalid/missing data error display is accurate */
-sig->algo = -1;
sig->version = 0;
+sig->keytype = -1;
+sig->hashtype = -1;
q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
@@ -504,13 +519,18 @@ for (p = raw_hdr; ; p++)
Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
break;
case 'a':
- for (i = 0; pdkim_algos[i]; i++)
- if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
- {
- sig->algo = i;
- break;
- }
+ {
+ uschar * s = Ustrchr(cur_val, '-');
+
+ for(i = 0; i < nelem(pdkim_keytypes); i++)
+ if (Ustrncmp(cur_val, pdkim_keytypes[i], s - cur_val) == 0)
+ { sig->keytype = i; break; }
+ for (++s, i = 0; i < nelem(pdkim_hashes); i++)
+ if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0)
+ { sig->hashtype = i; break; }
break;
+ }
+
case 'c':
for (i = 0; pdkim_combined_canons[i].str; i++)
if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
@@ -582,10 +602,12 @@ DEBUG(D_acl)
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
+/*XXX hash method: extend for sha512 */
if (!exim_sha_init(&sig->body_hash_ctx,
- sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
+ pdkim_hashes[sig->hashtype].exim_hashmethod))
{
- DEBUG(D_acl) debug_printf("PDKIM: hash init internal error\n");
+ DEBUG(D_acl)
+ debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
return NULL;
}
return sig;
@@ -597,190 +619,145 @@ return sig;
static pdkim_pubkey *
pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
{
-pdkim_pubkey *pub;
-const uschar *p;
-uschar * cur_tag = NULL; int ts = 0, tl = 0;
-uschar * cur_val = NULL; int vs = 0, vl = 0;
-int where = PDKIM_HDR_LIMBO;
+const uschar * ele;
+int sep = ';';
+pdkim_pubkey * pub;
pub = store_get(sizeof(pdkim_pubkey));
memset(pub, 0, sizeof(pdkim_pubkey));
-for (p = raw_record; ; p++)
+while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
+ {
+ const uschar * val;
+
+ if ((val = Ustrchr(ele, '=')))
{
- uschar c = *p;
+ int taglen = val++ - ele;
- /* Ignore FWS */
- if (c != '\r' && c != '\n') switch (where)
+ DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
+ switch (ele[0])
{
- case PDKIM_HDR_LIMBO: /* In limbo, just wait for a tag-char to appear */
- if (!(c >= 'a' && c <= 'z'))
- break;
- where = PDKIM_HDR_TAG;
- /*FALLTHROUGH*/
-
- case PDKIM_HDR_TAG:
- if (c >= 'a' && c <= 'z')
- cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
-
- if (c == '=')
- {
- cur_tag[tl] = '\0';
- where = PDKIM_HDR_VALUE;
- }
- break;
-
- case PDKIM_HDR_VALUE:
- if (c == ';' || c == '\0')
- {
- if (tl && vl)
- {
- cur_val[vl] = '\0';
- pdkim_strtrim(cur_val);
- DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
-
- switch (cur_tag[0])
- {
- case 'v':
- pub->version = string_copy(cur_val); break;
- case 'h':
- case 'k':
-/* This field appears to never be used. Also, unclear why
-a 'k' (key-type_ would go in this field name. There is a field
-"keytype", also never used.
- pub->hashes = string_copy(cur_val);
-*/
- break;
- case 'g':
- pub->granularity = string_copy(cur_val); break;
- case 'n':
- pub->notes = pdkim_decode_qp(cur_val); break;
- case 'p':
- pdkim_decode_base64(US cur_val, &pub->key); break;
- case 's':
- pub->srvtype = string_copy(cur_val); break;
- case 't':
- if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
- if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
+ case 'v': pub->version = val; break;
+ case 'h': pub->hashes = val; break;
+ case 'k': break;
+ case 'g': pub->granularity = val; break;
+ case 'n': pub->notes = pdkim_decode_qp(val); break;
+ case 'p': pdkim_decode_base64(val, &pub->key); break;
+ case 's': pub->srvtype = val; break;
+ case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
+ if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
break;
- default:
- DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
- break;
- }
- }
- tl = 0;
- vl = 0;
- where = PDKIM_HDR_LIMBO;
- }
- else
- cur_val = string_catn(cur_val, &vs, &vl, p, 1);
- break;
+ default: DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
}
-
- if (c == '\0') break;
}
+ }
/* Set fallback defaults */
if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
-else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0) return NULL;
+else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
+ {
+ DEBUG(D_acl) debug_printf(" Bad v= field\n");
+ return NULL;
+ }
-if (!pub->granularity) pub->granularity = string_copy(US"*");
+if (!pub->granularity) pub->granularity = US"*";
/*
-if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
+if (!pub->keytype ) pub->keytype = US"rsa";
*/
-if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
+if (!pub->srvtype ) pub->srvtype = US"*";
/* p= is required */
if (pub->key.data)
return pub;
+DEBUG(D_acl) debug_printf(" Missing p= field\n");
return NULL;
}
/* -------------------------------------------------------------------------- */
-static int
-pdkim_update_bodyhash(pdkim_ctx * ctx, const char * data, int len)
+/* Update the bodyhash for one sig, with some additional data.
+If we have to relax the data for this sig, return our copy of it. */
+
+/*XXX Currently we calculate a hash for each sig. But it is possible
+that multi-signing will be wanted using different signing algos
+(rsa, ec) using the same hash and canonicalization. Consider in future
+hanging the hash+cacnon from the ctx and only referencing from the sig,
+so that it can be calculated only once - being over the body this
+caould be meagbytes, hence expensive. */
+
+static blob *
+pdkim_update_sig_bodyhash(pdkim_signature * sig, blob * orig_data, blob * relaxed_data)
{
-pdkim_signature * sig;
-uschar * relaxed_data = NULL; /* Cache relaxed version of data */
-int relaxed_len = 0;
+blob * canon_data = orig_data;
+/* Defaults to simple canon (no further treatment necessary) */
-/* Traverse all signatures, updating their hashes. */
-for (sig = ctx->sig; sig; sig = sig->next)
+if (sig->canon_body == PDKIM_CANON_RELAXED)
{
- /* Defaults to simple canon (no further treatment necessary) */
- const uschar *canon_data = CUS data;
- int canon_len = len;
-
- if (sig->canon_body == PDKIM_CANON_RELAXED)
+ /* Relax the line if not done already */
+ if (!relaxed_data)
{
- /* Relax the line if not done already */
- if (!relaxed_data)
- {
- BOOL seen_wsp = FALSE;
- const char *p;
- int q = 0;
+ BOOL seen_wsp = FALSE;
+ const uschar * p;
+ int q = 0;
- /* We want to be able to free this else we allocate
- for the entire message which could be many MB. Since
- we don't know what allocations the SHA routines might
- do, not safe to use store_get()/store_reset(). */
+ /* We want to be able to free this else we allocate
+ for the entire message which could be many MB. Since
+ we don't know what allocations the SHA routines might
+ do, not safe to use store_get()/store_reset(). */
- relaxed_data = store_malloc(len+1);
+ relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
+ relaxed_data->data = US (relaxed_data+1);
- for (p = data; *p; p++)
- {
- char c = *p;
- if (c == '\r')
- {
- if (q > 0 && relaxed_data[q-1] == ' ')
- q--;
- }
- else if (c == '\t' || c == ' ')
- {
- c = ' '; /* Turns WSP into SP */
- if (seen_wsp)
- continue;
- seen_wsp = TRUE;
- }
- else
- seen_wsp = FALSE;
- relaxed_data[q++] = c;
+ for (p = orig_data->data; *p; p++)
+ {
+ char c = *p;
+ if (c == '\r')
+ {
+ if (q > 0 && relaxed_data->data[q-1] == ' ')
+ q--;
}
- relaxed_data[q] = '\0';
- relaxed_len = q;
+ else if (c == '\t' || c == ' ')
+ {
+ c = ' '; /* Turns WSP into SP */
+ if (seen_wsp)
+ continue;
+ seen_wsp = TRUE;
+ }
+ else
+ seen_wsp = FALSE;
+ relaxed_data->data[q++] = c;
}
- canon_data = relaxed_data;
- canon_len = relaxed_len;
+ relaxed_data->data[q] = '\0';
+ relaxed_data->len = q;
}
+ canon_data = relaxed_data;
+ }
- /* Make sure we don't exceed the to-be-signed body length */
- if ( sig->bodylength >= 0
- && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
- )
- canon_len = sig->bodylength - sig->signed_body_bytes;
+/* Make sure we don't exceed the to-be-signed body length */
+if ( sig->bodylength >= 0
+ && sig->signed_body_bytes + (unsigned long)canon_data->len > sig->bodylength
+ )
+ canon_data->len = sig->bodylength - sig->signed_body_bytes;
- if (canon_len > 0)
- {
- exim_sha_update(&sig->body_hash_ctx, CUS canon_data, canon_len);
- sig->signed_body_bytes += canon_len;
- DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
- }
+if (canon_data->len > 0)
+ {
+ exim_sha_update(&sig->body_hash_ctx, CUS canon_data->data, canon_data->len);
+ sig->signed_body_bytes += canon_data->len;
+ DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
}
-if (relaxed_data) store_free(relaxed_data);
-return PDKIM_OK;
+return relaxed_data;
}
/* -------------------------------------------------------------------------- */
static void
-pdkim_finish_bodyhash(pdkim_ctx *ctx)
+pdkim_finish_bodyhash(pdkim_ctx * ctx)
{
-pdkim_signature *sig;
+pdkim_signature * sig;
/* Traverse all signatures */
for (sig = ctx->sig; sig; sig = sig->next)
@@ -792,8 +769,9 @@ for (sig = ctx->sig; sig; sig = sig->next)
DEBUG(D_acl)
{
debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
- "PDKIM [%s] Body hash computed: ",
- sig->domain, sig->signed_body_bytes, sig->domain);
+ "PDKIM [%s] Body %s computed: ",
+ sig->domain, sig->signed_body_bytes,
+ sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
pdkim_hexprint(CUS bh.data, bh.len);
}
@@ -832,10 +810,10 @@ for (sig = ctx->sig; sig; sig = sig->next)
-static int
+static void
pdkim_body_complete(pdkim_ctx * ctx)
{
-pdkim_signature * sig = ctx->sig; /*XXX assumes only one sig */
+pdkim_signature * sig;
/* In simple body mode, if any empty lines were buffered,
replace with one. rfc 4871 3.4.3 */
@@ -843,15 +821,15 @@ replace with one. rfc 4871 3.4.3 */
it indicates that all linebreaks should be buffered, including
the one terminating a text line */
-if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
- && sig->signed_body_bytes == 0
- && ctx->num_buffered_crlf > 0
- )
- pdkim_update_bodyhash(ctx, "\r\n", 2);
+for (sig = ctx->sig; sig; sig = sig->next)
+ if ( sig->canon_body == PDKIM_CANON_SIMPLE
+ && sig->signed_body_bytes == 0
+ && sig->num_buffered_blanklines > 0
+ )
+ (void) pdkim_update_sig_bodyhash(sig, &lineending, NULL);
ctx->flags |= PDKIM_SEEN_EOD;
ctx->linebuf_offset = 0;
-return PDKIM_OK;
}
@@ -859,70 +837,78 @@ return PDKIM_OK;
/* -------------------------------------------------------------------------- */
/* Call from pdkim_feed below for processing complete body lines */
-static int
-pdkim_bodyline_complete(pdkim_ctx *ctx)
+static void
+pdkim_bodyline_complete(pdkim_ctx * ctx)
{
-char *p = ctx->linebuf;
-int n = ctx->linebuf_offset;
-pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
+blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
+pdkim_signature * sig;
+blob * rnl = NULL;
+blob * rline = NULL;
/* Ignore extra data if we've seen the end-of-data marker */
-if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
+if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
/* We've always got one extra byte to stuff a zero ... */
-ctx->linebuf[ctx->linebuf_offset] = '\0';
+ctx->linebuf[line.len] = '\0';
/* Terminate on EOD marker */
if (ctx->flags & PDKIM_DOT_TERM)
{
- if (memcmp(p, ".\r\n", 3) == 0)
- return pdkim_body_complete(ctx);
+ if (memcmp(line.data, ".\r\n", 3) == 0)
+ { pdkim_body_complete(ctx); return; }
/* Unstuff dots */
- if (memcmp(p, "..", 2) == 0)
- {
- p++;
- n--;
- }
+ if (memcmp(line.data, "..", 2) == 0)
+ { line.data++; line.len--; }
}
/* Empty lines need to be buffered until we find a non-empty line */
-if (memcmp(p, "\r\n", 2) == 0)
+if (memcmp(line.data, "\r\n", 2) == 0)
{
- ctx->num_buffered_crlf++;
- goto BAIL;
+ for (sig = ctx->sig; sig; sig = sig->next) sig->num_buffered_blanklines++;
+ goto all_skip;
}
-if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
+/* Process line for each sig separately */
+for (sig = ctx->sig; sig; sig = sig->next)
{
- /* Lines with just spaces need to be buffered too */
- char *check = p;
- while (memcmp(check, "\r\n", 2) != 0)
+ if (sig->canon_body == PDKIM_CANON_RELAXED)
{
- char c = *check;
+ /* Lines with just spaces need to be buffered too */
+ uschar * cp = line.data;
+ char c;
+
+ while ((c = *cp))
+ {
+ if (c == '\r' && cp[1] == '\n') break;
+ if (c != ' ' && c != '\t') goto sig_process;
+ cp++;
+ }
- if (c != '\t' && c != ' ')
- goto PROCESS;
- check++;
+ sig->num_buffered_blanklines++;
+ goto sig_skip;
}
- ctx->num_buffered_crlf++;
- goto BAIL;
-}
+sig_process:
+ /* At this point, we have a non-empty line, so release the buffered ones. */
-PROCESS:
-/* At this point, we have a non-empty line, so release the buffered ones. */
-while (ctx->num_buffered_crlf)
- {
- pdkim_update_bodyhash(ctx, "\r\n", 2);
- ctx->num_buffered_crlf--;
+ while (sig->num_buffered_blanklines)
+ {
+ rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
+ sig->num_buffered_blanklines--;
+ }
+
+ rline = pdkim_update_sig_bodyhash(sig, &line, rline);
+sig_skip: ;
}
-pdkim_update_bodyhash(ctx, p, n);
+if (rnl) store_free(rnl);
+if (rline) store_free(rline);
+
+all_skip:
-BAIL:
ctx->linebuf_offset = 0;
-return PDKIM_OK;
+return;
}
@@ -999,7 +985,7 @@ return PDKIM_OK;
#define HEADER_BUFFER_FRAG_SIZE 256
DLLEXPORT int
-pdkim_feed(pdkim_ctx *ctx, char *data, int len)
+pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
{
int p, rc;
@@ -1027,8 +1013,7 @@ else for (p = 0; p<len; p++)
else if (c == '\n')
{
ctx->flags &= ~PDKIM_SEEN_CR;
- if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK)
- return rc;
+ pdkim_bodyline_complete(ctx);
}
if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
@@ -1208,7 +1193,7 @@ return str;
/* -------------------------------------------------------------------------- */
static uschar *
-pdkim_create_header(pdkim_signature *sig, BOOL final)
+pdkim_create_header(pdkim_signature * sig, BOOL final)
{
uschar * base64_bh;
uschar * base64_b;
@@ -1229,7 +1214,7 @@ col = hdr_len;
/* Required and static bits */
hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
- pdkim_algos[sig->algo]);
+ dkim_sig_to_a_tag(sig));
hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
pdkim_querymethods[sig->querymethod]);
hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
@@ -1297,11 +1282,23 @@ if (sig->bodylength >= 0)
}
/* Preliminary or final version? */
-base64_b = final ? pdkim_encode_base64(&sig->sighash) : US"";
-hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
+if (final)
+ {
+ base64_b = pdkim_encode_base64(&sig->sighash);
+ hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
-/* add trailing semicolon: I'm not sure if this is actually needed */
-hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
+ /* add trailing semicolon: I'm not sure if this is actually needed */
+ hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
+ }
+else
+ {
+ /* To satisfy the rule "all surrounding whitespace [...] deleted"
+ ( RFC 6376 section 3.7 ) we ensure there is no whitespace here. Otherwise
+ the headcat routine could insert a linebreak which the relaxer would reduce
+ to a single space preceding the terminating semicolon, resulting in an
+ incorrect header-hash. */
+ hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=;", US"");
+ }
hdr[hdr_len] = '\0';
return hdr;
@@ -1337,7 +1334,9 @@ DEBUG(D_acl)
{
debug_printf(
"PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
- " Raw record: ");
+ " %s\n"
+ " Raw record: ",
+ dns_txt_name);
pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
}
@@ -1364,7 +1363,7 @@ DEBUG(D_acl) debug_printf(
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
/* Import public key */
-if ((*errstr = exim_rsa_verify_init(&p->key, vctx)))
+if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
{
DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
sig->verify_status = PDKIM_VERIFY_INVALID;
@@ -1382,16 +1381,22 @@ DLLEXPORT int
pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
const uschar ** err)
{
-pdkim_signature *sig = ctx->sig;
+pdkim_signature * sig;
/* Check if we must still flush a (partial) header. If that is the
case, the message has no body, and we must compute a body hash
out of '<CR><LF>' */
if (ctx->cur_header && ctx->cur_header_len)
{
- int rc = pdkim_header_complete(ctx);
- if (rc != PDKIM_OK) return rc;
- pdkim_update_bodyhash(ctx, "\r\n", 2);
+ blob * rnl = NULL;
+ int rc;
+
+ if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
+ return rc;
+
+ for (sig = ctx->sig; sig; sig = sig->next)
+ rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
+ if (rnl) store_free(rnl);
}
else
DEBUG(D_acl) debug_printf(
@@ -1400,9 +1405,8 @@ else
/* Build (and/or evaluate) body hash */
pdkim_finish_bodyhash(ctx);
-while (sig)
+for (sig = ctx->sig; sig; sig = sig->next)
{
- BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
hctx hhash_ctx;
uschar * sig_hdr = US"";
blob hhash;
@@ -1412,14 +1416,22 @@ while (sig)
hdata.data = NULL;
hdata.len = 0;
- if (!exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256))
+ if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
{
- DEBUG(D_acl) debug_printf("PDKIM: hask setup internal error\n");
+ DEBUG(D_acl)
+ debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
break;
}
+ if (ctx->flags & PDKIM_MODE_SIGN)
+ DEBUG(D_acl) debug_printf(
+ "PDKIM >> Headers to be signed: >>>>>>>>>>>>\n"
+ " %s\n",
+ sig->sign_headers);
+
DEBUG(D_acl) debug_printf(
- "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
+ "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
+
/* SIGNING ---------------------------------------------------------------- */
/* When signing, walk through our header list and add them to the hash. As we
@@ -1429,49 +1441,43 @@ while (sig)
if (ctx->flags & PDKIM_MODE_SIGN)
{
- uschar * headernames = NULL; /* Collected signed header names */
int hs = 0, hl = 0;
pdkim_stringlist *p;
const uschar * l;
uschar * s;
int sep = 0;
+ sig->headernames = NULL; /* Collected signed header names */
+
for (p = sig->headers; p; p = p->next)
- if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
+ {
+ uschar * rh = p->value;
+
+ if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
{
- uschar * rh;
/* Collect header names (Note: colon presence is guaranteed here) */
- uschar * q = Ustrchr(p->value, ':');
-
- headernames = string_catn(headernames, &hs, &hl,
- p->value, (q - US p->value) + (p->next ? 1 : 0));
+ sig->headernames = string_append_listele_n(sig->headernames, &hs, &hl,
+ ':', rh, Ustrchr(rh, ':') - rh);
- rh = sig->canon_headers == PDKIM_CANON_RELAXED
- ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
- : string_copy(CUS p->value); /* just copy it for simple canon */
+ if (sig->canon_headers == PDKIM_CANON_RELAXED)
+ rh = pdkim_relax_header(rh, TRUE); /* cook header for relaxed canon */
/* Feed header to the hash algorithm */
exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
/* Remember headers block for signing (when the library cannot do incremental) */
- (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
+ (void) exim_dkim_data_append(&hdata, &hdata_alloc, rh);
DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
}
+ }
+ /* Any headers we wanted to sign but were not present must also be listed */
l = sig->sign_headers;
while((s = string_nextinlist(&l, &sep, NULL, 0)))
if (*s != '_')
- { /*SSS string_append_listele() */
- if (hl > 0 && headernames[hl-1] != ':')
- headernames = string_catn(headernames, &hs, &hl, US":", 1);
-
- headernames = string_cat(headernames, &hs, &hl, s);
- }
- headernames[hl] = '\0';
-
- /* Copy headernames to signature struct */
- sig->headernames = headernames;
+ sig->headernames = string_append_listele(sig->headernames, &hs, &hl, ':', s);
+ sig->headernames[hl] = '\0';
/* Create signature header with b= omitted */
sig_hdr = pdkim_create_header(sig, FALSE);
@@ -1508,7 +1514,7 @@ while (sig)
/* cook header for relaxed canon, or just copy it for simple */
uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
- ? pdkim_relax_header(hdrs->value, 1)
+ ? pdkim_relax_header(hdrs->value, TRUE)
: string_copy(CUS hdrs->value);
/* Feed header to the hash algorithm */
@@ -1530,9 +1536,18 @@ while (sig)
DEBUG(D_acl) debug_printf(
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ DEBUG(D_acl)
+ {
+ debug_printf(
+ "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
+ pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
+ debug_printf(
+ "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ }
+
/* Relax header if necessary */
if (sig->canon_headers == PDKIM_CANON_RELAXED)
- sig_hdr = pdkim_relax_header(sig_hdr, 0);
+ sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
DEBUG(D_acl)
{
@@ -1549,21 +1564,24 @@ while (sig)
DEBUG(D_acl)
{
- debug_printf("PDKIM [%s] Header hash computed: ", sig->domain);
+ debug_printf("PDKIM [%s] Header %s computed: ",
+ sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
pdkim_hexprint(hhash.data, hhash.len);
}
- /* Remember headers block for signing (when the library cannot do incremental) */
+ /* Remember headers block for signing (when the signing library cannot do
+ incremental) */
if (ctx->flags & PDKIM_MODE_SIGN)
- (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
+ (void) exim_dkim_data_append(&hdata, &hdata_alloc, US sig_hdr);
/* SIGNING ---------------------------------------------------------------- */
if (ctx->flags & PDKIM_MODE_SIGN)
{
es_ctx sctx;
- /* Import private key */
- if ((*err = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
+ /* Import private key, including the keytype */
+/*XXX extend for non-RSA algos */
+ if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
{
DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
return PDKIM_ERR_RSA_PRIVKEY;
@@ -1573,11 +1591,14 @@ while (sig)
calculated, with GnuTLS we have to sign an entire block of headers
(due to available interfaces) and it recalculates the hash internally. */
-#if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
+#if defined(SIGN_OPENSSL) || defined(SIGN_GCRYPT)
hdata = hhash;
#endif
- if ((*err = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sighash)))
+/*XXX extend for non-RSA algos */
+ if ((*err = exim_dkim_sign(&sctx,
+ pdkim_hashes[sig->hashtype].exim_hashmethod,
+ &hdata, &sig->sighash)))
{
DEBUG(D_acl) debug_printf("signing: %s\n", *err);
return PDKIM_ERR_RSA_SIGNING;
@@ -1596,7 +1617,6 @@ while (sig)
else
{
ev_ctx vctx;
- pdkim_pubkey * p;
/* Make sure we have all required signature tags */
if (!( sig->domain && *sig->domain
@@ -1604,7 +1624,8 @@ while (sig)
&& sig->headernames && *sig->headernames
&& sig->bodyhash.data
&& sig->sighash.data
- && sig->algo > -1
+ && sig->keytype >= 0
+ && sig->hashtype >= 0
&& sig->version
) )
{
@@ -1629,11 +1650,41 @@ while (sig)
goto NEXT_VERIFY;
}
+ DEBUG(D_acl)
+ {
+ debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
+ pdkim_hexprint(sig->sighash.data, sig->sighash.len);
+ }
+
if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
goto NEXT_VERIFY;
+ /* If the pubkey limits to a list of specific hashes, ignore sigs that
+ do not have the hash part of the sig algorithm matching */
+
+ if (sig->pubkey->hashes)
+ {
+ const uschar * list = sig->pubkey->hashes, * ele;
+ int sep = ':';
+ while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
+ if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
+ if (!ele)
+ {
+ DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
+ sig->pubkey->hashes,
+ pdkim_keytypes[sig->keytype],
+ pdkim_hashes[sig->hashtype].dkim_hashname);
+ sig->verify_status = PDKIM_VERIFY_FAIL;
+ sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
+ goto NEXT_VERIFY;
+ }
+ }
+
/* Check the signature */
- if ((*err = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
+/*XXX needs extension for non-RSA */
+ if ((*err = exim_dkim_verify(&vctx,
+ pdkim_hashes[sig->hashtype].exim_hashmethod,
+ &hhash, &sig->sighash)))
{
DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
sig->verify_status = PDKIM_VERIFY_FAIL;
@@ -1659,8 +1710,6 @@ NEXT_VERIFY:
debug_printf("\n");
}
}
-
- sig = sig->next;
}
/* If requested, set return pointer to signature(s) */
@@ -1691,40 +1740,45 @@ return ctx;
/* -------------------------------------------------------------------------- */
-DLLEXPORT pdkim_ctx *
-pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo,
- BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *),
- const uschar ** errstr)
+/*XXX ? needs extension to cover non-RSA algo? */
+
+DLLEXPORT pdkim_signature *
+pdkim_init_sign(pdkim_ctx * ctx,
+ uschar * domain, uschar * selector, uschar * privkey,
+ uschar * hashname, const uschar ** errstr)
{
-pdkim_ctx * ctx;
+int hashtype;
pdkim_signature * sig;
-if (!domain || !selector || !rsa_privkey)
+if (!domain || !selector || !privkey)
return NULL;
-ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature));
-memset(ctx, 0, sizeof(pdkim_ctx));
-
-ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
-ctx->linebuf = CS (ctx+1);
-
-DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
+/* Allocate & init one signature struct */
-sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN);
+sig = store_get(sizeof(pdkim_signature));
memset(sig, 0, sizeof(pdkim_signature));
sig->bodylength = -1;
-ctx->sig = sig;
sig->domain = string_copy(US domain);
sig->selector = string_copy(US selector);
-sig->rsa_privkey = string_copy(US rsa_privkey);
-sig->algo = algo;
+sig->privkey = string_copy(US privkey);
+/*XXX no keytype yet; comes from privkey */
-if (!exim_sha_init(&sig->body_hash_ctx,
- algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
+for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
+ if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
+ { sig->hashtype = hashtype; break; }
+if (hashtype >= nelem(pdkim_hashes))
+ {
+ DEBUG(D_acl)
+ debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
+ return NULL;
+ }
+
+if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
{
- DEBUG(D_acl) debug_printf("PDKIM: hash setup internal error\n");
+ DEBUG(D_acl)
+ debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
return NULL;
}
@@ -1733,29 +1787,27 @@ DEBUG(D_acl)
pdkim_signature s = *sig;
ev_ctx vctx;
- debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
debug_printf("WARNING: bad dkim key in dns\n");
- debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
-return ctx;
+return sig;
}
/* -------------------------------------------------------------------------- */
-DLLEXPORT int
-pdkim_set_optional(pdkim_ctx *ctx,
- char *sign_headers,
- char *identity,
+DLLEXPORT void
+pdkim_set_optional(pdkim_signature * sig,
+ char * sign_headers,
+ char * identity,
int canon_headers,
int canon_body,
long bodylength,
unsigned long created,
unsigned long expires)
{
-pdkim_signature * sig = ctx->sig;
-
if (identity)
sig->identity = string_copy(US identity);
@@ -1768,14 +1820,26 @@ sig->bodylength = bodylength;
sig->created = created;
sig->expires = expires;
-return PDKIM_OK;
+return;
+}
+
+
+
+void
+pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
+ int(*dns_txt_callback)(char *, char *))
+{
+memset(ctx, 0, sizeof(pdkim_ctx));
+ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
+ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
+DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
}
void
pdkim_init(void)
{
-exim_rsa_init();
+exim_dkim_init();
}
diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h
index 8c477f744..e82f26c05 100644
--- a/src/src/pdkim/pdkim.h
+++ b/src/src/pdkim/pdkim.h
@@ -51,25 +51,23 @@
#define PDKIM_VERIFY_FAIL_BODY 1
#define PDKIM_VERIFY_FAIL_MESSAGE 2
-#define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE 3
-#define PDKIM_VERIFY_INVALID_BUFFER_SIZE 4
-#define PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD 5
-#define PDKIM_VERIFY_INVALID_PUBKEY_IMPORT 6
-#define PDKIM_VERIFY_INVALID_SIGNATURE_ERROR 7
-#define PDKIM_VERIFY_INVALID_DKIM_VERSION 8
+#define PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH 3
+#define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE 4
+#define PDKIM_VERIFY_INVALID_BUFFER_SIZE 5
+#define PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD 6
+#define PDKIM_VERIFY_INVALID_PUBKEY_IMPORT 7
+#define PDKIM_VERIFY_INVALID_SIGNATURE_ERROR 8
+#define PDKIM_VERIFY_INVALID_DKIM_VERSION 9
/* -------------------------------------------------------------------------- */
/* Some parameter values */
#define PDKIM_QUERYMETHOD_DNS_TXT 0
-#define PDKIM_ALGO_RSA_SHA256 0
-#define PDKIM_ALGO_RSA_SHA1 1
-
#define PDKIM_CANON_SIMPLE 0
#define PDKIM_CANON_RELAXED 1
-#define PDKIM_HASH_SHA256 0
-#define PDKIM_HASH_SHA1 1
+/*XXX change to enums */
+#define PDKIM_HASH_SHA256 1
#define PDKIM_KEYTYPE_RSA 0
@@ -97,14 +95,14 @@ typedef struct sha2_context sha2_context;
/* -------------------------------------------------------------------------- */
/* Public key as (usually) fetched from DNS */
typedef struct pdkim_pubkey {
- uschar *version; /* v= */
- uschar *granularity; /* g= */
+ const uschar * version; /* v= */
+ const uschar *granularity; /* g= */
+ const uschar * hashes; /* h= */
#ifdef notdef
- uschar *hashes; /* h= */
uschar *keytype; /* k= */
#endif
- uschar *srvtype; /* s= */
+ const uschar *srvtype; /* s= */
uschar *notes; /* n= */
blob key; /* p= */
@@ -115,15 +113,15 @@ typedef struct pdkim_pubkey {
/* -------------------------------------------------------------------------- */
/* Signature as it appears in a DKIM-Signature header */
typedef struct pdkim_signature {
+ struct pdkim_signature * next;
/* Bits stored in a DKIM signature header --------------------------- */
/* (v=) The version, as an integer. Currently, always "1" */
int version;
- /* (a=) The signature algorithm. Either PDKIM_ALGO_RSA_SHA256
- or PDKIM_ALGO_RSA_SHA1 */
- int algo;
+ int keytype; /* PDKIM_KEYTYPE_RSA */
+ int hashtype; /* pdkim_hashes index */
/* (c=x/) Header canonicalization method. Either PDKIM_CANON_SIMPLE
or PDKIM_CANON_RELAXED */
@@ -169,7 +167,7 @@ typedef struct pdkim_signature {
/* (bh=) Raw body hash data, along with its length in bytes */
blob bodyhash;
- /* Folded DKIM-Signature: header. Singing only, NULL for verifying.
+ /* Folded DKIM-Signature: header. Signing only, NULL for verifying.
Ready for insertion into the message. Note: Folded using CRLFTB,
but final line terminator is NOT included. Note2: This buffer is
free()d when you call pdkim_free_ctx(). */
@@ -226,19 +224,17 @@ typedef struct pdkim_signature {
Caution: is NULL if signing or if no record was retrieved. */
pdkim_pubkey *pubkey;
- /* Pointer to the next pdkim_signature signature. NULL if signing or if
- this is the last signature. */
- void *next;
-
/* Properties below this point are used internally only ------------- */
/* Per-signature helper variables ----------------------------------- */
hctx body_hash_ctx;
unsigned long signed_body_bytes; /* How many body bytes we hashed */
+ int num_buffered_blanklines;
pdkim_stringlist *headers; /* Raw headers included in the sig */
+
/* Signing specific ------------------------------------------------- */
- uschar * rsa_privkey; /* Private RSA key */
+ uschar * privkey; /* Private key */
uschar * sign_headers; /* To-be-signed header names */
uschar * rawsig_no_b_val; /* Original signature header w/o b= tag value. */
} pdkim_signature;
@@ -266,9 +262,8 @@ typedef struct pdkim_ctx {
uschar *cur_header;
int cur_header_size;
int cur_header_len;
- char *linebuf;
+ uschar *linebuf;
int linebuf_offset;
- int num_buffered_crlf;
int num_headers;
pdkim_stringlist *headers; /* Raw headers for verification */
} pdkim_ctx;
@@ -285,21 +280,24 @@ extern "C" {
void pdkim_init (void);
+void pdkim_init_context (pdkim_ctx *, BOOL, int(*)(char *, char *));
+
DLLEXPORT
-pdkim_ctx *pdkim_init_sign (char *, char *, char *, int,
- BOOL, int(*)(char *, char *), const uschar **);
+pdkim_signature *pdkim_init_sign (pdkim_ctx *,
+ uschar *, uschar *, uschar *, uschar *,
+ const uschar **);
DLLEXPORT
pdkim_ctx *pdkim_init_verify (int(*)(char *, char *), BOOL);
DLLEXPORT
-int pdkim_set_optional (pdkim_ctx *, char *, char *,int, int,
+void pdkim_set_optional (pdkim_signature *, char *, char *,int, int,
long,
unsigned long,
unsigned long);
DLLEXPORT
-int pdkim_feed (pdkim_ctx *, char *, int);
+int pdkim_feed (pdkim_ctx *, uschar *, int);
DLLEXPORT
int pdkim_feed_finish (pdkim_ctx *, pdkim_signature **, const uschar **);
@@ -309,6 +307,8 @@ void pdkim_free_ctx (pdkim_ctx *);
const uschar * pdkim_errstr(int);
+uschar * dkim_sig_to_a_tag(const pdkim_signature * sig);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/src/pdkim/pdkim_hash.h b/src/src/pdkim/pdkim_hash.h
index 143cd19df..008f277b3 100644
--- a/src/src/pdkim/pdkim_hash.h
+++ b/src/src/pdkim/pdkim_hash.h
@@ -19,11 +19,11 @@
#include "../blob.h"
#include "../hash.h"
-#ifdef RSA_OPENSSL
+#ifdef SIGN_OPENSSL
# include <openssl/rsa.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
-#elif defined(RSA_GNUTLS)
+#elif defined(SIGN_GNUTLS)
# include <gnutls/gnutls.h>
# include <gnutls/x509.h>
#endif
diff --git a/src/src/pdkim/rsa.c b/src/src/pdkim/signing.c
index 950c617c7..e8cb297ca 100644
--- a/src/src/pdkim/rsa.c
+++ b/src/src/pdkim/signing.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2016 Exim maintainers
*
- * RSA signing/verification interface
+ * signing/verification interface
*/
#include "../exim.h"
@@ -15,21 +15,21 @@
#endif
#include "crypt_ver.h"
-#include "rsa.h"
+#include "signing.h"
/******************************************************************************/
-#ifdef RSA_GNUTLS
+#ifdef SIGN_GNUTLS
void
-exim_rsa_init(void)
+exim_dkim_init(void)
{
}
/* accumulate data (gnutls-only). String to be appended must be nul-terminated. */
blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
{
int len = b->len;
b->data = string_append(b->data, alloc, &len, 1, s);
@@ -43,7 +43,7 @@ return b;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
{
gnutls_datum_t k;
int rc;
@@ -51,14 +51,8 @@ int rc;
k.data = privkey_pem;
k.size = strlen(privkey_pem);
-if ( (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS
- /*|| (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
- GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS */
- )
- return gnutls_strerror(rc);
-
-if ( /* (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS
- ||*/ (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
+if ( (rc = gnutls_x509_privkey_init(&sign_ctx->key)) != GNUTLS_E_SUCCESS
+ || (rc = gnutls_x509_privkey_import(sign_ctx->key, &k,
GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS
)
return gnutls_strerror(rc);
@@ -76,31 +70,38 @@ sign hash.
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
+exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig)
{
+gnutls_digest_algorithm_t dig;
gnutls_datum_t k;
size_t sigsize = 0;
int rc;
const uschar * ret = NULL;
+switch (hash)
+ {
+ case HASH_SHA1: dig = GNUTLS_DIG_SHA1; break;
+ case HASH_SHA2_256: dig = GNUTLS_DIG_SHA256; break;
+ case HASH_SHA2_512: dig = GNUTLS_DIG_SHA512; break;
+ default: return US"nonhandled hash type";
+ }
+
/* Allocate mem for signature */
k.data = data->data;
k.size = data->len;
-(void) gnutls_x509_privkey_sign_data(sign_ctx->rsa,
- is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
+(void) gnutls_x509_privkey_sign_data(sign_ctx->key, dig,
0, &k, NULL, &sigsize);
sig->data = store_get(sigsize);
sig->len = sigsize;
/* Do signing */
-if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->rsa,
- is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
+if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->key, dig,
0, &k, sig->data, &sigsize)) != GNUTLS_E_SUCCESS
)
ret = gnutls_strerror(rc);
-gnutls_x509_privkey_deinit(sign_ctx->rsa);
+gnutls_x509_privkey_deinit(sign_ctx->key);
return ret;
}
@@ -110,18 +111,18 @@ return ret;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
{
gnutls_datum_t k;
int rc;
const uschar * ret = NULL;
-gnutls_pubkey_init(&verify_ctx->rsa);
+gnutls_pubkey_init(&verify_ctx->key);
k.data = pubkey_der->data;
k.size = pubkey_der->len;
-if ((rc = gnutls_pubkey_import(verify_ctx->rsa, &k, GNUTLS_X509_FMT_DER))
+if ((rc = gnutls_pubkey_import(verify_ctx->key, &k, GNUTLS_X509_FMT_DER))
!= GNUTLS_E_SUCCESS)
ret = gnutls_strerror(rc);
return ret;
@@ -132,30 +133,39 @@ return ret;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
+exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig)
{
+gnutls_sign_algorithm_t algo;
gnutls_datum_t k, s;
int rc;
const uschar * ret = NULL;
+/*XXX needs extension for non-rsa */
+switch (hash)
+ {
+ case HASH_SHA1: algo = GNUTLS_SIGN_RSA_SHA1; break;
+ case HASH_SHA2_256: algo = GNUTLS_SIGN_RSA_SHA256; break;
+ case HASH_SHA2_512: algo = GNUTLS_SIGN_RSA_SHA512; break;
+ default: return US"nonhandled hash type";
+ }
+
k.data = data_hash->data;
k.size = data_hash->len;
s.data = sig->data;
s.size = sig->len;
-if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->rsa,
- is_sha1 ? GNUTLS_SIGN_RSA_SHA1 : GNUTLS_SIGN_RSA_SHA256,
- 0, &k, &s)) < 0)
+if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->key, algo, 0, &k, &s)) < 0)
ret = gnutls_strerror(rc);
-gnutls_pubkey_deinit(verify_ctx->rsa);
+gnutls_pubkey_deinit(verify_ctx->key);
return ret;
}
-#elif defined(RSA_GCRYPT)
+#elif defined(SIGN_GCRYPT)
/******************************************************************************/
+/* This variant is used under pre-3.0.0 GnuTLS. Only rsa-sha1 and rsa-sha256 */
/* Internal service routine:
@@ -217,7 +227,7 @@ return NULL;
void
-exim_rsa_init(void)
+exim_dkim_init(void)
{
/* Version check should be the very first call because it
makes sure that important subsystems are initialized. */
@@ -259,7 +269,7 @@ return;
String to be appended must be nul-terminated. */
blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
{
return b; /*dummy*/
}
@@ -270,13 +280,16 @@ return b; /*dummy*/
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
{
uschar * s1, * s2;
blob der;
long alen;
int rc;
+/*XXX will need extension to _spot_ as well as handle a
+non-RSA key? I think... */
+
/*
* RSAPrivateKey ::= SEQUENCE
* version Version,
@@ -325,6 +338,7 @@ if ( (s1 = as_mpi(&der, &sign_ctx->n))
)
return s1;
+#ifdef extreme_debug
DEBUG(D_acl) debug_printf_indent("rsa_signing_init:\n");
{
uschar * s;
@@ -345,6 +359,7 @@ DEBUG(D_acl) debug_printf_indent("rsa_signing_init:\n");
gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->qp);
debug_printf_indent(" QP: %s\n", s);
}
+#endif
return NULL;
asn_err: return US asn1_strerror(rc);
@@ -360,13 +375,28 @@ sign hash.
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
+exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig)
{
+char * sexp_hash;
gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
gcry_mpi_t m_sig;
uschar * errstr;
gcry_error_t gerr;
+/*XXX will need extension for hash types (though, possibly, should
+be re-specced to not rehash but take an already-hashed value? Actually
+current impl looks WRONG - it _is_ given a hash so should not be
+re-hashing. Has this been tested?
+
+Will need extension for non-RSA sugning algos. */
+
+switch (hash)
+ {
+ case HASH_SHA1: sexp_hash = "(data(flags pkcs1)(hash sha1 %b))"; break;
+ case HASH_SHA2_256: sexp_hash = "(data(flags pkcs1)(hash sha256 %b))"; break;
+ default: return US"nonhandled hash type";
+ }
+
#define SIGSPACE 128
sig->data = store_get(SIGSPACE);
@@ -381,10 +411,7 @@ if ( (gerr = gcry_sexp_build (&s_key, NULL,
sign_ctx->n, sign_ctx->e,
sign_ctx->d, sign_ctx->p,
sign_ctx->q, sign_ctx->qp))
- || (gerr = gcry_sexp_build (&s_hash, NULL,
- is_sha1
- ? "(data(flags pkcs1)(hash sha1 %b))"
- : "(data(flags pkcs1)(hash sha256 %b))",
+ || (gerr = gcry_sexp_build (&s_hash, NULL, sexp_hash,
(int) data->len, CS data->data))
|| (gerr = gcry_pk_sign (&s_sig, s_hash, s_key))
)
@@ -398,12 +425,14 @@ if ( !(s_sig = gcry_sexp_find_token(s_sig, "s", 0))
m_sig = gcry_sexp_nth_mpi(s_sig, 1, GCRYMPI_FMT_USG);
+#ifdef extreme_debug
DEBUG(D_acl)
{
uschar * s;
gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, m_sig);
debug_printf_indent(" SG: %s\n", s);
}
+#endif
gerr = gcry_mpi_print(GCRYMPI_FMT_USG, sig->data, SIGSPACE, &sig->len, m_sig);
if (gerr)
@@ -421,7 +450,7 @@ return NULL;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
{
/*
in code sequence per b81207d2bfa92 rsa_parse_public_key() and asn1_get_mpi()
@@ -480,6 +509,7 @@ if ( (errstr = as_mpi(pubkey_der, &verify_ctx->n))
)
return errstr;
+#ifdef extreme_debug
DEBUG(D_acl) debug_printf_indent("rsa_verify_init:\n");
{
uschar * s;
@@ -489,6 +519,7 @@ DEBUG(D_acl) debug_printf_indent("rsa_verify_init:\n");
debug_printf_indent(" E : %s\n", s);
}
+#endif
return NULL;
asn_err:
@@ -501,24 +532,30 @@ DEBUG(D_acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc));
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
+exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig)
{
/*
cf. libgnutls 2.8.5 _wrap_gcry_pk_verify()
*/
+char * sexp_hash;
gcry_mpi_t m_sig;
gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
gcry_error_t gerr;
uschar * stage;
+/*XXX needs extension for SHA512 */
+switch (hash)
+ {
+ case HASH_SHA1: sexp_hash = "(data(flags pkcs1)(hash sha1 %b))"; break;
+ case HASH_SHA2_256: sexp_hash = "(data(flags pkcs1)(hash sha256 %b))"; break;
+ default: return US"nonhandled hash type";
+ }
+
if ( (stage = US"pkey sexp build",
gerr = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))",
verify_ctx->n, verify_ctx->e))
|| (stage = US"data sexp build",
- gerr = gcry_sexp_build (&s_hash, NULL,
- is_sha1
- ? "(data(flags pkcs1)(hash sha1 %b))"
- : "(data(flags pkcs1)(hash sha256 %b))",
+ gerr = gcry_sexp_build (&s_hash, NULL, sexp_hash,
(int) data_hash->len, CS data_hash->data))
|| (stage = US"sig mpi scan",
gerr = gcry_mpi_scan(&m_sig, GCRYMPI_FMT_USG, sig->data, sig->len, NULL))
@@ -545,18 +582,19 @@ return NULL;
-#elif defined(RSA_OPENSSL)
+#elif defined(SIGN_OPENSSL)
/******************************************************************************/
void
-exim_rsa_init(void)
+exim_dkim_init(void)
{
+ERR_load_crypto_strings();
}
/* accumulate data (gnutls-only) */
blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
{
return b; /*dummy*/
}
@@ -566,29 +604,12 @@ return b; /*dummy*/
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
{
-uschar * p, * q;
-int len;
-
-/* Convert PEM to DER */
-if ( !(p = Ustrstr(privkey_pem, "-----BEGIN RSA PRIVATE KEY-----"))
- || !(q = Ustrstr(p+=31, "-----END RSA PRIVATE KEY-----"))
- )
- return US"Bad PEM wrapping";
-
-*q = '\0';
-if ((len = b64decode(p, &p)) < 0)
- return US"b64decode failed";
-
-if (!(sign_ctx->rsa = d2i_RSAPrivateKey(NULL, CUSS &p, len)))
- {
- char ssl_errstring[256];
- ERR_load_crypto_strings(); /*XXX move to a startup routine */
- ERR_error_string(ERR_get_error(), ssl_errstring);
- return string_copy(US ssl_errstring);
- }
+BIO * bp = BIO_new_mem_buf(privkey_pem, -1);
+if (!(sign_ctx->key = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL)))
+ return US ERR_error_string(ERR_get_error(), NULL);
return NULL;
}
@@ -599,53 +620,60 @@ return NULL;
OR
sign hash.
-Return: NULL for success, or an error string */
+Return: NULL for success with the signaature in the sig blob, or an error string */
const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
+exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig)
{
-uint len;
-const uschar * ret = NULL;
+const EVP_MD * md;
+EVP_PKEY_CTX * ctx;
+size_t siglen;
-/* Allocate mem for signature */
-len = RSA_size(sign_ctx->rsa);
-sig->data = store_get(len);
-sig->len = len;
+switch (hash)
+ {
+ case HASH_SHA1: md = EVP_sha1(); break;
+ case HASH_SHA2_256: md = EVP_sha256(); break;
+ case HASH_SHA2_512: md = EVP_sha512(); break;
+ default: return US"nonhandled hash type";
+ }
-/* Do signing */
-if (RSA_sign(is_sha1 ? NID_sha1 : NID_sha256,
- CUS data->data, data->len,
- US sig->data, &len, sign_ctx->rsa) != 1)
+if ( (ctx = EVP_PKEY_CTX_new(sign_ctx->key, NULL))
+ && EVP_PKEY_sign_init(ctx) > 0
+ && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0
+ && EVP_PKEY_CTX_set_signature_md(ctx, md) > 0
+ && EVP_PKEY_sign(ctx, NULL, &siglen, data->data, data->len) > 0
+ )
{
- char ssl_errstring[256];
- ERR_load_crypto_strings(); /*XXX move to a startup routine */
- ERR_error_string(ERR_get_error(), ssl_errstring);
- ret = string_copy(US ssl_errstring);
+ /* Allocate mem for signature */
+ sig->data = store_get(siglen);
+
+ if (EVP_PKEY_sign(ctx, sig->data, &siglen, data->data, data->len) > 0)
+ {
+ EVP_PKEY_CTX_free(ctx);
+ sig->len = siglen;
+ return NULL;
+ }
}
-RSA_free(sign_ctx->rsa);
-return ret;;
+if (ctx) EVP_PKEY_CTX_free(ctx);
+return US ERR_error_string(ERR_get_error(), NULL);
}
/* import public key (from DER in memory)
-Return: nULL for success, or an error string */
+Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
{
-const uschar * p = CUS pubkey_der->data;
-const uschar * ret = NULL;
+const uschar * s = pubkey_der->data;
-if (!(verify_ctx->rsa = d2i_RSA_PUBKEY(NULL, &p, (long) pubkey_der->len)))
- {
- char ssl_errstring[256];
- ERR_load_crypto_strings(); /*XXX move to a startup routine */
- ERR_error_string(ERR_get_error(), ssl_errstring);
- ret = string_copy(CUS ssl_errstring);
- }
-return ret;
+/*XXX hmm, we never free this */
+
+if ((verify_ctx->key = d2i_PUBKEY(NULL, &s, pubkey_der->len)))
+ return NULL;
+return US ERR_error_string(ERR_get_error(), NULL);
}
@@ -655,23 +683,34 @@ return ret;
Return: NULL for success, or an error string */
const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
+exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig)
{
-const uschar * ret = NULL;
+const EVP_MD * md;
+EVP_PKEY_CTX * ctx;
-if (RSA_verify(is_sha1 ? NID_sha1 : NID_sha256,
- CUS data_hash->data, data_hash->len,
- US sig->data, (uint) sig->len, verify_ctx->rsa) != 1)
+switch (hash)
{
- char ssl_errstring[256];
- ERR_load_crypto_strings(); /*XXX move to a startup routine */
- ERR_error_string(ERR_get_error(), ssl_errstring);
- ret = string_copy(US ssl_errstring);
+ case HASH_SHA1: md = EVP_sha1(); break;
+ case HASH_SHA2_256: md = EVP_sha256(); break;
+ case HASH_SHA2_512: md = EVP_sha512(); break;
+ default: return US"nonhandled hash type";
}
-return ret;
+
+if ( (ctx = EVP_PKEY_CTX_new(verify_ctx->key, NULL))
+ && EVP_PKEY_verify_init(ctx) > 0
+ && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0
+ && EVP_PKEY_CTX_set_signature_md(ctx, md) > 0
+ && EVP_PKEY_verify(ctx, sig->data, sig->len,
+ data_hash->data, data_hash->len) == 1
+ )
+ { EVP_PKEY_CTX_free(ctx); return NULL; }
+
+if (ctx) EVP_PKEY_CTX_free(ctx);
+return US ERR_error_string(ERR_get_error(), NULL);
}
+
#endif
/******************************************************************************/
diff --git a/src/src/pdkim/rsa.h b/src/src/pdkim/signing.h
index 6018eba64..abf255988 100644
--- a/src/src/pdkim/rsa.h
+++ b/src/src/pdkim/signing.h
@@ -12,15 +12,15 @@
#include "crypt_ver.h"
-#ifdef RSA_OPENSSL
+#ifdef SIGN_OPENSSL
# include <openssl/rsa.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
-#elif defined(RSA_GNUTLS)
+#elif defined(SIGN_GNUTLS)
# include <gnutls/gnutls.h>
# include <gnutls/x509.h>
# include <gnutls/abstract.h>
-#elif defined(RSA_GCRYPT)
+#elif defined(SIGN_GCRYPT)
# include <gcrypt.h>
# include <libtasn1.h>
#endif
@@ -28,29 +28,30 @@
#include "../blob.h"
-#ifdef RSA_OPENSSL
+#ifdef SIGN_OPENSSL
typedef struct {
- RSA * rsa;
+ EVP_PKEY * key;
} es_ctx;
typedef struct {
- RSA * rsa;
+ EVP_PKEY * key;
} ev_ctx;
-#elif defined(RSA_GNUTLS)
+#elif defined(SIGN_GNUTLS)
typedef struct {
- gnutls_x509_privkey_t rsa;
+ gnutls_x509_privkey_t key;
} es_ctx;
typedef struct {
- gnutls_pubkey_t rsa;
+ gnutls_pubkey_t key;
} ev_ctx;
-#elif defined(RSA_GCRYPT)
+#elif defined(SIGN_GCRYPT)
typedef struct {
+ int keytype;
gcry_mpi_t n;
gcry_mpi_t e;
gcry_mpi_t d;
@@ -62,6 +63,7 @@ typedef struct {
} es_ctx;
typedef struct {
+ int keytype;
gcry_mpi_t n;
gcry_mpi_t e;
} ev_ctx;
@@ -69,13 +71,13 @@ typedef struct {
#endif
-extern void exim_rsa_init(void);
-extern blob * exim_rsa_data_append(blob *, int *, uschar *);
+extern void exim_dkim_init(void);
+extern blob * exim_dkim_data_append(blob *, int *, uschar *);
-extern const uschar * exim_rsa_signing_init(uschar *, es_ctx *);
-extern const uschar * exim_rsa_sign(es_ctx *, BOOL, blob *, blob *);
-extern const uschar * exim_rsa_verify_init(blob *, ev_ctx *);
-extern const uschar * exim_rsa_verify(ev_ctx *, BOOL, blob *, blob *);
+extern const uschar * exim_dkim_signing_init(uschar *, es_ctx *);
+extern const uschar * exim_dkim_sign(es_ctx *, hashmethod, blob *, blob *);
+extern const uschar * exim_dkim_verify_init(blob *, ev_ctx *);
+extern const uschar * exim_dkim_verify(ev_ctx *, hashmethod, blob *, blob *);
#endif /*DISABLE_DKIM*/
/* End of File */
diff --git a/src/src/perl.c b/src/src/perl.c
index 92218a6ef..5f4f0d98d 100644
--- a/src/src/perl.c
+++ b/src/src/perl.c
@@ -60,7 +60,7 @@ XS(xs_expand_string)
str = expand_string(US SvPV(ST(0), len));
ST(0) = sv_newmortal();
if (str != NULL)
- sv_setpv(ST(0), (const char *) str);
+ sv_setpv(ST(0), CCS str);
else if (!expand_string_forcedfail)
croak("syntax error in Exim::expand_string argument: %s",
expand_string_message);
diff --git a/src/src/queue.c b/src/src/queue.c
index 50e4aaef3..8b0494b26 100644
--- a/src/src/queue.c
+++ b/src/src/queue.c
@@ -405,28 +405,18 @@ if (!recurse)
*p = 0;
p = big_buffer;
- sprintf(CS p, "pid=%d", (int)queue_run_pid);
- while (*p != 0) p++;
+ p += sprintf(CS p, "pid=%d", (int)queue_run_pid);
if (extras[0] != 0)
- {
- sprintf(CS p, " -q%s", extras);
- while (*p != 0) p++;
- }
+ p += sprintf(CS p, " -q%s", extras);
- if (deliver_selectstring != NULL)
- {
- sprintf(CS p, " -R%s %s", deliver_selectstring_regex? "r" : "",
+ if (deliver_selectstring)
+ p += sprintf(CS p, " -R%s %s", deliver_selectstring_regex? "r" : "",
deliver_selectstring);
- while (*p != 0) p++;
- }
- if (deliver_selectstring_sender != NULL)
- {
- sprintf(CS p, " -S%s %s", deliver_selectstring_sender_regex? "r" : "",
+ if (deliver_selectstring_sender)
+ p += sprintf(CS p, " -S%s %s", deliver_selectstring_sender_regex? "r" : "",
deliver_selectstring_sender);
- while (*p != 0) p++;
- }
log_detail = string_copy(big_buffer);
if (*queue_name)
@@ -438,10 +428,10 @@ if (!recurse)
/* If deliver_selectstring is a regex, compile it. */
-if (deliver_selectstring != NULL && deliver_selectstring_regex)
+if (deliver_selectstring && deliver_selectstring_regex)
selectstring_regex = regex_must_compile(deliver_selectstring, TRUE, FALSE);
-if (deliver_selectstring_sender != NULL && deliver_selectstring_sender_regex)
+if (deliver_selectstring_sender && deliver_selectstring_sender_regex)
selectstring_regex_sender =
regex_must_compile(deliver_selectstring_sender, TRUE, FALSE);
@@ -890,7 +880,7 @@ for (reset_point = store_get(0); f; f = f->next)
if (Ustat(fname, &statbuf) == 0)
size = message_size + statbuf.st_size - SPOOL_DATA_START_OFFSET + 1;
- i = (now - received_time)/60; /* minutes on queue */
+ i = (now - received_time.tv_sec)/60; /* minutes on queue */
if (i > 90)
{
i = (i + 30)/60;
@@ -1142,10 +1132,14 @@ if (action != MSG_SHOW_COPY) printf("Message %s ", id);
switch(action)
{
case MSG_SHOW_COPY:
- deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE);
- deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE);
- transport_write_message(1, NULL, 0);
- break;
+ {
+ transport_ctx tctx = {{0}};
+ deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE);
+ deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE);
+ tctx.u.fd = 1;
+ transport_write_message(&tctx, 0);
+ break;
+ }
case MSG_FREEZE:
diff --git a/src/src/rda.c b/src/src/rda.c
index 995909b09..fb3edac17 100644
--- a/src/src/rda.c
+++ b/src/src/rda.c
@@ -715,30 +715,28 @@ if ((pid = fork()) == 0)
yield == FF_FAIL || yield == FF_FREEZE)
{
address_item *addr;
- for (addr = *generated; addr != NULL; addr = addr->next)
+ for (addr = *generated; addr; addr = addr->next)
{
int reply_options = 0;
if ( rda_write_string(fd, addr->address) != 0
- || write(fd, &(addr->mode), sizeof(addr->mode))
- != sizeof(addr->mode)
- || write(fd, &(addr->flags), sizeof(addr->flags))
- != sizeof(addr->flags)
+ || write(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
+ || write(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
|| rda_write_string(fd, addr->prop.errors_address) != 0
)
goto bad;
- if (addr->pipe_expandn != NULL)
+ if (addr->pipe_expandn)
{
uschar **pp;
- for (pp = addr->pipe_expandn; *pp != NULL; pp++)
+ for (pp = addr->pipe_expandn; *pp; pp++)
if (rda_write_string(fd, *pp) != 0)
goto bad;
}
if (rda_write_string(fd, NULL) != 0)
goto bad;
- if (addr->reply == NULL)
+ if (!addr->reply)
{
if (write(fd, &reply_options, sizeof(int)) != sizeof(int)) /* 0 means no reply */
goto bad;
@@ -889,9 +887,9 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
/* Next comes the mode and the flags fields */
- if (read(fd, &(addr->mode), sizeof(addr->mode)) != sizeof(addr->mode) ||
- read(fd, &(addr->flags), sizeof(addr->flags)) != sizeof(addr->flags) ||
- !rda_read_string(fd, &(addr->prop.errors_address))) goto DISASTER;
+ if (read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode) ||
+ read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags) ||
+ !rda_read_string(fd, &addr->prop.errors_address)) goto DISASTER;
/* Next comes a possible setting for $thisaddress and any numerical
variables for pipe expansion, terminated by a NULL string. The maximum
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 8b685c8fc..f831f866a 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -11,136 +11,12 @@ implementation of the conditional .ifdef etc. */
#include "exim.h"
-extern char **environ;
-
-static void fn_smtp_receive_timeout(const uschar * name, const uschar * str);
-static void save_config_line(const uschar* line);
-static void save_config_position(const uschar *file, int line);
-static void print_config(BOOL admin, BOOL terse);
-static void readconf_options_auths(void);
-
-
-#define CSTATE_STACK_SIZE 10
-
-const uschar *config_directory = NULL;
-
-
-/* Structure for chain (stack) of .included files */
-
-typedef struct config_file_item {
- struct config_file_item *next;
- const uschar *filename;
- const uschar *directory;
- FILE *file;
- int lineno;
-} config_file_item;
-
-/* Structure for chain of configuration lines (-bP config) */
-
-typedef struct config_line_item {
- struct config_line_item *next;
- uschar *line;
-} config_line_item;
-
-static config_line_item* config_lines;
-
-/* Structure of table of conditional words and their state transitions */
-
-typedef struct cond_item {
- uschar *name;
- int namelen;
- int action1;
- int action2;
- int pushpop;
-} cond_item;
-
-/* Structure of table of syslog facility names and values */
-
-typedef struct syslog_fac_item {
- uschar *name;
- int value;
-} syslog_fac_item;
-
-/* constants */
-static const char * const hidden = "<value not displayable>";
-
-/* Static variables */
-
-static config_file_item *config_file_stack = NULL; /* For includes */
-
-static uschar *syslog_facility_str = NULL;
-static uschar next_section[24];
-static uschar time_buffer[24];
-
-/* State variables for conditional loading (.ifdef / .else / .endif) */
-
-static int cstate = 0;
-static int cstate_stack_ptr = -1;
-static int cstate_stack[CSTATE_STACK_SIZE];
-
-/* Table of state transitions for handling conditional inclusions. There are
-four possible state transitions:
-
- .ifdef true
- .ifdef false
- .elifdef true (or .else)
- .elifdef false
-
-.endif just causes the previous cstate to be popped off the stack */
-
-static int next_cstate[3][4] =
- {
- /* State 0: reading from file, or reading until next .else or .endif */
- { 0, 1, 2, 2 },
- /* State 1: condition failed, skipping until next .else or .endif */
- { 2, 2, 0, 1 },
- /* State 2: skipping until .endif */
- { 2, 2, 2, 2 },
- };
-
-/* Table of conditionals and the states to set. For each name, there are four
-values: the length of the name (to save computing it each time), the state to
-set if a macro was found in the line, the state to set if a macro was not found
-in the line, and a stack manipulation setting which is:
-
- -1 pull state value off the stack
- 0 don't alter the stack
- +1 push value onto stack, before setting new state
-*/
-
-static cond_item cond_list[] = {
- { US"ifdef", 5, 0, 1, 1 },
- { US"ifndef", 6, 1, 0, 1 },
- { US"elifdef", 7, 2, 3, 0 },
- { US"elifndef", 8, 3, 2, 0 },
- { US"else", 4, 2, 2, 0 },
- { US"endif", 5, 0, 0, -1 }
-};
-
-static int cond_list_size = sizeof(cond_list)/sizeof(cond_item);
-
-/* Table of syslog facility names and their values */
-
-static syslog_fac_item syslog_list[] = {
- { US"mail", LOG_MAIL },
- { US"user", LOG_USER },
- { US"news", LOG_NEWS },
- { US"uucp", LOG_UUCP },
- { US"local0", LOG_LOCAL0 },
- { US"local1", LOG_LOCAL1 },
- { US"local2", LOG_LOCAL2 },
- { US"local3", LOG_LOCAL3 },
- { US"local4", LOG_LOCAL4 },
- { US"local5", LOG_LOCAL5 },
- { US"local6", LOG_LOCAL6 },
- { US"local7", LOG_LOCAL7 },
- { US"daemon", LOG_DAEMON }
-};
-
-static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item);
-
-
+#ifdef MACRO_PREDEF
+# include "macro_predef.h"
+#endif
+static uschar * syslog_facility_str;
+static void fn_smtp_receive_timeout(const uschar *, const uschar *);
/*************************************************
* Main configuration options *
@@ -217,6 +93,7 @@ static optionlist optionlist_config[] = {
{ "check_spool_inodes", opt_int, &check_spool_inodes },
{ "check_spool_space", opt_Kint, &check_spool_space },
{ "chunking_advertise_hosts", opt_stringptr, &chunking_advertise_hosts },
+ { "commandline_checks_require_admin", opt_bool,&commandline_checks_require_admin },
{ "daemon_smtp_port", opt_stringptr|opt_hidden, &daemon_smtp_port },
{ "daemon_smtp_ports", opt_stringptr, &daemon_smtp_port },
{ "daemon_startup_retries", opt_int, &daemon_startup_retries },
@@ -432,6 +309,7 @@ static optionlist optionlist_config[] = {
#endif
{ "split_spool_directory", opt_bool, &split_spool_directory },
{ "spool_directory", opt_stringptr, &spool_directory },
+ { "spool_wireformat", opt_bool, &spool_wireformat },
#ifdef LOOKUP_SQLITE
{ "sqlite_lock_timeout", opt_int, &sqlite_lock_timeout },
#endif
@@ -494,7 +372,166 @@ static optionlist optionlist_config[] = {
{ "write_rejectlog", opt_bool, &write_rejectlog }
};
+#ifndef MACRO_PREDEF
static int optionlist_config_size = nelem(optionlist_config);
+#endif
+
+
+#ifdef MACRO_PREDEF
+
+static void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {/*Dummy*/}
+
+void
+options_main(void)
+{
+options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN", NULL);
+}
+
+void
+options_auths(void)
+{
+struct auth_info * ai;
+uschar buf[64];
+
+options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
+
+for (ai = auths_available; ai->driver_name[0]; ai++)
+ {
+ spf(buf, sizeof(buf), US"_DRIVER_AUTHENTICATOR_%T", ai->driver_name);
+ builtin_macro_create(buf);
+ options_from_list(ai->options, (unsigned)*ai->options_count, US"AUTHENTICATOR", ai->driver_name);
+ }
+}
+
+
+#else /*!MACRO_PREDEF*/
+
+extern char **environ;
+
+static void save_config_line(const uschar* line);
+static void save_config_position(const uschar *file, int line);
+static void print_config(BOOL admin, BOOL terse);
+
+
+#define CSTATE_STACK_SIZE 10
+
+const uschar *config_directory = NULL;
+
+
+/* Structure for chain (stack) of .included files */
+
+typedef struct config_file_item {
+ struct config_file_item *next;
+ const uschar *filename;
+ const uschar *directory;
+ FILE *file;
+ int lineno;
+} config_file_item;
+
+/* Structure for chain of configuration lines (-bP config) */
+
+typedef struct config_line_item {
+ struct config_line_item *next;
+ uschar *line;
+} config_line_item;
+
+static config_line_item* config_lines;
+
+/* Structure of table of conditional words and their state transitions */
+
+typedef struct cond_item {
+ uschar *name;
+ int namelen;
+ int action1;
+ int action2;
+ int pushpop;
+} cond_item;
+
+/* Structure of table of syslog facility names and values */
+
+typedef struct syslog_fac_item {
+ uschar *name;
+ int value;
+} syslog_fac_item;
+
+/* constants */
+static const char * const hidden = "<value not displayable>";
+
+/* Static variables */
+
+static config_file_item *config_file_stack = NULL; /* For includes */
+
+static uschar *syslog_facility_str = NULL;
+static uschar next_section[24];
+static uschar time_buffer[24];
+
+/* State variables for conditional loading (.ifdef / .else / .endif) */
+
+static int cstate = 0;
+static int cstate_stack_ptr = -1;
+static int cstate_stack[CSTATE_STACK_SIZE];
+
+/* Table of state transitions for handling conditional inclusions. There are
+four possible state transitions:
+
+ .ifdef true
+ .ifdef false
+ .elifdef true (or .else)
+ .elifdef false
+
+.endif just causes the previous cstate to be popped off the stack */
+
+static int next_cstate[3][4] =
+ {
+ /* State 0: reading from file, or reading until next .else or .endif */
+ { 0, 1, 2, 2 },
+ /* State 1: condition failed, skipping until next .else or .endif */
+ { 2, 2, 0, 1 },
+ /* State 2: skipping until .endif */
+ { 2, 2, 2, 2 },
+ };
+
+/* Table of conditionals and the states to set. For each name, there are four
+values: the length of the name (to save computing it each time), the state to
+set if a macro was found in the line, the state to set if a macro was not found
+in the line, and a stack manipulation setting which is:
+
+ -1 pull state value off the stack
+ 0 don't alter the stack
+ +1 push value onto stack, before setting new state
+*/
+
+static cond_item cond_list[] = {
+ { US"ifdef", 5, 0, 1, 1 },
+ { US"ifndef", 6, 1, 0, 1 },
+ { US"elifdef", 7, 2, 3, 0 },
+ { US"elifndef", 8, 3, 2, 0 },
+ { US"else", 4, 2, 2, 0 },
+ { US"endif", 5, 0, 0, -1 }
+};
+
+static int cond_list_size = sizeof(cond_list)/sizeof(cond_item);
+
+/* Table of syslog facility names and their values */
+
+static syslog_fac_item syslog_list[] = {
+ { US"mail", LOG_MAIL },
+ { US"user", LOG_USER },
+ { US"news", LOG_NEWS },
+ { US"uucp", LOG_UUCP },
+ { US"local0", LOG_LOCAL0 },
+ { US"local1", LOG_LOCAL1 },
+ { US"local2", LOG_LOCAL2 },
+ { US"local3", LOG_LOCAL3 },
+ { US"local4", LOG_LOCAL4 },
+ { US"local5", LOG_LOCAL5 },
+ { US"local6", LOG_LOCAL6 },
+ { US"local7", LOG_LOCAL7 },
+ { US"daemon", LOG_DAEMON }
+};
+
+static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item);
+
@@ -528,7 +565,7 @@ for (r = routers; r; r = r->next)
for (i = 0; i < *ri->options_count; i++)
{
if ((ri->options[i].type & opt_mask) != opt_stringptr) continue;
- if (p == (char *)(r->options_block) + (long int)(ri->options[i].value))
+ if (p == CS (r->options_block) + (long int)(ri->options[i].value))
return US ri->options[i].name;
}
}
@@ -541,8 +578,8 @@ for (t = transports; t; t = t->next)
optionlist * op = &ti->options[i];
if ((op->type & opt_mask) != opt_stringptr) continue;
if (p == ( op->type & opt_public
- ? (char *)t
- : (char *)t->options_block
+ ? CS t
+ : CS t->options_block
)
+ (long int)op->value)
return US op->name;
@@ -559,41 +596,27 @@ return US"";
* Deal with an assignment to a macro *
*************************************************/
-/* We have a new definition. The macro_item structure includes a final vector
-called "name" which is one byte long. Thus, adding "namelen" gives us enough
-room to store the "name" string.
-If a builtin macro we place at head of list, else tail. This lets us lazy-create
-builtins. */
+/* We have a new definition; append to the list.
+
+Args:
+ name Name of the macro. Must be in storage persistent past the call
+ val Expansion result for the macro. Ditto persistence.
+*/
macro_item *
-macro_create(const uschar * name, const uschar * val,
- BOOL command_line, BOOL builtin)
+macro_create(const uschar * name, const uschar * val, BOOL command_line)
{
-unsigned namelen = Ustrlen(name);
-macro_item * m = store_get(sizeof(macro_item) + namelen);
+macro_item * m = store_get(sizeof(macro_item));
-/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val) */
-if (!macros)
- {
- macros = m;
- mlast = m;
- m->next = NULL;
- }
-else if (builtin)
- {
- m->next = macros;
- macros = m;
- }
-else
- {
- mlast->next = m;
- mlast = m;
- m->next = NULL;
- }
+/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); */
+m->next = NULL;
m->command_line = command_line;
-m->namelen = namelen;
-m->replacement = string_copy(val);
-Ustrcpy(m->name, name);
+m->namelen = Ustrlen(name);
+m->replen = Ustrlen(val);
+m->name = name;
+m->replacement = val;
+mlast->next = m;
+mlast = m;
return m;
}
@@ -680,230 +703,23 @@ if (m && m->command_line) return;
if (redef)
if (m)
+ {
+ m->replen = Ustrlen(s);
m->replacement = string_copy(s);
+ }
else
log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "can't redefine an undefined macro "
"\"%s\"", name);
/* We have a new definition. */
else
- (void) macro_create(name, s, FALSE, FALSE);
+ (void) macro_create(string_copy(name), string_copy(s), FALSE);
}
-/*************************************************/
-/* Create compile-time feature macros */
-static void
-readconf_features(void)
-{
-/* Probably we could work out a static initialiser for wherever
-macros are stored, but this will do for now. Some names are awkward
-due to conflicts with other common macros. */
-
-#ifdef SUPPORT_CRYPTEQ
- macro_create(US"_HAVE_CRYPTEQ", US"y", FALSE, TRUE);
-#endif
-#if HAVE_ICONV
- macro_create(US"_HAVE_ICONV", US"y", FALSE, TRUE);
-#endif
-#if HAVE_IPV6
- macro_create(US"_HAVE_IPV6", US"y", FALSE, TRUE);
-#endif
-#ifdef HAVE_SETCLASSRESOURCES
- macro_create(US"_HAVE_SETCLASSRESOURCES", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_PAM
- macro_create(US"_HAVE_PAM", US"y", FALSE, TRUE);
-#endif
-#ifdef EXIM_PERL
- macro_create(US"_HAVE_PERL", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPAND_DLFUNC
- macro_create(US"_HAVE_DLFUNC", US"y", FALSE, TRUE);
-#endif
-#ifdef USE_TCP_WRAPPERS
- macro_create(US"_HAVE_TCPWRAPPERS", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_TLS
- macro_create(US"_HAVE_TLS", US"y", FALSE, TRUE);
-# ifdef USE_GNUTLS
- macro_create(US"_HAVE_GNUTLS", US"y", FALSE, TRUE);
-# else
- macro_create(US"_HAVE_OPENSSL", US"y", FALSE, TRUE);
-# endif
-#endif
-#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
- macro_create(US"_HAVE_TRANSLATE_IP_ADDRESS", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
- macro_create(US"_HAVE_MOVE_FROZEN_MESSAGES", US"y", FALSE, TRUE);
-#endif
-#ifdef WITH_CONTENT_SCAN
- macro_create(US"_HAVE_CONTENT_SCANNING", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_DKIM
- macro_create(US"_HAVE_DKIM", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_DNSSEC
- macro_create(US"_HAVE_DNSSEC", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_EVENT
- macro_create(US"_HAVE_EVENT", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_I18N
- macro_create(US"_HAVE_I18N", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_OCSP
- macro_create(US"_HAVE_OCSP", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_PRDR
- macro_create(US"_HAVE_PRDR", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_PROXY
- macro_create(US"_HAVE_PROXY", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_SOCKS
- macro_create(US"_HAVE_SOCKS", US"y", FALSE, TRUE);
-#endif
-#ifdef TCP_FASTOPEN
- macro_create(US"_HAVE_TCP_FASTOPEN", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_LMDB
- macro_create(US"_HAVE_LMDB", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_SPF
- macro_create(US"_HAVE_SPF", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_SRS
- macro_create(US"_HAVE_SRS", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_BRIGHTMAIL
- macro_create(US"_HAVE_BRIGHTMAIL", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DANE
- macro_create(US"_HAVE_DANE", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DCC
- macro_create(US"_HAVE_DCC", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DMARC
- macro_create(US"_HAVE_DMARC", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DSN_INFO
- macro_create(US"_HAVE_DSN_INFO", US"y", FALSE, TRUE);
-#endif
-
-#ifdef LOOKUP_LSEARCH
- macro_create(US"_HAVE_LOOKUP_LSEARCH", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_CDB
- macro_create(US"_HAVE_LOOKUP_CDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_DBM
- macro_create(US"_HAVE_LOOKUP_DBM", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_DNSDB
- macro_create(US"_HAVE_LOOKUP_DNSDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_DSEARCH
- macro_create(US"_HAVE_LOOKUP_DSEARCH", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_IBASE
- macro_create(US"_HAVE_LOOKUP_IBASE", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_LDAP
- macro_create(US"_HAVE_LOOKUP_LDAP", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_LMDB
- macro_create(US"_HAVE_LOOKUP_LMDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_MYSQL
- macro_create(US"_HAVE_LOOKUP_MYSQL", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_NIS
- macro_create(US"_HAVE_LOOKUP_NIS", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_NISPLUS
- macro_create(US"_HAVE_LOOKUP_NISPLUS", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_ORACLE
- macro_create(US"_HAVE_LOOKUP_ORACLE", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_PASSWD
- macro_create(US"_HAVE_LOOKUP_PASSWD", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_PGSQL
- macro_create(US"_HAVE_LOOKUP_PGSQL", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_REDIS
- macro_create(US"_HAVE_LOOKUP_REDIS", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_SQLITE
- macro_create(US"_HAVE_LOOKUP_SQLITE", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_TESTDB
- macro_create(US"_HAVE_LOOKUP_TESTDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_WHOSON
- macro_create(US"_HAVE_LOOKUP_WHOSON", US"y", FALSE, TRUE);
-#endif
-
-#ifdef TRANSPORT_APPENDFILE
-# ifdef SUPPORT_MAILDIR
- macro_create(US"_HAVE_TRANSPORT_APPEND_MAILDIR", US"y", FALSE, TRUE);
-# endif
-# ifdef SUPPORT_MAILSTORE
- macro_create(US"_HAVE_TRANSPORT_APPEND_MAILSTORE", US"y", FALSE, TRUE);
-# endif
-# ifdef SUPPORT_MBX
- macro_create(US"_HAVE_TRANSPORT_APPEND_MBX", US"y", FALSE, TRUE);
-# endif
-#endif
-}
-
-
-void
-readconf_options_from_list(optionlist * opts, unsigned nopt, const uschar * section, uschar * group)
-{
-int i;
-const uschar * s;
-
-/* The 'previously-defined-substring' rule for macros in config file
-lines is done so for these builtin macros: we know that the table
-we source from is in strict alpha order, hence the builtins portion
-of the macros list is in reverse-alpha (we prepend them) - so longer
-macros that have substrings are always discovered first during
-expansion. */
-
-for (i = 0; i < nopt; i++) if (*(s = US opts[i].name) && *s != '*')
- if (group)
- macro_create(string_sprintf("_OPT_%T_%T_%T", section, group, s), US"y", FALSE, TRUE);
- else
- macro_create(string_sprintf("_OPT_%T_%T", section, s), US"y", FALSE, TRUE);
-}
-
-
-static void
-readconf_options(void)
-{
-readconf_options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN", NULL);
-readconf_options_routers();
-readconf_options_transports();
-readconf_options_auths();
-}
-
-static void
-macros_create_builtin(void)
-{
-readconf_features();
-readconf_options();
-macros_builtin_created = TRUE;
-}
-
-
/*************************************************
* Read configuration line *
*************************************************/
@@ -1014,22 +830,10 @@ for (;;)
if (*s != '=') s = ss; /* Not a macro definition */
}
- /* If the builtin macros are not yet defined, and the line contains an
- underscrore followed by an one of the three possible chars used by
- builtins, create them. */
+ /* Skip leading chars which cannot start a macro name, to avoid multiple
+ pointless rescans in Ustrstr calls. */
- if (!macros_builtin_created)
- {
- const uschar * t, * p;
- uschar c;
- for (t = s; (p = CUstrchr(t, '_')); t = p+1)
- if (c = p[1], c == 'O' || c == 'D' || c == 'H')
- {
-/* fprintf(stderr, "%s: builtins create triggered by '%s'\n", __FUNCTION__, s); */
- macros_create_builtin();
- break;
- }
- }
+ while (*s && !isupper(*s) && *s != '_') s++;
/* For each defined macro, scan the line (from after XXX= if present),
replacing all occurrences of the macro. */
@@ -1037,18 +841,17 @@ for (;;)
macro_found = FALSE;
for (m = macros; m; m = m->next)
{
- uschar *p, *pp;
- uschar *t = s;
+ uschar * p, *pp;
+ uschar * t = s;
while ((p = Ustrstr(t, m->name)) != NULL)
{
int moveby;
- int replen = Ustrlen(m->replacement);
-/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, t) */
+/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, ss); */
/* Expand the buffer if necessary */
- while (newlen - m->namelen + replen + 1 > big_buffer_size)
+ while (newlen - m->namelen + m->replen + 1 > big_buffer_size)
{
int newsize = big_buffer_size + BIG_BUFFER_SIZE;
uschar *newbuffer = store_malloc(newsize);
@@ -1067,13 +870,14 @@ for (;;)
same macro. */
pp = p + m->namelen;
- if ((moveby = replen - m->namelen) != 0)
+ if ((moveby = m->replen - m->namelen) != 0)
{
- memmove(p + replen, pp, (big_buffer + newlen) - pp + 1);
+ memmove(p + m->replen, pp, (big_buffer + newlen) - pp + 1);
newlen += moveby;
}
- Ustrncpy(p, m->replacement, replen);
- t = p + replen;
+ Ustrncpy(p, m->replacement, m->replen);
+ t = p + m->replen;
+ while (*t && !isupper(*t) && *t != '_') t++;
macro_found = TRUE;
}
}
@@ -1470,7 +1274,7 @@ ol = find_option(name2, oltop, last);
if (ol == NULL) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
"Exim internal error: missing set flag for %s", name);
return (data_block == NULL)? (BOOL *)(ol->value) :
- (BOOL *)((uschar *)data_block + (long int)(ol->value));
+ (BOOL *)(US data_block + (long int)(ol->value));
}
@@ -1896,9 +1700,13 @@ switch (type)
const uschar * list = sptr;
uschar * s;
uschar * list_o = *str_target;
+ int size = 0, len = 0;
+
+ if (list_o)
+ size = (len = Ustrlen(list_o)) + 1;
while ((s = string_nextinlist(&list, &sep_i, NULL, 0)))
- list_o = string_append_listele(list_o, sep_o, s);
+ list_o = string_append_listele(list_o, &size, &len, sep_o, s);
if (list_o)
*str_target = string_copy_malloc(list_o);
}
@@ -1939,8 +1747,8 @@ switch (type)
}
else
{
- chain = (rewrite_rule **)((uschar *)data_block + (long int)(ol2->value));
- flagptr = (int *)((uschar *)data_block + (long int)(ol3->value));
+ chain = (rewrite_rule **)(US data_block + (long int)(ol2->value));
+ flagptr = (int *)(US data_block + (long int)(ol3->value));
}
while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
@@ -1972,7 +1780,7 @@ switch (type)
if (data_block == NULL)
*((uschar **)(ol2->value)) = ss;
else
- *((uschar **)((uschar *)data_block + (long int)(ol2->value))) = ss;
+ *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
if (ss != NULL)
{
@@ -1991,7 +1799,7 @@ switch (type)
if (data_block == NULL)
*((uid_t *)(ol->value)) = uid;
else
- *((uid_t *)((uschar *)data_block + (long int)(ol->value))) = uid;
+ *((uid_t *)(US data_block + (long int)(ol->value))) = uid;
/* Set the flag indicating a fixed value is set */
@@ -2013,7 +1821,7 @@ switch (type)
if (data_block == NULL)
*((gid_t *)(ol2->value)) = pw->pw_gid;
else
- *((gid_t *)((uschar *)data_block + (long int)(ol2->value))) = pw->pw_gid;
+ *((gid_t *)(US data_block + (long int)(ol2->value))) = pw->pw_gid;
*set_flag = TRUE;
}
}
@@ -2035,7 +1843,7 @@ switch (type)
if (data_block == NULL)
*((uschar **)(ol2->value)) = ss;
else
- *((uschar **)((uschar *)data_block + (long int)(ol2->value))) = ss;
+ *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
if (ss != NULL)
{
@@ -2053,7 +1861,7 @@ switch (type)
if (data_block == NULL)
*((gid_t *)(ol->value)) = gid;
else
- *((gid_t *)((uschar *)data_block + (long int)(ol->value))) = gid;
+ *((gid_t *)(US data_block + (long int)(ol->value))) = gid;
*(get_set_flag(name, oltop, last, data_block)) = TRUE;
break;
@@ -2083,7 +1891,7 @@ switch (type)
if (data_block == NULL)
*((uid_t **)(ol->value)) = list;
else
- *((uid_t **)((uschar *)data_block + (long int)(ol->value))) = list;
+ *((uid_t **)(US data_block + (long int)(ol->value))) = list;
p = op;
while (count-- > 1)
@@ -2124,7 +1932,7 @@ switch (type)
if (data_block == NULL)
*((gid_t **)(ol->value)) = list;
else
- *((gid_t **)((uschar *)data_block + (long int)(ol->value))) = list;
+ *((gid_t **)(US data_block + (long int)(ol->value))) = list;
p = op;
while (count-- > 1)
@@ -2160,7 +1968,7 @@ switch (type)
if (data_block == NULL)
*((uschar **)(ol2->value)) = sptr;
else
- *((uschar **)((uschar *)data_block + (long int)(ol2->value))) = sptr;
+ *((uschar **)(US data_block + (long int)(ol2->value))) = sptr;
freesptr = FALSE;
break;
}
@@ -2198,7 +2006,7 @@ switch (type)
int bit = 1 << ((ol->type >> 16) & 31);
int *ptr = (data_block == NULL)?
(int *)(ol->value) :
- (int *)((uschar *)data_block + (long int)ol->value);
+ (int *)(US data_block + (long int)ol->value);
if (boolvalue) *ptr |= bit; else *ptr &= ~bit;
break;
}
@@ -2208,7 +2016,7 @@ switch (type)
if (data_block == NULL)
*((BOOL *)(ol->value)) = boolvalue;
else
- *((BOOL *)((uschar *)data_block + (long int)(ol->value))) = boolvalue;
+ *((BOOL *)(US data_block + (long int)(ol->value))) = boolvalue;
/* Verify fudge */
@@ -2221,7 +2029,7 @@ switch (type)
if (data_block == NULL)
*((BOOL *)(ol2->value)) = boolvalue;
else
- *((BOOL *)((uschar *)data_block + (long int)(ol2->value))) = boolvalue;
+ *((BOOL *)(US data_block + (long int)(ol2->value))) = boolvalue;
}
}
@@ -2236,7 +2044,7 @@ switch (type)
if (data_block == NULL)
*((BOOL *)(ol2->value)) = TRUE;
else
- *((BOOL *)((uschar *)data_block + (long int)(ol2->value))) = TRUE;
+ *((BOOL *)(US data_block + (long int)(ol2->value))) = TRUE;
}
}
break;
@@ -2299,7 +2107,7 @@ switch (type)
if (data_block == NULL)
*((int *)(ol->value)) = value;
else
- *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+ *((int *)(US data_block + (long int)(ol->value))) = value;
break;
/* Integer held in K: again, allow octal and hex formats, and suffixes K, M
@@ -2349,7 +2157,7 @@ switch (type)
if (data_block == NULL)
*((int *)(ol->value)) = value;
else
- *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+ *((int *)(US data_block + (long int)(ol->value))) = value;
break;
/* Fixed-point number: held to 3 decimal places. */
@@ -2390,7 +2198,7 @@ switch (type)
if (data_block == NULL)
*((int *)(ol->value)) = value;
else
- *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+ *((int *)(US data_block + (long int)(ol->value))) = value;
break;
/* There's a special routine to read time values. */
@@ -2403,7 +2211,7 @@ switch (type)
if (data_block == NULL)
*((int *)(ol->value)) = value;
else
- *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+ *((int *)(US data_block + (long int)(ol->value))) = value;
break;
/* A time list is a list of colon-separated times, with the first
@@ -2415,7 +2223,7 @@ switch (type)
int count = 0;
int *list = (data_block == NULL)?
(int *)(ol->value) :
- (int *)((uschar *)data_block + (long int)(ol->value));
+ (int *)(US data_block + (long int)(ol->value));
if (*s != 0) for (count = 1; count <= list[0] - 2; count++)
{
@@ -2492,10 +2300,10 @@ t /= 24;
d = t % 7;
w = t/7;
-if (w > 0) { sprintf(CS p, "%dw", w); while (*p) p++; }
-if (d > 0) { sprintf(CS p, "%dd", d); while (*p) p++; }
-if (h > 0) { sprintf(CS p, "%dh", h); while (*p) p++; }
-if (m > 0) { sprintf(CS p, "%dm", m); while (*p) p++; }
+if (w > 0) p += sprintf(CS p, "%dw", w);
+if (d > 0) p += sprintf(CS p, "%dd", d);
+if (h > 0) p += sprintf(CS p, "%dh", h);
+if (m > 0) p += sprintf(CS p, "%dm", m);
if (s > 0 || p == time_buffer) sprintf(CS p, "%ds", s);
return time_buffer;
@@ -2565,7 +2373,7 @@ if (options_block != NULL)
{
if ((ol->type & opt_public) == 0)
options_block = (void *)(((driver_instance *)options_block)->options_block);
- value = (void *)((uschar *)options_block + (long int)value);
+ value = (void *)(US options_block + (long int)value);
}
switch(ol->type & opt_mask)
@@ -2654,7 +2462,7 @@ switch(ol->type & opt_mask)
{
void *value2 = ol2->value;
if (options_block != NULL)
- value2 = (void *)((uschar *)options_block + (long int)value2);
+ value2 = (void *)(US options_block + (long int)value2);
s = *((uschar **)value2);
if (!no_labels) printf("%s = ", name);
printf("%s\n", (s == NULL)? US"" : string_printing(s));
@@ -2688,7 +2496,7 @@ switch(ol->type & opt_mask)
{
void *value2 = ol2->value;
if (options_block != NULL)
- value2 = (void *)((uschar *)options_block + (long int)value2);
+ value2 = (void *)(US options_block + (long int)value2);
s = *((uschar **)value2);
if (!no_labels) printf("%s = ", name);
printf("%s\n", (s == NULL)? US"" : string_printing(s));
@@ -2783,7 +2591,7 @@ switch(ol->type & opt_mask)
{
void *value2 = ol2->value;
if (options_block != NULL)
- value2 = (void *)((uschar *)options_block + (long int)value2);
+ value2 = (void *)(US options_block + (long int)value2);
s = *((uschar **)value2);
if (s != NULL)
{
@@ -3038,7 +2846,6 @@ else if (Ustrcmp(type, "macro") == 0)
fprintf(stderr, "exim: permission denied\n");
exit(EXIT_FAILURE);
}
- if (!macros_builtin_created) macros_create_builtin();
for (m = macros; m; m = m->next)
if (!name || Ustrcmp(name, m->name) == 0)
{
@@ -3466,6 +3273,11 @@ a macro definition. */
while ((s = get_config_line()) != NULL)
{
+
+ if (config_lineno == 1 && Ustrstr(s, "\xef\xbb\xbf") == s)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "found unexpected BOM (Byte Order Mark)");
+
if (isupper(s[0])) read_macro_assignment(s);
else if (Ustrncmp(s, "domainlist", 10) == 0)
@@ -3784,14 +3596,14 @@ if (tls_dh_max_bits < 1024)
"tls_dh_max_bits is too small, must be at least 1024 for interop");
/* If openssl_options is set, validate it */
-if (openssl_options != NULL)
+if (openssl_options)
{
# ifdef USE_GNUTLS
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"openssl_options is set but we're using GnuTLS");
# else
long dummy;
- if (!(tls_openssl_options_parse(openssl_options, &dummy)))
+ if (!tls_openssl_options_parse(openssl_options, &dummy))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"openssl_options parse error: %s", openssl_options);
# endif
@@ -3832,7 +3644,7 @@ init_driver(driver_instance *d, driver_info *drivers_available,
driver_info *dd;
for (dd = drivers_available; dd->driver_name[0] != 0;
- dd = (driver_info *)(((uschar *)dd) + size_of_info))
+ dd = (driver_info *)((US dd) + size_of_info))
{
if (Ustrcmp(d->driver_name, dd->driver_name) == 0)
{
@@ -4045,7 +3857,7 @@ for (ol = d->info->options; ol < d->info->options + count; ol++)
int type = ol->type & opt_mask;
if (type != opt_stringptr) continue;
options_block = ((ol->type & opt_public) == 0)? d->options_block : (void *)d;
- value = *(uschar **)((uschar *)options_block + (long int)(ol->value));
+ value = *(uschar **)(US options_block + (long int)(ol->value));
if (value != NULL && (ss = Ustrstr(value, s)) != NULL)
{
if (ss <= value || (ss[-1] != '$' && ss[-1] != '{') ||
@@ -4121,14 +3933,14 @@ else if (len == 7 && strncmpic(pp, US"timeout", len) == 0)
static int values[] =
{ 'A', 'M', RTEF_CTOUT, RTEF_CTOUT|'A', RTEF_CTOUT|'M' };
- for (i = 0; i < sizeof(extras)/sizeof(uschar *); i++)
+ for (i = 0; i < nelem(extras); i++)
if (strncmpic(x, extras[i], xlen) == 0)
{
*more_errno = values[i];
break;
}
- if (i >= sizeof(extras)/sizeof(uschar *))
+ if (i >= nelem(extras))
if (strncmpic(x, US"DNS", xlen) == 0)
log_write(0, LOG_MAIN|LOG_PANIC, "\"timeout_dns\" is no longer "
"available in retry rules (it has never worked) - treated as "
@@ -4347,21 +4159,6 @@ while ((p = get_config_line()))
* Initialize authenticators *
*************************************************/
-static void
-readconf_options_auths(void)
-{
-struct auth_info * ai;
-
-readconf_options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
-
-for (ai = auths_available; ai->driver_name[0]; ai++)
- {
- macro_create(string_sprintf("_DRIVER_AUTHENTICATOR_%T", ai->driver_name), US"y", FALSE, TRUE);
- readconf_options_from_list(ai->options, (unsigned)*ai->options_count, US"AUTHENTICATOR", ai->driver_name);
- }
-}
-
-
/* Read the authenticators section of the configuration file.
Arguments: none
@@ -4539,7 +4336,7 @@ while(next_section[0] != 0)
{
int bit;
int first = 0;
- int last = sizeof(section_list) / sizeof(uschar *);
+ int last = nelem(section_list);
int mid = last/2;
int n = Ustrlen(next_section);
@@ -4595,6 +4392,7 @@ save_config_position(const uschar *file, int line)
this operates on a global (static) list that holds all the pre-parsed
config lines, we do no further processing here, output formatting and
honouring of <hide> or macros will be done during output */
+
static void
save_config_line(const uschar* line)
{
@@ -4693,6 +4491,7 @@ for (i = config_lines; i; i = i->next)
}
}
+#endif /*!MACRO_PREDEF*/
/* vi: aw ai sw=2
*/
/* End of readconf.c */
diff --git a/src/src/receive.c b/src/src/receive.c
index 7980c324f..65e9fb415 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -84,12 +84,10 @@ receive_check_set_sender(uschar *newsender)
{
uschar *qnewsender;
if (trusted_caller) return TRUE;
-if (newsender == NULL || untrusted_set_sender == NULL) return FALSE;
-qnewsender = (Ustrchr(newsender, '@') != NULL)?
- newsender : string_sprintf("%s@%s", newsender, qualify_domain_sender);
-return
- match_address_list(qnewsender, TRUE, TRUE, CUSS &untrusted_set_sender, NULL, -1,
- 0, NULL) == OK;
+if (!newsender || !untrusted_set_sender) return FALSE;
+qnewsender = Ustrchr(newsender, '@')
+ ? newsender : string_sprintf("%s@%s", newsender, qualify_domain_sender);
+return match_address_list_basic(qnewsender, CUSS &untrusted_set_sender, 0) == OK;
}
@@ -831,7 +829,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
{
message_size++;
if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR;
- (void) cutthrough_put_nl();
+ cutthrough_data_put_nl();
if (ch != '\r') ch_state = 1; else continue;
}
break;
@@ -850,7 +848,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
if (ch == '.')
{
uschar c= ch;
- (void) cutthrough_puts(&c, 1);
+ cutthrough_data_puts(&c, 1);
}
ch_state = 1;
break;
@@ -860,7 +858,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
message_size++;
body_linecount++;
if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR;
- (void) cutthrough_put_nl();
+ cutthrough_data_put_nl();
if (ch == '\r')
{
ch_state = 2;
@@ -881,11 +879,11 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
if (message_size > thismessage_size_limit) return END_SIZE;
}
if(ch == '\n')
- (void) cutthrough_put_nl();
+ cutthrough_data_put_nl();
else
{
uschar c = ch;
- (void) cutthrough_puts(&c, 1);
+ cutthrough_data_puts(&c, 1);
}
}
@@ -921,7 +919,7 @@ BOOL fix_nl = FALSE;
for(;;)
{
- switch ((ch = (bdat_getc)(GETC_BUFFER_UNLIMITED)))
+ switch ((ch = bdat_getc(GETC_BUFFER_UNLIMITED)))
{
case EOF: return END_EOF;
case ERR: return END_PROTOCOL;
@@ -991,7 +989,7 @@ for(;;)
{
message_size++;
if (fout && fputc('\n', fout) == EOF) return END_WERROR;
- (void) cutthrough_put_nl();
+ cutthrough_data_put_nl();
if (ch == '\r') continue; /* don't write CR */
ch_state = MID_LINE;
}
@@ -1008,16 +1006,58 @@ for(;;)
if (message_size > thismessage_size_limit) return END_SIZE;
}
if(ch == '\n')
- (void) cutthrough_put_nl();
+ cutthrough_data_put_nl();
else
{
uschar c = ch;
- (void) cutthrough_puts(&c, 1);
+ cutthrough_data_puts(&c, 1);
}
}
/*NOTREACHED*/
}
+static int
+read_message_bdat_smtp_wire(FILE *fout)
+{
+int ch;
+
+/* Remember that this message uses wireformat. */
+
+DEBUG(D_receive) debug_printf("CHUNKING: writing spoolfile in wire format\n");
+spool_file_wireformat = TRUE;
+
+for (;;)
+ {
+ if (chunking_data_left > 0)
+ {
+ unsigned len = MAX(chunking_data_left, thismessage_size_limit - message_size + 1);
+ uschar * buf = bdat_getbuf(&len);
+
+ message_size += len;
+ if (fout && fwrite(buf, len, 1, fout) != 1) return END_WERROR;
+ }
+ else switch (ch = bdat_getc(GETC_BUFFER_UNLIMITED))
+ {
+ case EOF: return END_EOF;
+ case EOD: return END_DOT;
+ case ERR: return END_PROTOCOL;
+
+ default:
+ message_size++;
+ /*XXX not done:
+ linelength
+ max_received_linelength
+ body_linecount
+ body_zerocount
+ */
+ if (fout && fputc(ch, fout) == EOF) return END_WERROR;
+ break;
+ }
+ if (message_size > thismessage_size_limit) return END_SIZE;
+ }
+/*NOTREACHED*/
+}
+
@@ -1140,7 +1180,8 @@ switch(where)
case ACL_WHERE_DKIM:
case ACL_WHERE_MIME:
case ACL_WHERE_DATA:
- if (cutthrough.fd >= 0 && (acl_removed_headers || acl_added_headers))
+ if ( cutthrough.fd >= 0 && cutthrough.delivery
+ && (acl_removed_headers || acl_added_headers))
{
log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs"
" will not take effect on cutthrough deliveries");
@@ -1148,11 +1189,11 @@ switch(where)
}
}
-if (acl_removed_headers != NULL)
+if (acl_removed_headers)
{
DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers removed by %s ACL:\n", acl_name);
- for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
+ for (h = header_list; h; h = h->next) if (h->type != htype_old)
{
const uschar * list = acl_removed_headers;
int sep = ':'; /* This is specified as a colon-separated list */
@@ -1170,10 +1211,10 @@ if (acl_removed_headers != NULL)
DEBUG(D_receive|D_acl) debug_printf_indent(">>\n");
}
-if (acl_added_headers == NULL) return;
+if (!acl_added_headers) return;
DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers added by %s ACL:\n", acl_name);
-for (h = acl_added_headers; h != NULL; h = next)
+for (h = acl_added_headers; h; h = next)
{
next = h->next;
@@ -1262,7 +1303,7 @@ add_host_info_for_log(uschar * s, int * sizeptr, int * ptrptr)
if (sender_fullhost)
{
if (LOGGING(dnssec) && sender_host_dnssec) /*XXX sender_helo_dnssec? */
- s = string_cat(s, sizeptr, ptrptr, US" DS");
+ s = string_catn(s, sizeptr, ptrptr, US" DS", 3);
s = string_append(s, sizeptr, ptrptr, 2, US" H=", sender_fullhost);
if (LOGGING(incoming_interface) && interface_address != NULL)
{
@@ -1270,9 +1311,14 @@ if (sender_fullhost)
string_sprintf(" I=[%s]:%d", interface_address, interface_port));
}
}
-if (sender_ident != NULL)
+if (tcp_in_fastopen && !tcp_in_fastopen_logged)
+ {
+ s = string_catn(s, sizeptr, ptrptr, US" TFO", 4);
+ tcp_in_fastopen_logged = TRUE;
+ }
+if (sender_ident)
s = string_append(s, sizeptr, ptrptr, 2, US" U=", sender_ident);
-if (received_protocol != NULL)
+if (received_protocol)
s = string_append(s, sizeptr, ptrptr, 2, US" P=", received_protocol);
return s;
}
@@ -1307,36 +1353,30 @@ unsigned long mbox_size;
header_line *my_headerlist;
uschar *user_msg, *log_msg;
int mime_part_count_buffer = -1;
+uschar * mbox_filename;
int rc = OK;
memset(CS rfc822_file_path,0,2048);
/* check if it is a MIME message */
-my_headerlist = header_list;
-while (my_headerlist != NULL)
- {
- /* skip deleted headers */
- if (my_headerlist->type == '*')
- {
- my_headerlist = my_headerlist->next;
- continue;
- }
- if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0)
+
+for (my_headerlist = header_list; my_headerlist; my_headerlist = my_headerlist->next)
+ if ( my_headerlist->type != '*' /* skip deleted headers */
+ && strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0
+ )
{
DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
goto DO_MIME_ACL;
}
- my_headerlist = my_headerlist->next;
- }
DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
return TRUE;
DO_MIME_ACL:
+
/* make sure the eml mbox file is spooled up */
-mbox_file = spool_mbox(&mbox_size, NULL);
-if (mbox_file == NULL) {
- /* error while spooling */
+if (!(mbox_file = spool_mbox(&mbox_size, NULL, &mbox_filename)))
+ { /* error while spooling */
log_write(0, LOG_MAIN|LOG_PANIC,
"acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
Uunlink(spool_name);
@@ -1348,7 +1388,7 @@ if (mbox_file == NULL) {
message_id[0] = 0; /* Indicate no message accepted */
*smtp_reply_ptr = US""; /* Indicate reply already sent */
return FALSE; /* Indicate skip to end of receive function */
-};
+ }
mime_is_rfc822 = 0;
@@ -1372,14 +1412,13 @@ if (Ustrlen(rfc822_file_path) > 0)
/* check if we must check any message/rfc822 attachments */
if (rc == OK)
{
- uschar temp_path[1024];
+ uschar * scandir;
struct dirent * entry;
DIR * tempdir;
- (void) string_format(temp_path, sizeof(temp_path), "%s/scan/%s",
- spool_directory, message_id);
+ scandir = string_copyn(mbox_filename, Ustrrchr(mbox_filename, '/') - mbox_filename);
- tempdir = opendir(CS temp_path);
+ tempdir = opendir(CS scandir);
for (;;)
{
if (!(entry = readdir(tempdir)))
@@ -1387,7 +1426,7 @@ if (rc == OK)
if (strncmpic(US entry->d_name, US"__rfc822_", 9) == 0)
{
(void) string_format(rfc822_file_path, sizeof(rfc822_file_path),
- "%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
+ "%s/%s", scandir, entry->d_name);
DEBUG(D_receive) debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n",
rfc822_file_path);
break;
@@ -1653,7 +1692,7 @@ search_tidyup();
cutthrough delivery with the no-spool option. It shouldn't be possible
to set up the combination, but just in case kill any ongoing connection. */
if (extract_recip || !smtp_input)
- cancel_cutthrough_connection("not smtp input");
+ cancel_cutthrough_connection(TRUE, US"not smtp input");
/* Initialize the chain of headers by setting up a place-holder for Received:
header. Temporarily mark it as "old", i.e. not to be used. We keep header_last
@@ -1709,9 +1748,9 @@ message id creation below. */
/* For other uses of the received time we can operate with granularity of one
second, and for that we use the global variable received_time. This is for
-things like ultimate message timeouts. */
+things like ultimate message timeouts.XXX */
-received_time = message_id_tv.tv_sec;
+received_time = message_id_tv;
/* If SMTP input, set the special handler for timeouts. The alarm() calls
happen in the smtp_getc() function when it refills its buffer. */
@@ -2160,7 +2199,7 @@ for (;;)
sender_address,
sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"",
sender_ident ? " U=" : "", sender_ident ? sender_ident : US"");
- smtp_printf("552 Message header not CRLF terminated\r\n");
+ smtp_printf("552 Message header not CRLF terminated\r\n", FALSE);
bdat_flush_data();
smtp_reply = US"";
goto TIDYUP; /* Skip to end of function */
@@ -2988,26 +3027,24 @@ inbound is, but inbound chunking ought to be ok with outbound plain.
Could we do onward CHUNKING given inbound CHUNKING?
*/
if (chunking_state > CHUNKING_OFFERED)
- cancel_cutthrough_connection("chunking active");
+ cancel_cutthrough_connection(FALSE, US"chunking active");
/* Cutthrough delivery:
We have to create the Received header now rather than at the end of reception,
so the timestamp behaviour is a change to the normal case.
-XXX Ensure this gets documented XXX.
Having created it, send the headers to the destination. */
-if (cutthrough.fd >= 0)
+
+if (cutthrough.fd >= 0 && cutthrough.delivery)
{
if (received_count > received_headers_max)
{
- cancel_cutthrough_connection("too many headers");
+ cancel_cutthrough_connection(TRUE, US"too many headers");
if (smtp_input) receive_swallow_smtp(); /* Swallow incoming SMTP */
log_write(0, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: "
"Too many \"Received\" headers",
sender_address,
- (sender_fullhost == NULL)? "" : " H=",
- (sender_fullhost == NULL)? US"" : sender_fullhost,
- (sender_ident == NULL)? "" : " U=",
- (sender_ident == NULL)? US"" : sender_ident);
+ sender_fullhost ? "H=" : "", sender_fullhost ? sender_fullhost : US"",
+ sender_ident ? "U=" : "", sender_ident ? sender_ident : US"");
message_id[0] = 0; /* Indicate no message accepted */
smtp_reply = US"550 Too many \"Received\" headers - suspected mail loop";
goto TIDYUP; /* Skip to end of function */
@@ -3087,9 +3124,11 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
{
if (smtp_input)
{
- message_ended = chunking_state > CHUNKING_OFFERED
- ? read_message_bdat_smtp(data_file)
- : read_message_data_smtp(data_file);
+ message_ended = chunking_state <= CHUNKING_OFFERED
+ ? read_message_data_smtp(data_file)
+ : spool_wireformat
+ ? read_message_bdat_smtp_wire(data_file)
+ : read_message_bdat_smtp(data_file);
receive_linecount++; /* The terminating "." line */
}
else message_ended = read_message_data(data_file);
@@ -3105,7 +3144,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
if (smtp_input)
{
Uunlink(spool_name); /* Lose data file when closed */
- cancel_cutthrough_connection("sender closed connection");
+ cancel_cutthrough_connection(TRUE, US"sender closed connection");
message_id[0] = 0; /* Indicate no message accepted */
smtp_reply = handle_lost_connection(US"");
smtp_yield = FALSE;
@@ -3118,7 +3157,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
case END_SIZE:
Uunlink(spool_name); /* Lose the data file when closed */
- cancel_cutthrough_connection("mail too big");
+ cancel_cutthrough_connection(TRUE, US"mail too big");
if (smtp_input) receive_swallow_smtp(); /* Swallow incoming SMTP */
log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: "
@@ -3151,7 +3190,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
case END_PROTOCOL:
Uunlink(spool_name); /* Lose the data file when closed */
- cancel_cutthrough_connection("sender protocol error");
+ cancel_cutthrough_connection(TRUE, US"sender protocol error");
smtp_reply = US""; /* Response already sent */
message_id[0] = 0; /* Indicate no message accepted */
goto TIDYUP; /* Skip to end of function */
@@ -3184,7 +3223,7 @@ if (fflush(data_file) == EOF || ferror(data_file) ||
log_write(0, LOG_MAIN, "Message abandoned: %s", msg);
Uunlink(spool_name); /* Lose the data file */
- cancel_cutthrough_connection("error writing spoolfile");
+ cancel_cutthrough_connection(TRUE, US"error writing spoolfile");
if (smtp_input)
{
@@ -3423,7 +3462,7 @@ else
DEBUG(D_receive)
debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
"skipping remaining items\n", rc, item);
- cancel_cutthrough_connection("dkim acl not ok");
+ cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
break;
}
}
@@ -3467,7 +3506,7 @@ else
int all_pass = OK;
int all_fail = FAIL;
- smtp_printf("353 PRDR content analysis beginning\r\n");
+ smtp_printf("353 PRDR content analysis beginning\r\n", TRUE);
/* Loop through recipients, responses must be in same order received */
for (c = 0; recipients_count > c; c++)
{
@@ -3542,14 +3581,14 @@ else
{
recipients_count = 0;
blackholed_by = US"DATA ACL";
- if (log_msg != NULL)
+ if (log_msg)
blackhole_log_msg = string_sprintf(": %s", log_msg);
- cancel_cutthrough_connection("data acl discard");
+ cancel_cutthrough_connection(TRUE, US"data acl discard");
}
else if (rc != OK)
{
Uunlink(spool_name);
- cancel_cutthrough_connection("data acl not ok");
+ cancel_cutthrough_connection(TRUE, US"data acl not ok");
#ifdef WITH_CONTENT_SCAN
unspool_mbox();
#endif
@@ -3643,6 +3682,7 @@ dcc_ok = 0;
version supplied with Exim always accepts, but this is a hook for sysadmins to
supply their own checking code. The local_scan() function is run even when all
the recipients have been discarded. */
+/*XXS could we avoid this for the standard case, given that few people will use it? */
lseek(data_fd, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
@@ -4148,9 +4188,9 @@ for this message. */
XXX We do not handle queue-only, freezing, or blackholes.
*/
-if(cutthrough.fd >= 0)
+if(cutthrough.fd >= 0 && cutthrough.delivery)
{
- uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the message */
+ uschar * msg = cutthrough_finaldot(); /* Ask the target system to accept the message */
/* Logging was done in finaldot() */
switch(msg[0])
{
@@ -4267,12 +4307,12 @@ if (smtp_input)
else if (chunking_state > CHUNKING_OFFERED)
{
- smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n",
+ smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n", FALSE,
chunking_datasize, message_size+message_linecount, message_id);
chunking_state = CHUNKING_OFFERED;
}
else
- smtp_printf("250 OK id=%s\r\n", message_id);
+ smtp_printf("250 OK id=%s\r\n", FALSE, message_id);
if (host_checking)
fprintf(stdout,
@@ -4286,7 +4326,7 @@ if (smtp_input)
smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
fake_response_text);
else
- smtp_printf("%.1024s\r\n", smtp_reply);
+ smtp_printf("%.1024s\r\n", FALSE, smtp_reply);
switch (cutthrough_done)
{
@@ -4297,7 +4337,6 @@ if (smtp_input)
Uunlink(spool_fname(US"input", message_subdir, message_id, US"-D"));
Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
- message_id[0] = 0; /* Prevent a delivery from starting */
break;
case TMP_REJ:
@@ -4307,12 +4346,15 @@ if (smtp_input)
Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
}
- message_id[0] = 0; /* Prevent a delivery from starting */
default:
break;
}
- cutthrough.delivery = FALSE;
- cutthrough.defer_pass = FALSE;
+ if (cutthrough_done != NOT_TRIED)
+ {
+ message_id[0] = 0; /* Prevent a delivery from starting */
+ cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
+ cutthrough.defer_pass = FALSE;
+ }
}
/* For batched SMTP, generate an error message on failure, and do
diff --git a/src/src/regex.c b/src/src/regex.c
index 9274f9095..3560bef52 100644
--- a/src/src/regex.c
+++ b/src/src/regex.c
@@ -105,7 +105,7 @@ regex_match_string = NULL;
if (!mime_stream) /* We are in the DATA ACL */
{
- if (!(mbox_file = spool_mbox(&mbox_size, NULL)))
+ if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL)))
{ /* error while spooling */
log_write(0, LOG_MAIN|LOG_PANIC,
"regex acl condition: error while creating mbox spool file");
diff --git a/src/src/retry.c b/src/src/retry.c
index 364591bd0..91c27104a 100644
--- a/src/src/retry.c
+++ b/src/src/retry.c
@@ -54,8 +54,8 @@ if (retry != NULL && retry->rules != NULL)
last_rule = last_rule->next);
DEBUG(D_retry)
debug_printf(" received_time=%d diff=%d timeout=%d\n",
- received_time, (int)(now - received_time), last_rule->timeout);
- address_timeout = (now - received_time > last_rule->timeout);
+ (int)received_time.tv_sec, (int)(now - received_time.tv_sec), last_rule->timeout);
+ address_timeout = (now - received_time.tv_sec > last_rule->timeout);
}
else
{
@@ -159,8 +159,7 @@ deliveries (so as to do it all in one go). The tree records addresses that have
become unusable during this delivery process (i.e. those that will get put into
the retry database when it is updated). */
-node = tree_search(tree_unusable, host_key);
-if (node != NULL)
+if ((node = tree_search(tree_unusable, host_key)))
{
DEBUG(D_transport|D_retry) debug_printf("found in tree of unusables\n");
host->status = (node->data.val > 255)?
@@ -172,7 +171,7 @@ if (node != NULL)
/* Open the retry database, giving up if there isn't one. Otherwise, search for
the retry records, and then close the database again. */
-if ((dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)) == NULL)
+if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
{
DEBUG(D_deliver|D_retry|D_hints_lookup)
debug_printf("no retry data available\n");
@@ -184,7 +183,7 @@ dbfn_close(dbm_file);
/* Ignore the data if it is too old - too long since it was written */
-if (host_retry_record == NULL)
+if (!host_retry_record)
{
DEBUG(D_transport|D_retry) debug_printf("no host retry record\n");
}
@@ -194,7 +193,7 @@ else if (now - host_retry_record->time_stamp > retry_data_expire)
DEBUG(D_transport|D_retry) debug_printf("host retry record too old\n");
}
-if (message_retry_record == NULL)
+if (!message_retry_record)
{
DEBUG(D_transport|D_retry) debug_printf("no message retry record\n");
}
@@ -211,7 +210,7 @@ address. Allow the delivery if it has. Otherwise set the appropriate unusable
flag and return FALSE. Otherwise arrange to return TRUE if this is an expired
host. */
-if (host_retry_record != NULL)
+if (host_retry_record)
{
*retry_host_key = host_key;
@@ -243,7 +242,7 @@ if (host_retry_record != NULL)
for reaching its retry time (or forcing). If not, mark the host unusable,
unless the ultimate address timeout has been reached. */
-if (message_retry_record != NULL)
+if (message_retry_record)
{
*retry_message_key = message_key;
if (now < message_retry_record->next_try && !deliver_force)
@@ -295,6 +294,7 @@ retry_add_item(address_item *addr, uschar *key, int flags)
{
retry_item *rti = store_get(sizeof(retry_item));
host_item * host = addr->host_used;
+
rti->next = addr->retries;
addr->retries = rti;
rti->key = key;
@@ -378,7 +378,7 @@ if (alternate) alternate = string_sprintf("*@%s", alternate);
/* Scan the configured retry items. */
-for (yield = retries; yield != NULL; yield = yield->next)
+for (yield = retries; yield; yield = yield->next)
{
const uschar *plist = yield->pattern;
const uschar *slist = yield->senders;
@@ -472,19 +472,19 @@ for (yield = retries; yield != NULL; yield = yield->next)
/* If the "senders" condition is set, check it. Note that sender_address may
be null during -brt checking, in which case we do not use this rule. */
- if (slist != NULL && (sender_address == NULL ||
- match_address_list(sender_address, TRUE, TRUE, &slist, NULL, -1, 0,
- NULL) != OK))
+ if ( slist
+ && ( !sender_address
+ || match_address_list_basic(sender_address, &slist, 0) != OK
+ ) )
continue;
/* Check for a match between the address list item at the start of this retry
rule and either the main or alternate keys. */
- if (match_address_list(key, TRUE, TRUE, &plist, NULL, -1, UCHAR_MAX+1,
- NULL) == OK ||
- (alternate != NULL &&
- match_address_list(alternate, TRUE, TRUE, &plist, NULL, -1,
- UCHAR_MAX+1, NULL) == OK))
+ if ( match_address_list_basic(key, &plist, UCHAR_MAX+1) == OK
+ || ( alternate
+ && match_address_list_basic(alternate, &plist, UCHAR_MAX+1) == OK
+ ) )
break;
}
@@ -639,7 +639,6 @@ for (i = 0; i < 3; i++)
}
DEBUG(D_retry)
- {
if (rti->flags & rf_host)
debug_printf("retry for %s (%s) = %s %d %d\n", rti->key,
addr->domain, retry->pattern, retry->basic_errno,
@@ -647,7 +646,6 @@ for (i = 0; i < 3; i++)
else
debug_printf("retry for %s = %s %d %d\n", rti->key, retry->pattern,
retry->basic_errno, retry->more_errno);
- }
/* Set up the message for the database retry record. Because DBM
records have a maximum data length, we enforce a limit. There isn't
@@ -756,7 +754,7 @@ for (i = 0; i < 3; i++)
this is a small bit of code, and it does no harm to leave it in place,
just in case. */
- if ( received_time <= retry_record->first_failed
+ if ( received_time.tv_sec <= retry_record->first_failed
&& addr == endaddr
&& !retry_record->expired
&& rule)
@@ -764,7 +762,7 @@ for (i = 0; i < 3; i++)
retry_rule *last_rule;
for (last_rule = rule; last_rule->next; last_rule = last_rule->next)
;
- if (now - received_time > last_rule->timeout)
+ if (now - received_time.tv_sec > last_rule->timeout)
{
DEBUG(D_retry) debug_printf("on queue longer than maximum retry\n");
timedout_count++;
@@ -861,10 +859,8 @@ for (i = 0; i < 3; i++)
timed_out = TRUE;
}
else
- {
DEBUG(D_retry)
debug_printf("timed out but some hosts were skipped\n");
- }
} /* Loop for an address and its parents */
/* If this is a deferred address, and retry processing was requested by
diff --git a/src/src/rfc2047.c b/src/src/rfc2047.c
index 5c987e292..041a18858 100644
--- a/src/src/rfc2047.c
+++ b/src/src/rfc2047.c
@@ -50,7 +50,7 @@ ptr = *ptrptr = store_get(Ustrlen(string) + 1); /* No longer than this */
while (*string != 0)
{
- register int ch = *string++;
+ int ch = *string++;
if (ch == '_') *ptr++ = ' ';
else if (ch == '=')
@@ -197,9 +197,9 @@ uschar *mimeword, *q1, *q2, *endword;
*error = NULL;
mimeword = decode_mimeword(string, lencheck, &q1, &q2, &endword, &dlen, &dptr);
-if (mimeword == NULL)
+if (!mimeword)
{
- if (lenptr != NULL) *lenptr = size;
+ if (lenptr) *lenptr = size;
return string;
}
@@ -210,7 +210,7 @@ string building code. */
yield = store_get(++size);
-while (mimeword != NULL)
+while (mimeword)
{
#if HAVE_ICONV
@@ -317,7 +317,7 @@ while (mimeword != NULL)
string = endword + 2;
mimeword = decode_mimeword(string, lencheck, &q1, &q2, &endword, &dlen, &dptr);
- if (mimeword != NULL)
+ if (mimeword)
{
uschar *s = string;
while (isspace(*s)) s++;
@@ -330,8 +330,8 @@ the length as well if requested. */
yield = string_cat(yield, &size, &ptr, string);
yield[ptr] = 0;
-if (lenptr != NULL) *lenptr = ptr;
-if (sizeptr != NULL) *sizeptr = size;
+if (lenptr) *lenptr = ptr;
+if (sizeptr) *sizeptr = size;
return yield;
}
diff --git a/src/src/route.c b/src/src/route.c
index 08b3e055d..bbaa5285d 100644
--- a/src/src/route.c
+++ b/src/src/route.c
@@ -143,20 +143,28 @@ optionlist optionlist_routers[] = {
int optionlist_routers_size = sizeof(optionlist_routers)/sizeof(optionlist);
+#ifdef MACRO_PREDEF
+
+# include "macro_predef.h"
+
void
-readconf_options_routers(void)
+options_routers(void)
{
struct router_info * ri;
+uschar buf[64];
-readconf_options_from_list(optionlist_routers, nelem(optionlist_routers), US"ROUTERS", NULL);
+options_from_list(optionlist_routers, nelem(optionlist_routers), US"ROUTERS", NULL);
for (ri = routers_available; ri->driver_name[0]; ri++)
{
- macro_create(string_sprintf("_DRIVER_ROUTER_%T", ri->driver_name), US"y", FALSE, TRUE);
- readconf_options_from_list(ri->options, (unsigned)*ri->options_count, US"ROUTER", ri->driver_name);
+ spf(buf, sizeof(buf), US"_DRIVER_ROUTER_%T", ri->driver_name);
+ builtin_macro_create(buf);
+ options_from_list(ri->options, (unsigned)*ri->options_count, US"ROUTER", ri->driver_name);
}
}
+#else /*!MACRO_PREDEF*/
+
/*************************************************
* Set router pointer from name *
*************************************************/
@@ -1357,7 +1365,7 @@ new->prop.errors_address = parent->prop.errors_address;
/* Copy the propagated flags and address_data from the original. */
-copyflag(new, addr, af_propagate);
+new->prop.ignore_error = addr->prop.ignore_error;
new->prop.address_data = addr->prop.address_data;
new->dsn_flags = addr->dsn_flags;
new->dsn_orcpt = addr->dsn_orcpt;
@@ -1919,4 +1927,5 @@ disable_logging = FALSE;
return yield;
}
+#endif /*!MACRO_PREDEF*/
/* End of route.c */
diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c
index 6c76c7119..b3a54e7cb 100644
--- a/src/src/routers/accept.c
+++ b/src/src/routers/accept.c
@@ -32,6 +32,18 @@ accept_router_options_block accept_router_option_defaults = {
};
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+void accept_router_init(router_instance *rblock) {}
+int accept_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
/*************************************************
* Initialization entry point *
@@ -125,4 +137,5 @@ addr->prop.remove_headers = remove_headers;
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? OK : DEFER;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/accept.c */
diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c
index e4f7a2539..9e230b1be 100644
--- a/src/src/routers/dnslookup.c
+++ b/src/src/routers/dnslookup.c
@@ -44,6 +44,22 @@ address can appear in the tables drtables.c. */
int dnslookup_router_options_count =
sizeof(dnslookup_router_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+dnslookup_router_options_block dnslookup_router_option_defaults = {0};
+void dnslookup_router_init(router_instance *rblock) {}
+int dnslookup_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
+
/* Default private options block for the dnslookup router. */
dnslookup_router_options_block dnslookup_router_option_defaults = {
@@ -446,6 +462,7 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
OK : DEFER;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/dnslookup.c */
/* vi: aw ai sw=2
*/
diff --git a/src/src/routers/ipliteral.c b/src/src/routers/ipliteral.c
index 22d292d88..5cd6da52a 100644
--- a/src/src/routers/ipliteral.c
+++ b/src/src/routers/ipliteral.c
@@ -30,6 +30,17 @@ value is present to keep some compilers happy. */
ipliteral_router_options_block ipliteral_router_option_defaults = { 0 };
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+void ipliteral_router_init(router_instance *rblock) {}
+int ipliteral_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
/*************************************************
* Initialization entry point *
@@ -190,4 +201,5 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
OK : DEFER;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/ipliteral.c */
diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c
index 96e9626df..3592809ea 100644
--- a/src/src/routers/iplookup.c
+++ b/src/src/routers/iplookup.c
@@ -44,6 +44,20 @@ address can appear in the tables drtables.c. */
int iplookup_router_options_count =
sizeof(iplookup_router_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+iplookup_router_options_block iplookup_router_option_defaults = {0};
+void iplookup_router_init(router_instance *rblock) {}
+int iplookup_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the iplookup router. */
iplookup_router_options_block iplookup_router_option_defaults = {
@@ -240,9 +254,10 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
/* Connect to the remote host, under a timeout. In fact, timeouts can occur
here only for TCP calls; for a UDP socket, "connect" always works (the
router will timeout later on the read call). */
+/*XXX could take advantage of TFO */
if (ip_connect(query_socket, host_af, h->address,ob->port, ob->timeout,
- ob->protocol != ip_udp) < 0)
+ ob->protocol == ip_udp ? NULL : &tcp_fastopen_nodata) < 0)
{
close(query_socket);
DEBUG(D_route)
@@ -379,7 +394,6 @@ the chain of new addressess. */
new_addr = deliver_make_addr(reroute, TRUE);
new_addr->parent = addr;
-copyflag(new_addr, addr, af_propagate);
new_addr->prop = addr->prop;
if (addr->child_count == USHRT_MAX)
@@ -402,4 +416,5 @@ if (rc != OK) return rc;
return OK;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/iplookup.c */
diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c
index 95c69328d..a695a9b6a 100644
--- a/src/src/routers/manualroute.c
+++ b/src/src/routers/manualroute.c
@@ -34,6 +34,21 @@ address can appear in the tables drtables.c. */
int manualroute_router_options_count =
sizeof(manualroute_router_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+manualroute_router_options_block manualroute_router_option_defaults = {0};
+void manualroute_router_init(router_instance *rblock) {}
+int manualroute_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
/* Default private options block for the manualroute router. */
manualroute_router_options_block manualroute_router_option_defaults = {
@@ -333,7 +348,7 @@ while (*options != 0)
{
transport_instance *t;
for (t = transports; t != NULL; t = t->next)
- if (Ustrcmp(t->name, s) == 0)
+ if (Ustrncmp(t->name, s, n) == 0)
{
transport = t;
individual_transport_set = TRUE;
@@ -474,4 +489,5 @@ addr->transport = transport;
return OK;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/manualroute.c */
diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c
index cd02f366f..abba024db 100644
--- a/src/src/routers/queryprogram.c
+++ b/src/src/routers/queryprogram.c
@@ -40,6 +40,20 @@ address can appear in the tables drtables.c. */
int queryprogram_router_options_count =
sizeof(queryprogram_router_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+queryprogram_router_options_block queryprogram_router_option_defaults = {0};
+void queryprogram_router_init(router_instance *rblock) {}
+int queryprogram_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the queryprogram router. */
queryprogram_router_options_block queryprogram_router_option_defaults = {
@@ -109,12 +123,14 @@ add_generated(router_instance *rblock, address_item **addr_new,
{
while (generated != NULL)
{
+ BOOL ignore_error = addr->prop.ignore_error;
address_item *next = generated;
+
generated = next->next;
next->parent = addr;
- orflag(next, addr, af_propagate);
next->prop = *addr_prop;
+ next->prop.ignore_error = next->prop.ignore_error || ignore_error;
next->start_router = rblock->redirect_router;
next->next = *addr_new;
@@ -539,4 +555,5 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
OK : DEFER;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/queryprogram.c */
diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c
index 29537baae..9923af585 100644
--- a/src/src/routers/redirect.c
+++ b/src/src/routers/redirect.c
@@ -133,6 +133,21 @@ address can appear in the tables drtables.c. */
int redirect_router_options_count =
sizeof(redirect_router_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+redirect_router_options_block redirect_router_option_defaults = {0};
+void redirect_router_init(router_instance *rblock) {}
+int redirect_router_entry(router_instance *rblock, address_item *addr,
+ struct passwd *pw, int verify, address_item **addr_local,
+ address_item **addr_remote, address_item **addr_new,
+ address_item **addr_succeed) {return 0;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
/* Default private options block for the redirect router. */
redirect_router_options_block redirect_router_option_defaults = {
@@ -333,7 +348,6 @@ while (generated)
generated = next->next;
next->parent = addr;
- orflag(next, addr, af_ignore_error);
next->start_router = rblock->redirect_router;
if (addr->child_count == USHRT_MAX)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
@@ -373,8 +387,12 @@ while (generated)
If so, we must take care to re-instate it when we copy in the propagated
data so that it overrides any errors_to setting on the router. */
- next->prop = *addr_prop;
- if (errors_address != NULL) next->prop.errors_address = errors_address;
+ {
+ BOOL ignore_error = next->prop.ignore_error;
+ next->prop = *addr_prop;
+ next->prop.ignore_error = ignore_error || addr->prop.ignore_error;
+ }
+ if (errors_address) next->prop.errors_address = errors_address;
/* For pipes, files, and autoreplies, record this router as handling them,
because they don't go through the routing process again. Then set up uid,
@@ -897,10 +915,8 @@ else
next->next = *addr_new;
*addr_new = next;
- /* Copy relevant flags (af_propagate is a name for the set), and set the
- data that propagates. */
+ /* Set the data that propagates. */
- copyflag(next, addr, af_propagate);
next->prop = addr_prop;
DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
@@ -921,4 +937,5 @@ addr->next = *addr_succeed;
return yield;
}
+#endif /*!MACRO_PREDEF*/
/* End of routers/redirect.c */
diff --git a/src/src/routers/rf_get_errors_address.c b/src/src/routers/rf_get_errors_address.c
index d7172d7ac..d81f0e907 100644
--- a/src/src/routers/rf_get_errors_address.c
+++ b/src/src/routers/rf_get_errors_address.c
@@ -60,7 +60,7 @@ if (s == NULL)
if (*s == 0)
{
- setflag(addr, af_ignore_error); /* For locally detected errors */
+ addr->prop.ignore_error = TRUE; /* For locally detected errors */
*errors_to = US""; /* Return path for SMTP */
return OK;
}
diff --git a/src/src/routers/rf_get_munge_headers.c b/src/src/routers/rf_get_munge_headers.c
index ecb4ee097..745704f62 100644
--- a/src/src/routers/rf_get_munge_headers.c
+++ b/src/src/routers/rf_get_munge_headers.c
@@ -91,6 +91,10 @@ if (rblock->remove_headers)
const uschar * list = rblock->remove_headers;
int sep = ':';
uschar * s;
+ int size = 0, len = 0;
+
+ if (*remove_headers)
+ size = (len = Ustrlen(*remove_headers)) + 1;
while ((s = string_nextinlist(&list, &sep, NULL, 0)))
if (!(s = expand_string(s)))
@@ -104,7 +108,7 @@ if (rblock->remove_headers)
}
}
else if (*s)
- *remove_headers = string_append_listele(*remove_headers, ':', s);
+ *remove_headers = string_append_listele(*remove_headers, &size, &len, ':', s);
}
return OK;
diff --git a/src/src/routers/rf_queue_add.c b/src/src/routers/rf_queue_add.c
index 784a5477f..1eb109c89 100644
--- a/src/src/routers/rf_queue_add.c
+++ b/src/src/routers/rf_queue_add.c
@@ -41,7 +41,7 @@ addr->prop.localpart_data = deliver_localpart_data; /* use in the transport */
/* Handle a local transport */
-if (addr->transport != NULL && addr->transport->info->local)
+if (addr->transport && addr->transport->info->local)
{
ugid_block ugid;
@@ -50,11 +50,13 @@ if (addr->transport != NULL && addr->transport->info->local)
When getting the home directory out of the password information, set the
flag that prevents expansion later. */
- if (pw != NULL)
+ if (pw)
{
addr->uid = pw->pw_uid;
addr->gid = pw->pw_gid;
- setflag(addr, af_uid_set|af_gid_set|af_home_expanded);
+ setflag(addr, af_uid_set);
+ setflag(addr, af_gid_set);
+ setflag(addr, af_home_expanded);
addr->home_dir = string_copy(US pw->pw_dir);
}
@@ -65,12 +67,12 @@ if (addr->transport != NULL && addr->transport->info->local)
otherwise use the expanded value of router_home_directory. The flag also
tells the transport not to re-expand it. */
- if (rblock->home_directory != NULL)
+ if (rblock->home_directory)
{
addr->home_dir = rblock->home_directory;
clearflag(addr, af_home_expanded);
}
- else if (addr->home_dir == NULL && testflag(addr, af_home_expanded))
+ else if (!addr->home_dir && testflag(addr, af_home_expanded))
addr->home_dir = deliver_home;
addr->current_dir = rblock->current_directory;
diff --git a/src/src/sieve.c b/src/src/sieve.c
index 96344c416..32d9279ea 100644
--- a/src/src/sieve.c
+++ b/src/src/sieve.c
@@ -291,7 +291,6 @@ for (pass=0; pass<=1; ++pass)
else
{ /* encoded char */
new += sprintf(CS new,"=%02X",ch);
- new+=3;
}
line+=3;
}
@@ -414,7 +413,7 @@ static int parse_mailto_uri(struct Sieve *filter, const uschar *uri, string_item
{
const uschar *start;
struct String to, hname;
-struct String hvalue = {NULL, 0};
+struct String hvalue = {.character = NULL, .length = 0};
int capacity;
string_item *new;
@@ -1046,30 +1045,33 @@ Arguments:
Returns: nothing
*/
-static void add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
+static void
+add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
{
address_item *new_addr;
for (new_addr=*generated; new_addr; new_addr=new_addr->next)
- {
- if (Ustrcmp(new_addr->address,addr)==0 && (file ? testflag(new_addr, af_pfr|af_file) : 1))
+ if ( Ustrcmp(new_addr->address,addr) == 0
+ && ( !file
+ || testflag(new_addr, af_pfr)
+ || testflag(new_addr, af_file)
+ )
+ )
{
if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
- {
debug_printf("Repeated %s `%s' ignored.\n",file ? "fileinto" : "redirect", addr);
- }
+
return;
}
- }
if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
- {
debug_printf("%s `%s'\n",file ? "fileinto" : "redirect", addr);
- }
-new_addr=deliver_make_addr(addr,TRUE);
+
+new_addr = deliver_make_addr(addr,TRUE);
if (file)
{
- setflag(new_addr, af_pfr|af_file);
+ setflag(new_addr, af_pfr);
+ setflag(new_addr, af_file);
new_addr->mode = 0;
}
new_addr->prop.errors_address = NULL;
@@ -3346,7 +3348,7 @@ while (*filter->pc)
addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
setflag(addr, af_pfr);
- setflag(addr, af_ignore_error);
+ addr->prop.ignore_error = TRUE;
addr->next = *generated;
*generated = addr;
addr->reply = store_get(sizeof(reply_item));
@@ -3390,7 +3392,7 @@ while (*filter->pc)
}
else
{
- struct String qp = { NULL, 0 }; /* Keep compiler happy (PH) */
+ struct String qp = { .character = NULL, .length = 0 }; /* Keep compiler happy (PH) */
capacity = 0;
start = reason.length;
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index f0885b3a1..36f685677 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -314,10 +314,10 @@ static void smtp_rset_handler(void);
*************************************************/
/* Synchronization checks can never be perfect because a packet may be on its
-way but not arrived when the check is done. Such checks can in any case only be
-done when TLS is not in use. Normally, the checks happen when commands are
-read: Exim ensures that there is no more input in the input buffer. In normal
-cases, the response to the command will be fast, and there is no further check.
+way but not arrived when the check is done. Normally, the checks happen when
+commands are read: Exim ensures that there is no more input in the input buffer.
+In normal cases, the response to the command will be fast, and there is no
+further check.
However, for some commands an ACL is run, and that can include delays. In those
cases, it is useful to do another check on the input just before sending the
@@ -333,15 +333,19 @@ Returns: TRUE if all is well; FALSE if there is input pending
*/
static BOOL
-check_sync(void)
+wouldblock_reading(void)
{
int fd, rc;
fd_set fds;
struct timeval tzero;
-if (!smtp_enforce_sync || sender_host_address == NULL ||
- sender_host_notsocket || tls_in.active >= 0)
- return TRUE;
+#ifdef SUPPORT_TLS
+if (tls_in.active >= 0)
+ return !tls_could_read();
+#endif
+
+if (smtp_inptr < smtp_inend)
+ return FALSE;
fd = fileno(smtp_in);
FD_ZERO(&fds);
@@ -361,6 +365,29 @@ smtp_inptr[rc] = 0;
return FALSE;
}
+static BOOL
+check_sync(void)
+{
+if (!smtp_enforce_sync || sender_host_address == NULL || sender_host_notsocket)
+ return TRUE;
+
+return wouldblock_reading();
+}
+
+
+/* If there's input waiting (and we're doing pipelineing) then we can pipeline
+a reponse with the one following. */
+
+static BOOL
+pipeline_response(void)
+{
+if ( !smtp_enforce_sync || !sender_host_address
+ || sender_host_notsocket || !pipelining_advertised)
+ return FALSE;
+
+return !wouldblock_reading();
+}
+
/*************************************************
@@ -400,6 +427,44 @@ log_write(L_smtp_incomplete_transaction, LOG_MAIN|LOG_SENDER|LOG_RECIPIENTS,
+/* Refill the buffer, and notify DKIM verification code.
+Return false for error or EOF.
+*/
+
+static BOOL
+smtp_refill(unsigned lim)
+{
+int rc, save_errno;
+if (!smtp_out) return FALSE;
+fflush(smtp_out);
+if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+
+/* Limit amount read, so non-message data is not fed to DKIM */
+
+rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE, lim));
+save_errno = errno;
+alarm(0);
+if (rc <= 0)
+ {
+ /* Must put the error text in fixed store, because this might be during
+ header reading, where it releases unused store above the header. */
+ if (rc < 0)
+ {
+ smtp_had_error = save_errno;
+ smtp_read_error = string_copy_malloc(
+ string_sprintf(" (error: %s)", strerror(save_errno)));
+ }
+ else smtp_had_eof = 1;
+ return FALSE;
+ }
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(smtp_inbuffer, rc);
+#endif
+smtp_inend = smtp_inbuffer + rc;
+smtp_inptr = smtp_inbuffer;
+return TRUE;
+}
+
/*************************************************
* SMTP version of getc() *
*************************************************/
@@ -417,39 +482,28 @@ int
smtp_getc(unsigned lim)
{
if (smtp_inptr >= smtp_inend)
- {
- int rc, save_errno;
- if (!smtp_out) return EOF;
- fflush(smtp_out);
- if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-
- /* Limit amount read, so non-message data is not fed to DKIM */
-
- rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE, lim));
- save_errno = errno;
- alarm(0);
- if (rc <= 0)
- {
- /* Must put the error text in fixed store, because this might be during
- header reading, where it releases unused store above the header. */
- if (rc < 0)
- {
- smtp_had_error = save_errno;
- smtp_read_error = string_copy_malloc(
- string_sprintf(" (error: %s)", strerror(save_errno)));
- }
- else smtp_had_eof = 1;
+ if (!smtp_refill(lim))
return EOF;
- }
-#ifndef DISABLE_DKIM
- dkim_exim_verify_feed(smtp_inbuffer, rc);
-#endif
- smtp_inend = smtp_inbuffer + rc;
- smtp_inptr = smtp_inbuffer;
- }
return *smtp_inptr++;
}
+uschar *
+smtp_getbuf(unsigned * len)
+{
+unsigned size;
+uschar * buf;
+
+if (smtp_inptr >= smtp_inend)
+ if (!smtp_refill(*len))
+ { *len = 0; return NULL; }
+
+if ((size = smtp_inend - smtp_inptr) > *len) size = *len;
+buf = smtp_inptr;
+smtp_inptr += size;
+*len = size;
+return buf;
+}
+
void
smtp_get_cache(void)
{
@@ -493,6 +547,7 @@ for(;;)
return lwr_receive_getc(chunking_data_left--);
receive_getc = lwr_receive_getc;
+ receive_getbuf = lwr_receive_getbuf;
receive_ungetc = lwr_receive_ungetc;
#ifndef DISABLE_DKIM
dkim_save = dkim_collect_input;
@@ -504,12 +559,15 @@ for(;;)
if (!pipelining_advertised && !check_sync())
{
+ unsigned n = smtp_inend - smtp_inptr;
+ if (n > 32) n = 32;
+
incomplete_transaction_log(US"sync failure");
log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error "
"(next input sent too soon: pipelining was not advertised): "
"rejected \"%s\" %s next input=\"%s\"",
smtp_cmd_buffer, host_and_ident(TRUE),
- string_printing(smtp_inptr));
+ string_printing(string_copyn(smtp_inptr, n)));
(void) synprot_error(L_smtp_protocol_error, 554, NULL,
US"SMTP synchronization error");
goto repeat_until_rset;
@@ -526,7 +584,7 @@ for(;;)
return EOD;
}
- smtp_printf("250 %u byte chunk received\r\n", chunking_datasize);
+ smtp_printf("250 %u byte chunk received\r\n", FALSE, chunking_datasize);
chunking_state = CHUNKING_OFFERED;
DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
@@ -564,7 +622,7 @@ next_cmd:
case NOOP_CMD:
HAD(SCH_NOOP);
- smtp_printf("250 OK\r\n");
+ smtp_printf("250 OK\r\n", FALSE);
goto next_cmd;
case BDAT_CMD:
@@ -594,6 +652,7 @@ next_cmd:
}
receive_getc = bdat_getc;
+ receive_getbuf = bdat_getbuf;
receive_ungetc = bdat_ungetc;
#ifndef DISABLE_DKIM
dkim_collect_input = dkim_save;
@@ -604,14 +663,28 @@ next_cmd:
}
}
+uschar *
+bdat_getbuf(unsigned * len)
+{
+uschar * buf;
+
+if (chunking_data_left <= 0)
+ { *len = 0; return NULL; }
+
+if (*len > chunking_data_left) *len = chunking_data_left;
+buf = lwr_receive_getbuf(len); /* Either smtp_getbuf or tls_getbuf */
+chunking_data_left -= *len;
+return buf;
+}
+
void
bdat_flush_data(void)
{
-while (chunking_data_left > 0)
- if (lwr_receive_getc(chunking_data_left--) < 0)
- break;
+unsigned n = chunking_data_left;
+(void) bdat_getbuf(&n);
receive_getc = lwr_receive_getc;
+receive_getbuf = lwr_receive_getbuf;
receive_ungetc = lwr_receive_ungetc;
if (chunking_state != CHUNKING_LAST)
@@ -725,18 +798,19 @@ they are also picked up later by smtp_fflush().
Arguments:
format format string
+ more further data expected
... optional arguments
Returns: nothing
*/
void
-smtp_printf(const char *format, ...)
+smtp_printf(const char *format, BOOL more, ...)
{
va_list ap;
-va_start(ap, format);
-smtp_vprintf(format, ap);
+va_start(ap, more);
+smtp_vprintf(format, more, ap);
va_end(ap);
}
@@ -745,7 +819,7 @@ smtp_printf(), bearing in mind that in C a vararg function can't directly
call another vararg function, only a function which accepts a va_list. */
void
-smtp_vprintf(const char *format, va_list ap)
+smtp_vprintf(const char *format, BOOL more, va_list ap)
{
BOOL yield;
@@ -791,7 +865,7 @@ if (rcpt_in_progress)
#ifdef SUPPORT_TLS
if (tls_in.active >= 0)
{
- if (tls_write(TRUE, big_buffer, Ustrlen(big_buffer)) < 0)
+ if (tls_write(TRUE, big_buffer, Ustrlen(big_buffer), more) < 0)
smtp_write_error = -1;
}
else
@@ -1570,7 +1644,7 @@ smtp_closedown(uschar *message)
{
if (smtp_in == NULL || smtp_batched_input) return;
receive_swallow_smtp();
-smtp_printf("421 %s\r\n", message);
+smtp_printf("421 %s\r\n", FALSE, message);
for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
{
@@ -1578,16 +1652,16 @@ for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
return;
case QUIT_CMD:
- smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+ smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
mac_smtp_fflush();
return;
case RSET_CMD:
- smtp_printf("250 Reset OK\r\n");
+ smtp_printf("250 Reset OK\r\n", FALSE);
break;
default:
- smtp_printf("421 %s\r\n", message);
+ smtp_printf("421 %s\r\n", FALSE, message);
break;
}
}
@@ -1723,14 +1797,33 @@ for (i = 0; i < smtp_ch_index; i++)
sep = US",";
}
-if (s != NULL) s[ptr] = 0; else s = US"";
-log_write(0, LOG_MAIN, "no MAIL in SMTP connection from %s D=%s%s",
- host_and_ident(FALSE),
- readconf_printtime( (int) ((long)time(NULL) - (long)smtp_connection_start)),
- s);
+if (s) s[ptr] = 0; else s = US"";
+log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s",
+ tcp_in_fastopen ? US"TFO " : US"",
+ host_and_ident(FALSE), string_timesince(&smtp_connection_start), s);
}
+/* Return list of recent smtp commands */
+
+uschar *
+smtp_cmd_hist(void)
+{
+uschar * list = NULL;
+int size = 0, len = 0, i;
+
+for (i = smtp_ch_index; i < SMTP_HBUFF_SIZE; i++)
+ if (smtp_connection_had[i] != SCH_NONE)
+ list = string_append_listele(list, &size, &len, ',',
+ smtp_names[smtp_connection_had[i]]);
+for (i = 0; i < smtp_ch_index; i++)
+ list = string_append_listele(list, &size, &len, ',',
+ smtp_names[smtp_connection_had[i]]);
+return list ? list : US"";
+}
+
+
+
/*************************************************
* Check HELO line and set sender_helo_name *
@@ -1849,17 +1942,17 @@ while (v > smtp_cmd_data && *v != '=' && !isspace(*v))
n = v;
if (*v == '=')
-{
+ {
while(isalpha(n[-1])) n--;
/* RFC says SP, but TAB seen in wild and other major MTAs accept it */
if (!isspace(n[-1])) return FALSE;
n[-1] = 0;
-}
+ }
else
-{
+ {
n++;
if (v == smtp_cmd_data) return FALSE;
-}
+ }
*v++ = 0;
*name = n;
*value = v;
@@ -1887,7 +1980,6 @@ smtp_reset(void *reset_point)
recipients_list = NULL;
rcpt_count = rcpt_defer_count = rcpt_fail_count =
raw_recipients_count = recipients_count = recipients_list_max = 0;
-cancel_cutthrough_connection("smtp reset");
message_linecount = 0;
message_size = -1;
acl_added_headers = NULL;
@@ -2018,6 +2110,7 @@ bsmtp_transaction_linecount = receive_linecount;
if ((receive_feof)()) return 0; /* Treat EOF as QUIT */
+cancel_cutthrough_connection(TRUE, US"smtp_setup_batch_msg");
smtp_reset(reset_point); /* Reset for start of message */
/* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
@@ -2042,6 +2135,7 @@ while (done <= 0)
/* Fall through */
case RSET_CMD:
+ cancel_cutthrough_connection(TRUE, US"RSET received");
smtp_reset(reset_point);
bsmtp_transaction_linecount = receive_linecount;
break;
@@ -2065,6 +2159,7 @@ while (done <= 0)
/* Reset to start of message */
+ cancel_cutthrough_connection(TRUE, US"MAIL received");
smtp_reset(reset_point);
/* Apply SMTP rewrite */
@@ -2237,6 +2332,28 @@ return FALSE;
}
+
+
+#ifdef TCP_FASTOPEN
+static void
+tfo_in_check(void)
+{
+# ifdef TCP_INFO
+struct tcp_info tinfo;
+socklen_t len = sizeof(tinfo);
+
+if ( getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
+ && tinfo.tcpi_state == TCP_SYN_RECV
+ )
+ {
+ DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection\n");
+ tcp_in_fastopen = TRUE;
+ }
+# endif
+}
+#endif
+
+
/*************************************************
* Start an SMTP session *
*************************************************/
@@ -2259,7 +2376,7 @@ uschar *user_msg, *log_msg;
uschar *code, *esc;
uschar *p, *s, *ss;
-smtp_connection_start = time(NULL);
+gettimeofday(&smtp_connection_start, NULL);
for (smtp_ch_index = 0; smtp_ch_index < SMTP_HBUFF_SIZE; smtp_ch_index++)
smtp_connection_had[smtp_ch_index] = SCH_NONE;
smtp_ch_index = 0;
@@ -2326,10 +2443,11 @@ else
/* Set up the buffer for inputting using direct read() calls, and arrange to
call the local functions instead of the standard C ones. */
-if (!(smtp_inbuffer = (uschar *)malloc(IN_BUFFER_SIZE)))
+if (!(smtp_inbuffer = US malloc(IN_BUFFER_SIZE)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP input buffer");
receive_getc = smtp_getc;
+receive_getbuf = smtp_getbuf;
receive_get_cache = smtp_get_cache;
receive_ungetc = smtp_ungetc;
receive_feof = smtp_feof;
@@ -2431,14 +2549,14 @@ if (!sender_host_unknown)
DEBUG(D_receive) debug_printf("checking for IP options\n");
- if (getsockopt(fileno(smtp_out), IPPROTO_IP, IP_OPTIONS, (uschar *)(ipopt),
+ if (getsockopt(fileno(smtp_out), IPPROTO_IP, IP_OPTIONS, US (ipopt),
&optlen) < 0)
{
if (errno != ENOPROTOOPT)
{
log_write(0, LOG_MAIN, "getsockopt() failed from %s: %s",
host_and_ident(FALSE), strerror(errno));
- smtp_printf("451 SMTP service not available\r\n");
+ smtp_printf("451 SMTP service not available\r\n", FALSE);
return FALSE;
}
}
@@ -2457,11 +2575,11 @@ if (!sender_host_unknown)
struct in_addr addr;
#if OPTSTYLE == 1
- uschar *optstart = (uschar *)(ipopt->__data);
+ uschar *optstart = US (ipopt->__data);
#elif OPTSTYLE == 2
- uschar *optstart = (uschar *)(ipopt->ip_opts);
+ uschar *optstart = US (ipopt->ip_opts);
#else
- uschar *optstart = (uschar *)(ipopt->ipopt_list);
+ uschar *optstart = US (ipopt->ipopt_list);
#endif
DEBUG(D_receive) debug_printf("IP options exist\n");
@@ -2470,7 +2588,7 @@ if (!sender_host_unknown)
p += Ustrlen(p);
for (opt = optstart; opt != NULL &&
- opt < (uschar *)(ipopt) + optlen;)
+ opt < US (ipopt) + optlen;)
{
switch (*opt)
{
@@ -2524,10 +2642,7 @@ if (!sender_host_unknown)
Ustrcat(p, "[ ");
p += 2;
for (i = 0; i < opt[1]; i++)
- {
- sprintf(CS p, "%2.2x ", opt[i]);
- p += 3;
- }
+ p += sprintf(CS p, "%2.2x ", opt[i]);
*p++ = ']';
}
opt += opt[1];
@@ -2543,7 +2658,7 @@ if (!sender_host_unknown)
log_write(0, LOG_MAIN|LOG_REJECT,
"connection from %s refused (IP options)", host_and_ident(FALSE));
- smtp_printf("554 SMTP service not available\r\n");
+ smtp_printf("554 SMTP service not available\r\n", FALSE);
return FALSE;
}
@@ -2595,7 +2710,7 @@ if (!sender_host_unknown)
{
log_write(L_connection_reject, LOG_MAIN|LOG_REJECT, "refused connection "
"from %s (host_reject_connection)", host_and_ident(FALSE));
- smtp_printf("554 SMTP service not available\r\n");
+ smtp_printf("554 SMTP service not available\r\n", FALSE);
return FALSE;
}
@@ -2626,7 +2741,7 @@ if (!sender_host_unknown)
log_write(L_connection_reject,
LOG_MAIN|LOG_REJECT, "refused connection from %s "
"(tcp wrappers)", host_and_ident(FALSE));
- smtp_printf("554 SMTP service not available\r\n");
+ smtp_printf("554 SMTP service not available\r\n", FALSE);
}
else
{
@@ -2636,7 +2751,7 @@ if (!sender_host_unknown)
log_write(L_connection_reject,
LOG_MAIN|LOG_REJECT, "temporarily refused connection from %s "
"(tcp wrappers errno=%d)", host_and_ident(FALSE), save_errno);
- smtp_printf("451 Temporary local problem - please try later\r\n");
+ smtp_printf("451 Temporary local problem - please try later\r\n", FALSE);
}
return FALSE;
}
@@ -2656,7 +2771,7 @@ if (!sender_host_unknown)
host_and_ident(FALSE), smtp_accept_count - 1, smtp_accept_max,
smtp_accept_reserve, (rc == DEFER)? " (lookup deferred)" : "");
smtp_printf("421 %s: Too many concurrent SMTP connections; "
- "please try again later\r\n", smtp_active_hostname);
+ "please try again later\r\n", FALSE, smtp_active_hostname);
return FALSE;
}
reserved_host = TRUE;
@@ -2677,7 +2792,7 @@ if (!sender_host_unknown)
LOG_MAIN, "temporarily refused connection from %s: not in "
"reserve list and load average = %.2f", host_and_ident(FALSE),
(double)load_average/1000.0);
- smtp_printf("421 %s: Too much load; please try again later\r\n",
+ smtp_printf("421 %s: Too much load; please try again later\r\n", FALSE,
smtp_active_hostname);
return FALSE;
}
@@ -2817,17 +2932,28 @@ this synchronisation check is disabled. */
if (!check_sync())
{
+ unsigned n = smtp_inend - smtp_inptr;
+ if (n > 32) n = 32;
+
log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol "
"synchronization error (input sent without waiting for greeting): "
"rejected connection from %s input=\"%s\"", host_and_ident(TRUE),
- string_printing(smtp_inptr));
- smtp_printf("554 SMTP synchronization error\r\n");
+ string_printing(string_copyn(smtp_inptr, n)));
+ smtp_printf("554 SMTP synchronization error\r\n", FALSE);
return FALSE;
}
/* Now output the banner */
-smtp_printf("%s", ss);
+smtp_printf("%s", FALSE, ss);
+
+/* Attempt to see if we sent the banner before the last ACK of the 3-way
+handshake arrived. If so we must have managed a TFO. */
+
+#ifdef TCP_FASTOPEN
+tfo_in_check();
+#endif
+
return TRUE;
}
@@ -2874,10 +3000,10 @@ if (++synprot_error_count > smtp_max_synprot_errors)
if (code > 0)
{
- smtp_printf("%d%c%s%s%s\r\n", code, (yield == 1)? '-' : ' ',
- (data == NULL)? US"" : data, (data == NULL)? US"" : US": ", errmess);
+ smtp_printf("%d%c%s%s%s\r\n", FALSE, code, yield == 1 ? '-' : ' ',
+ data ? data : US"", data ? US": " : US"", errmess);
if (yield == 1)
- smtp_printf("%d Too many syntax or protocol errors\r\n", code);
+ smtp_printf("%d Too many syntax or protocol errors\r\n", FALSE, code);
}
return yield;
@@ -2933,25 +3059,27 @@ if (rcpt_in_progress)
rcpt_in_progress = FALSE;
}
-/* Not output the message, splitting it up into multiple lines if necessary. */
+/* Now output the message, splitting it up into multiple lines if necessary.
+We only handle pipelining these responses as far as nonfinal/final groups,
+not the whole MAIL/RCPT/DATA response set. */
for (;;)
{
uschar *nl = Ustrchr(msg, '\n');
if (nl == NULL)
{
- smtp_printf("%.3s%c%.*s%s\r\n", code, final? ' ':'-', esclen, esc, msg);
+ smtp_printf("%.3s%c%.*s%s\r\n", !final, code, final ? ' ':'-', esclen, esc, msg);
return;
}
else if (nl[1] == 0 || no_multiline_responses)
{
- smtp_printf("%.3s%c%.*s%.*s\r\n", code, final? ' ':'-', esclen, esc,
+ smtp_printf("%.3s%c%.*s%.*s\r\n", !final, code, final ? ' ':'-', esclen, esc,
(int)(nl - msg), msg);
return;
}
else
{
- smtp_printf("%.3s-%.*s%.*s\r\n", code, esclen, esc, (int)(nl - msg), msg);
+ smtp_printf("%.3s-%.*s%.*s\r\n", TRUE, code, esclen, esc, (int)(nl - msg), msg);
msg = nl + 1;
while (isspace(*msg)) msg++;
}
@@ -3295,7 +3423,7 @@ if (code && defaultrespond)
va_start(ap, defaultrespond);
if (!string_vformat(buffer, sizeof(buffer), CS defaultrespond, ap))
log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_notquit_exit()");
- smtp_printf("%s %s\r\n", code, buffer);
+ smtp_printf("%s %s\r\n", FALSE, code, buffer);
va_end(ap);
}
mac_smtp_fflush();
@@ -3587,7 +3715,7 @@ if (allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0)
*recipient = rewrite_address_qualify(*recipient, TRUE);
return rd;
}
-smtp_printf("501 %s: recipient address must contain a domain\r\n",
+smtp_printf("501 %s: recipient address must contain a domain\r\n", FALSE,
smtp_cmd_data);
log_write(L_smtp_syntax_error,
LOG_MAIN|LOG_REJECT, "unqualified %s rejected: <%s> %s%s",
@@ -3613,7 +3741,7 @@ if (acl_smtp_quit)
if (*user_msgp)
smtp_respond(US"221", 3, TRUE, *user_msgp);
else
- smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+ smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
#ifdef SUPPORT_TLS
tls_close(TRUE, TRUE);
@@ -3629,7 +3757,7 @@ smtp_rset_handler(void)
{
HAD(SCH_RSET);
incomplete_transaction_log(US"RSET");
-smtp_printf("250 Reset OK\r\n");
+smtp_printf("250 Reset OK\r\n", FALSE);
cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE;
}
@@ -3849,7 +3977,7 @@ while (done <= 0)
{
c = smtp_in_auth(au, &s, &ss);
- smtp_printf("%s\r\n", s);
+ smtp_printf("%s\r\n", FALSE, s);
if (c != OK)
log_write(0, LOG_MAIN|LOG_REJECT, "%s authenticator failed for %s: %s",
au->name, host_and_ident(FALSE), ss);
@@ -3896,7 +4024,7 @@ while (done <= 0)
if (!check_helo(smtp_cmd_data))
{
- smtp_printf("501 Syntactically invalid %s argument(s)\r\n", hello);
+ smtp_printf("501 Syntactically invalid %s argument(s)\r\n", FALSE, hello);
log_write(0, LOG_MAIN|LOG_REJECT, "rejected %s from %s: syntactically "
"invalid argument(s): %s", hello, host_and_ident(FALSE),
@@ -3960,7 +4088,7 @@ while (done <= 0)
{
if (helo_required)
{
- smtp_printf("%d %s argument does not match calling host\r\n",
+ smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
tempfail? 451 : 550, hello);
log_write(0, LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s",
tempfail? "temporarily " : "",
@@ -4010,19 +4138,19 @@ while (done <= 0)
#endif
smtp_code = US"250 "; /* Default response code plus space*/
- if (user_msg == NULL)
+ if (!user_msg)
{
s = string_sprintf("%.3s %s Hello %s%s%s",
smtp_code,
smtp_active_hostname,
- (sender_ident == NULL)? US"" : sender_ident,
- (sender_ident == NULL)? US"" : US" at ",
- (sender_host_name == NULL)? sender_helo_name : sender_host_name);
+ sender_ident ? sender_ident : US"",
+ sender_ident ? US" at " : US"",
+ sender_host_name ? sender_host_name : sender_helo_name);
ptr = Ustrlen(s);
size = ptr + 1;
- if (sender_host_address != NULL)
+ if (sender_host_address)
{
s = string_catn(s, &size, &ptr, US" [", 2);
s = string_cat (s, &size, &ptr, sender_host_address);
@@ -4150,26 +4278,34 @@ while (done <= 0)
auth_instance *au;
BOOL first = TRUE;
for (au = auths; au; au = au->next)
- if (au->server && (au->advertise_condition == NULL ||
- expand_check_condition(au->advertise_condition, au->name,
- US"authenticator")))
+ {
+ au->advertised = FALSE;
+ if (au->server)
{
- int saveptr;
- if (first)
+ DEBUG(D_auth+D_expand) debug_printf_indent(
+ "Evaluating advertise_condition for %s athenticator\n",
+ au->public_name);
+ if ( !au->advertise_condition
+ || expand_check_condition(au->advertise_condition, au->name,
+ US"authenticator")
+ )
{
- s = string_catn(s, &size, &ptr, smtp_code, 3);
- s = string_catn(s, &size, &ptr, US"-AUTH", 5);
- first = FALSE;
- auth_advertised = TRUE;
+ int saveptr;
+ if (first)
+ {
+ s = string_catn(s, &size, &ptr, smtp_code, 3);
+ s = string_catn(s, &size, &ptr, US"-AUTH", 5);
+ first = FALSE;
+ auth_advertised = TRUE;
+ }
+ saveptr = ptr;
+ s = string_catn(s, &size, &ptr, US" ", 1);
+ s = string_cat (s, &size, &ptr, au->public_name);
+ while (++saveptr < ptr) s[saveptr] = toupper(s[saveptr]);
+ au->advertised = TRUE;
}
- saveptr = ptr;
- s = string_catn(s, &size, &ptr, US" ", 1);
- s = string_cat (s, &size, &ptr, au->public_name);
- while (++saveptr < ptr) s[saveptr] = toupper(s[saveptr]);
- au->advertised = TRUE;
}
- else
- au->advertised = FALSE;
+ }
if (!first) s = string_catn(s, &size, &ptr, US"\r\n", 2);
}
@@ -4230,7 +4366,7 @@ while (done <= 0)
s[ptr] = 0;
#ifdef SUPPORT_TLS
- if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr); else
+ if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr, FALSE); else
#endif
{
@@ -4253,6 +4389,7 @@ while (done <= 0)
: pnormal)
+ (tls_in.active >= 0 ? pcrpted : 0)
];
+ cancel_cutthrough_connection(TRUE, US"sent EHLO response");
smtp_reset(reset_point);
toomany = FALSE;
break; /* HELO/EHLO */
@@ -4272,7 +4409,7 @@ while (done <= 0)
if (helo_required && !helo_seen)
{
- smtp_printf("503 HELO or EHLO required\r\n");
+ smtp_printf("503 HELO or EHLO required\r\n", FALSE);
log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
"HELO/EHLO given", host_and_ident(FALSE));
break;
@@ -4298,7 +4435,7 @@ while (done <= 0)
if (smtp_accept_max_per_connection > 0 &&
smtp_mailcmd_count > smtp_accept_max_per_connection)
{
- smtp_printf("421 too many messages in this connection\r\n");
+ smtp_printf("421 too many messages in this connection\r\n", FALSE);
log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "
"messages in one connection", host_and_ident(TRUE));
break;
@@ -4307,6 +4444,7 @@ while (done <= 0)
/* Reset for start of message - even if this is going to fail, we
obviously need to throw away any previous data. */
+ cancel_cutthrough_connection(TRUE, US"MAIL received");
smtp_reset(reset_point);
toomany = FALSE;
sender_data = recipient_data = NULL;
@@ -4562,7 +4700,7 @@ while (done <= 0)
if (thismessage_size_limit > 0 && message_size > thismessage_size_limit)
{
- smtp_printf("552 Message size exceeds maximum permitted\r\n");
+ smtp_printf("552 Message size exceeds maximum permitted\r\n", FALSE);
log_write(L_size_reject,
LOG_MAIN|LOG_REJECT, "rejected MAIL FROM:<%s> %s: "
"message too big: size%s=%d max=%d",
@@ -4587,7 +4725,7 @@ while (done <= 0)
(smtp_check_spool_space && message_size >= 0)?
message_size + 5000 : 0))
{
- smtp_printf("452 Space shortage, please try later\r\n");
+ smtp_printf("452 Space shortage, please try later\r\n", FALSE);
sender_address = NULL;
break;
}
@@ -4609,7 +4747,7 @@ while (done <= 0)
}
else
{
- smtp_printf("501 %s: sender address must contain a domain\r\n",
+ smtp_printf("501 %s: sender address must contain a domain\r\n", FALSE,
smtp_cmd_data);
log_write(L_smtp_syntax_error,
LOG_MAIN|LOG_REJECT,
@@ -4637,8 +4775,10 @@ while (done <= 0)
if (rc == OK || rc == DISCARD)
{
+ BOOL more = pipeline_response();
+
if (!user_msg)
- smtp_printf("%s%s%s", US"250 OK",
+ smtp_printf("%s%s%s", more, US"250 OK",
#ifndef DISABLE_PRDR
prdr_requested ? US", PRDR Requested" : US"",
#else
@@ -4684,7 +4824,7 @@ while (done <= 0)
{
if (pipelining_advertised && last_was_rej_mail)
{
- smtp_printf("503 sender not yet given\r\n");
+ smtp_printf("503 sender not yet given\r\n", FALSE);
was_rej_mail = TRUE;
}
else
@@ -4832,7 +4972,7 @@ while (done <= 0)
if (recipients_max_reject)
{
rcpt_fail_count++;
- smtp_printf("552 too many recipients\r\n");
+ smtp_printf("552 too many recipients\r\n", FALSE);
if (!toomany)
log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: message "
"rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE));
@@ -4840,7 +4980,7 @@ while (done <= 0)
else
{
rcpt_defer_count++;
- smtp_printf("452 too many recipients\r\n");
+ smtp_printf("452 too many recipients\r\n", FALSE);
if (!toomany)
log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: excess "
"temporarily rejected: sender=<%s> %s", sender_address,
@@ -4882,10 +5022,12 @@ while (done <= 0)
if (rc == OK)
{
+ BOOL more = pipeline_response();
+
if (user_msg)
smtp_user_msg(US"250", user_msg);
else
- smtp_printf("250 Accepted\r\n");
+ smtp_printf("250 Accepted\r\n", more);
receive_add_recipient(recipient, -1);
/* Set the dsn flags in the recipients_list */
@@ -4904,7 +5046,7 @@ while (done <= 0)
if (user_msg)
smtp_user_msg(US"250", user_msg);
else
- smtp_printf("250 Accepted\r\n");
+ smtp_printf("250 Accepted\r\n", FALSE);
rcpt_fail_count++;
discarded = TRUE;
log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: "
@@ -4971,6 +5113,7 @@ while (done <= 0)
(int)chunking_state, chunking_data_left);
lwr_receive_getc = receive_getc;
+ lwr_receive_getbuf = receive_getbuf;
lwr_receive_ungetc = receive_ungetc;
receive_getc = bdat_getc;
receive_ungetc = bdat_ungetc;
@@ -4996,7 +5139,7 @@ while (done <= 0)
smtp_respond(code, 3, FALSE, rcpt_smtp_response);
}
if (pipelining_advertised && last_was_rcpt)
- smtp_printf("503 Valid RCPT command must precede %s\r\n",
+ smtp_printf("503 Valid RCPT command must precede %s\r\n", FALSE,
smtp_names[smtp_connection_had[smtp_ch_index-1]]);
else
done = synprot_error(L_smtp_protocol_error, 503, NULL,
@@ -5013,7 +5156,7 @@ while (done <= 0)
{
sender_address = NULL; /* This will allow a new MAIL without RSET */
sender_address_unrewritten = NULL;
- smtp_printf("554 Too many recipients\r\n");
+ smtp_printf("554 Too many recipients\r\n", FALSE);
break;
}
@@ -5048,7 +5191,7 @@ while (done <= 0)
smtp_user_msg(US"354", user_msg);
else
smtp_printf(
- "354 Enter message, ending with \".\" on a line by itself\r\n");
+ "354 Enter message, ending with \".\" on a line by itself\r\n", FALSE);
}
#ifdef TCP_QUICKACK
@@ -5071,7 +5214,7 @@ while (done <= 0)
if (!(address = parse_extract_address(smtp_cmd_data, &errmess,
&start, &end, &recipient_domain, FALSE)))
{
- smtp_printf("501 %s\r\n", errmess);
+ smtp_printf("501 %s\r\n", FALSE, errmess);
break;
}
@@ -5110,7 +5253,7 @@ while (done <= 0)
break;
}
- smtp_printf("%s\r\n", s);
+ smtp_printf("%s\r\n", FALSE, s);
}
break;
}
@@ -5162,6 +5305,7 @@ while (done <= 0)
do an implied RSET when STARTTLS is received. */
incomplete_transaction_log(US"STARTTLS");
+ cancel_cutthrough_connection(TRUE, US"STARTTLS received");
smtp_reset(reset_point);
toomany = FALSE;
cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
@@ -5238,7 +5382,7 @@ while (done <= 0)
if (rc == DEFER)
{
- smtp_printf("454 TLS currently unavailable\r\n");
+ smtp_printf("454 TLS currently unavailable\r\n", FALSE);
break;
}
@@ -5271,14 +5415,14 @@ while (done <= 0)
if (user_msg)
smtp_respond(US"221", 3, TRUE, user_msg);
else
- smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+ smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
smtp_get_connection_info());
done = 2;
break;
default:
- smtp_printf("554 Security failure\r\n");
+ smtp_printf("554 Security failure\r\n", FALSE);
break;
}
tls_close(TRUE, TRUE);
@@ -5298,6 +5442,7 @@ while (done <= 0)
case RSET_CMD:
smtp_rset_handler();
+ cancel_cutthrough_connection(TRUE, US"RSET received");
smtp_reset(reset_point);
toomany = FALSE;
break;
@@ -5305,7 +5450,7 @@ while (done <= 0)
case NOOP_CMD:
HAD(SCH_NOOP);
- smtp_printf("250 OK\r\n");
+ smtp_printf("250 OK\r\n", FALSE);
break;
@@ -5316,7 +5461,7 @@ while (done <= 0)
case HELP_CMD:
HAD(SCH_HELP);
- smtp_printf("214-Commands supported:\r\n");
+ smtp_printf("214-Commands supported:\r\n", TRUE);
{
uschar buffer[256];
buffer[0] = 0;
@@ -5331,7 +5476,7 @@ while (done <= 0)
if (acl_smtp_etrn != NULL) Ustrcat(buffer, " ETRN");
if (acl_smtp_expn != NULL) Ustrcat(buffer, " EXPN");
if (acl_smtp_vrfy != NULL) Ustrcat(buffer, " VRFY");
- smtp_printf("214%s\r\n", buffer);
+ smtp_printf("214%s\r\n", FALSE, buffer);
}
break;
@@ -5345,15 +5490,22 @@ while (done <= 0)
just drop the call rather than sending QUIT, and it clutters up the logs.
*/
- if (sender_address != NULL || recipients_count > 0)
- log_write(L_lost_incoming_connection,
- LOG_MAIN,
- "unexpected %s while reading SMTP command from %s%s",
- sender_host_unknown? "EOF" : "disconnection",
- host_and_ident(FALSE), smtp_read_error);
+ if (sender_address || recipients_count > 0)
+ log_write(L_lost_incoming_connection, LOG_MAIN,
+ "unexpected %s while reading SMTP command from %s%s%s D=%s",
+ sender_host_unknown ? "EOF" : "disconnection",
+ tcp_in_fastopen && !tcp_in_fastopen_logged ? US"TFO " : US"",
+ host_and_ident(FALSE), smtp_read_error,
+ string_timesince(&smtp_connection_start)
+ );
- else log_write(L_smtp_connection, LOG_MAIN, "%s lost%s",
- smtp_get_connection_info(), smtp_read_error);
+ else
+ log_write(L_smtp_connection, LOG_MAIN, "%s %slost%s D=%s",
+ smtp_get_connection_info(),
+ tcp_in_fastopen && !tcp_in_fastopen_logged ? US"TFO " : US"",
+ smtp_read_error,
+ string_timesince(&smtp_connection_start)
+ );
done = 1;
break;
@@ -5400,7 +5552,7 @@ while (done <= 0)
{
log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s",
error);
- smtp_printf("458 Internal failure\r\n");
+ smtp_printf("458 Internal failure\r\n", FALSE);
break;
}
}
@@ -5431,7 +5583,7 @@ while (done <= 0)
debug_printf("ETRN command is: %s\n", etrn_command);
debug_printf("ETRN command execution skipped\n");
}
- if (user_msg == NULL) smtp_printf("250 OK\r\n");
+ if (user_msg == NULL) smtp_printf("250 OK\r\n", FALSE);
else smtp_user_msg(US"250", user_msg);
break;
}
@@ -5442,7 +5594,7 @@ while (done <= 0)
if (smtp_etrn_serialize && !enq_start(etrn_serialize_key, 1))
{
- smtp_printf("458 Already processing %s\r\n", smtp_cmd_data);
+ smtp_printf("458 Already processing %s\r\n", FALSE, smtp_cmd_data);
break;
}
@@ -5505,12 +5657,12 @@ while (done <= 0)
{
log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s",
strerror(errno));
- smtp_printf("458 Unable to fork process\r\n");
+ smtp_printf("458 Unable to fork process\r\n", FALSE);
if (smtp_etrn_serialize) enq_end(etrn_serialize_key);
}
else
{
- if (user_msg == NULL) smtp_printf("250 OK\r\n");
+ if (user_msg == NULL) smtp_printf("250 OK\r\n", FALSE);
else smtp_user_msg(US"250", user_msg);
}
@@ -5529,7 +5681,7 @@ while (done <= 0)
case BADCHAR_CMD:
done = synprot_error(L_smtp_syntax_error, 0, NULL, /* Just logs */
US"NULL character(s) present (shown as '?')");
- smtp_printf("501 NULL characters are not allowed in SMTP commands\r\n");
+ smtp_printf("501 NULL characters are not allowed in SMTP commands\r\n", FALSE);
break;
@@ -5566,7 +5718,7 @@ while (done <= 0)
#ifdef SUPPORT_PROXY
case PROXY_FAIL_IGNORE_CMD:
- smtp_printf("503 Command refused, required Proxy negotiation failed\r\n");
+ smtp_printf("503 Command refused, required Proxy negotiation failed\r\n", FALSE);
break;
#endif
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index ba6153ea9..db33ac66e 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -100,7 +100,7 @@ smtp_get_port(uschar *rstring, address_item *addr, int *port, uschar *msg)
{
uschar *pstring = expand_string(rstring);
-if (pstring == NULL)
+if (!pstring)
{
addr->transport_return = PANIC;
addr->message = string_sprintf("failed to expand \"%s\" (\"port\" option) "
@@ -124,7 +124,7 @@ if (isdigit(*pstring))
else
{
struct servent *smtp_service = getservbyname(CS pstring, "tcp");
- if (smtp_service == NULL)
+ if (!smtp_service)
{
addr->transport_return = PANIC;
addr->message = string_sprintf("TCP port \"%s\" is not defined for %s",
@@ -140,9 +140,15 @@ return TRUE;
+/* Arguments as for smtp_connect(), plus
+ early_data if non-NULL, data to be sent - preferably in the TCP SYN segment
+
+Returns: connected socket number, or -1 with errno set
+*/
+
int
smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
- transport_instance * tb, int timeout)
+ transport_instance * tb, int timeout, const blob * early_data)
{
smtp_transport_options_block * ob =
(smtp_transport_options_block *)tb->options_block;
@@ -152,7 +158,6 @@ int dscp_level;
int dscp_option;
int sock;
int save_errno = 0;
-BOOL fastopen = FALSE;
#ifndef DISABLE_EVENT
deliver_host_address = host->address;
@@ -185,10 +190,6 @@ if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
(void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
}
-#ifdef TCP_FASTOPEN
-if (verify_check_given_host (&ob->hosts_try_fastopen, host) == OK) fastopen = TRUE;
-#endif
-
/* Bind to a specific interface if requested. Caller must ensure the interface
is the same type (IPv4 or IPv6) as the outgoing address. */
@@ -201,10 +202,24 @@ if (interface && ip_bind(sock, host_af, interface, 0) < 0)
}
/* Connect to the remote host, and add keepalive to the socket before returning
-it, if requested. */
+it, if requested. If the build supports TFO, request it - and if the caller
+requested some early-data then include that in the TFO request. */
-else if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
- save_errno = errno;
+else
+ {
+ const blob * fastopen = NULL;
+
+#ifdef TCP_FASTOPEN
+ if (verify_check_given_host(&ob->hosts_try_fastopen, host) == OK)
+ fastopen = early_data ? early_data : &tcp_fastopen_nodata;
+#endif
+
+ if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
+ save_errno = errno;
+ else if (early_data && !fastopen && early_data->data && early_data->len)
+ if (send(sock, early_data->data, early_data->len, 0) < 0)
+ save_errno = errno;
+ }
/* Either bind() or connect() failed */
@@ -243,6 +258,24 @@ else
}
}
+
+
+
+
+void
+smtp_port_for_connect(host_item * host, int port)
+{
+if (host->port != PORT_NONE)
+ {
+ HDEBUG(D_transport|D_acl|D_v)
+ debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
+ host->port);
+ port = host->port;
+ }
+else host->port = port; /* Set the port actually used */
+}
+
+
/*************************************************
* Connect to remote host *
*************************************************/
@@ -252,15 +285,9 @@ detected by checking for a colon in the address. AF_INET6 is defined even on
non-IPv6 systems, to enable the code to be less messy. However, on such systems
host->address will always be an IPv4 address.
-The port field in the host item is used if it is set (usually router from SRV
-records or elsewhere). In other cases, the default passed as an argument is
-used, and the host item is updated with its value.
-
Arguments:
- host host item containing name and address (and sometimes port)
+ host host item containing name and address and port
host_af AF_INET or AF_INET6
- port default remote port to connect to, in host byte order, for those
- hosts whose port setting is PORT_NONE
interface outgoing interface address or NULL
timeout timeout value or 0
tb transport
@@ -269,23 +296,15 @@ Returns: connected socket number, or -1 with errno set
*/
int
-smtp_connect(host_item *host, int host_af, int port, uschar *interface,
+smtp_connect(host_item *host, int host_af, uschar *interface,
int timeout, transport_instance * tb)
{
+int port = host->port;
#ifdef SUPPORT_SOCKS
smtp_transport_options_block * ob =
(smtp_transport_options_block *)tb->options_block;
#endif
-if (host->port != PORT_NONE)
- {
- HDEBUG(D_transport|D_acl|D_v)
- debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
- host->port);
- port = host->port;
- }
-else host->port = port; /* Set the port actually used */
-
callout_address = string_sprintf("[%s]:%d", host->address, port);
HDEBUG(D_transport|D_acl|D_v)
@@ -305,7 +324,7 @@ if (ob->socks_proxy)
return socks_sock_connect(host, host_af, port, interface, tb, timeout);
#endif
-return smtp_sock_connect(host, host_af, port, interface, tb, timeout);
+return smtp_sock_connect(host, host_af, port, interface, tb, timeout, NULL);
}
@@ -319,23 +338,33 @@ pipelining.
Argument:
outblock the SMTP output block
+ mode further data expected, or plain
Returns: TRUE if OK, FALSE on error, with errno set
*/
static BOOL
-flush_buffer(smtp_outblock *outblock)
+flush_buffer(smtp_outblock * outblock, int mode)
{
int rc;
int n = outblock->ptr - outblock->buffer;
+BOOL more = mode == SCMD_MORE;
+
+HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
+ more ? " (more expected)" : "");
-HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes\n", n);
#ifdef SUPPORT_TLS
if (tls_out.active == outblock->sock)
- rc = tls_write(FALSE, outblock->buffer, n);
+ rc = tls_write(FALSE, outblock->buffer, n, more);
else
#endif
- rc = send(outblock->sock, outblock->buffer, n, 0);
+ rc = send(outblock->sock, outblock->buffer, n,
+#ifdef MSG_MORE
+ more ? MSG_MORE : 0
+#else
+ 0
+#endif
+ );
if (rc <= 0)
{
@@ -359,7 +388,7 @@ any error message.
Arguments:
outblock contains buffer for pipelining, and socket
- noflush if TRUE, save the command in the output buffer, for pipelining
+ mode buffer, write-with-more-likely, write
format a format, starting with one of
of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT.
If NULL, flush pipeline buffer only.
@@ -371,7 +400,7 @@ Returns: 0 if command added to pipelining buffer, with nothing transmitted
*/
int
-smtp_write_command(smtp_outblock *outblock, BOOL noflush, const char *format, ...)
+smtp_write_command(smtp_outblock * outblock, int mode, const char *format, ...)
{
int count;
int rc = 0;
@@ -393,7 +422,7 @@ if (format)
if (count > outblock->buffersize - (outblock->ptr - outblock->buffer))
{
rc = outblock->cmd_count; /* flush resets */
- if (!flush_buffer(outblock)) return -1;
+ if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
}
Ustrncpy(CS outblock->ptr, big_buffer, count);
@@ -423,10 +452,10 @@ if (format)
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> %s\n", big_buffer);
}
-if (!noflush)
+if (mode != SCMD_BUFFER)
{
rc += outblock->cmd_count; /* flush resets */
- if (!flush_buffer(outblock)) return -1;
+ if (!flush_buffer(outblock, mode)) return -1;
}
return rc;
@@ -500,8 +529,9 @@ for (;;)
if((rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout)) <= 0)
{
- if (!errno)
- DEBUG(D_deliver|D_transport|D_acl) debug_printf_indent(" SMTP(closed)<<\n");
+ DEBUG(D_deliver|D_transport|D_acl)
+ debug_printf_indent(errno ? " SMTP(%s)<<\n" : " SMTP(closed)<<\n",
+ strerror(errno));
break;
}
diff --git a/src/src/spam.c b/src/src/spam.c
index d4b95b2f9..20154da4f 100644
--- a/src/src/spam.c
+++ b/src/src/spam.c
@@ -265,11 +265,9 @@ if (spam_ok && Ustrcmp(prev_user_name, user_name) == 0)
return override ? OK : spam_rc;
/* make sure the eml mbox file is spooled up */
-mbox_file = spool_mbox(&mbox_size, NULL);
-if (mbox_file == NULL)
- {
- /* error while spooling */
+if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL)))
+ { /* error while spooling */
log_write(0, LOG_MAIN|LOG_PANIC,
"%s error while creating mbox spool file", loglabel);
return DEFER;
@@ -287,8 +285,7 @@ start = time(NULL);
/* Check how many spamd servers we have
and register their addresses */
sep = 0; /* default colon-sep */
- while ((address = string_nextinlist(&spamd_address_list_ptr, &sep,
- NULL, 0)) != NULL)
+ while ((address = string_nextinlist(&spamd_address_list_ptr, &sep, NULL, 0)))
{
const uschar * sublist;
int sublist_sep = -(int)' '; /* default space-sep */
@@ -346,6 +343,7 @@ start = time(NULL);
for (;;)
{
+ /*XXX could potentially use TFO early-data here */
if ( (spamd_sock = ip_streamsocket(sd->hostspec, &errstr, 5)) >= 0
|| sd->retry <= 0
)
@@ -372,27 +370,30 @@ start = time(NULL);
(void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
/* now we are connected to spamd on spamd_sock */
if (sd->is_rspamd)
- { /* rspamd variant */
- uschar *req_str;
- const uschar * helo;
- const uschar * fcrdns;
- const uschar * authid;
-
- req_str = string_sprintf("CHECK RSPAMC/1.3\r\nContent-length: %lu\r\n"
- "Queue-Id: %s\r\nFrom: <%s>\r\nRecipient-Number: %d\r\n",
- mbox_size, message_id, sender_address, recipients_count);
+ {
+ uschar * req_str = NULL;
+ int size = 0, len = 0;
+ const uschar * s;
+
+ req_str = string_append(req_str, &size, &len, 8,
+ "CHECK RSPAMC/1.3\r\nContent-length: ", string_sprintf("%lu\r\n", mbox_size),
+ "Queue-Id: ", message_id,
+ "\r\nFrom: <", sender_address,
+ ">\r\nRecipient-Number: ", string_sprintf("%d\r\n", recipients_count));
+
for (i = 0; i < recipients_count; i ++)
- req_str = string_sprintf("%sRcpt: <%s>\r\n", req_str, recipients_list[i].address);
- if ((helo = expand_string(US"$sender_helo_name")) != NULL && *helo != '\0')
- req_str = string_sprintf("%sHelo: %s\r\n", req_str, helo);
- if ((fcrdns = expand_string(US"$sender_host_name")) != NULL && *fcrdns != '\0')
- req_str = string_sprintf("%sHostname: %s\r\n", req_str, fcrdns);
- if (sender_host_address != NULL)
- req_str = string_sprintf("%sIP: %s\r\n", req_str, sender_host_address);
- if ((authid = expand_string(US"$authenticated_id")) != NULL && *authid != '\0')
- req_str = string_sprintf("%sUser: %s\r\n", req_str, authid);
- req_str = string_sprintf("%s\r\n", req_str);
- wrote = send(spamd_sock, req_str, Ustrlen(req_str), 0);
+ req_str = string_append(req_str, &size, &len, 3,
+ "Rcpt: <", recipients_list[i].address, ">\r\n");
+ if ((s = expand_string(US"$sender_helo_name")) && *s)
+ req_str = string_append(req_str, &size, &len, 3, "Helo: ", s, "\r\n");
+ if ((s = expand_string(US"$sender_host_name")) && *s)
+ req_str = string_append(req_str, &size, &len, 3, "Hostname: ", s, "\r\n");
+ if (sender_host_address)
+ req_str = string_append(req_str, &size, &len, 3, "IP: ", sender_host_address, "\r\n");
+ if ((s = expand_string(US"$authenticated_id")) && *s)
+ req_str = string_append(req_str, &size, &len, 3, "User: ", s, "\r\n");
+ req_str = string_catn(req_str, &size, &len, "\r\n", 2);
+ wrote = send(spamd_sock, req_str, len, 0);
}
else
{ /* spamassassin variant */
diff --git a/src/src/spf.c b/src/src/spf.c
index 9ab56af23..2741c7baf 100644
--- a/src/src/spf.c
+++ b/src/src/spf.c
@@ -15,16 +15,17 @@
/* must be kept in numeric order */
static spf_result_id spf_result_id_list[] = {
- { US"invalid", 0},
- { US"neutral", 1 },
- { US"pass", 2 },
- { US"fail", 3 },
- { US"softfail", 4 },
- { US"none", 5 },
- { US"err_temp", 6 }, /* Deprecated Apr 2014 */
- { US"err_perm", 7 }, /* Deprecated Apr 2014 */
- { US"temperror", 6 }, /* RFC 4408 defined */
- { US"permerror", 7 } /* RFC 4408 defined */
+ /* name value */
+ { US"invalid", 0},
+ { US"neutral", 1 },
+ { US"pass", 2 },
+ { US"fail", 3 },
+ { US"softfail", 4 },
+ { US"none", 5 },
+ { US"err_temp", 6 }, /* Deprecated Apr 2014 */
+ { US"err_perm", 7 }, /* Deprecated Apr 2014 */
+ { US"temperror", 6 }, /* RFC 4408 defined */
+ { US"permerror", 7 } /* RFC 4408 defined */
};
SPF_server_t *spf_server = NULL;
@@ -102,10 +103,10 @@ int spf_process(const uschar **listptr, uschar *spf_envelope_sender, int action)
SPF_request_query_mailfrom(spf_request, &spf_response);
/* set up expansion items */
- spf_header_comment = (uschar *)SPF_response_get_header_comment(spf_response);
- spf_received = (uschar *)SPF_response_get_received_spf(spf_response);
- spf_result = (uschar *)SPF_strresult(SPF_response_result(spf_response));
- spf_smtp_comment = (uschar *)SPF_response_get_smtp_comment(spf_response);
+ spf_header_comment = US SPF_response_get_header_comment(spf_response);
+ spf_received = US SPF_response_get_received_spf(spf_response);
+ spf_result = US SPF_strresult(SPF_response_result(spf_response));
+ spf_smtp_comment = US SPF_response_get_smtp_comment(spf_response);
rc = SPF_response_result(spf_response);
diff --git a/src/src/spool_in.c b/src/src/spool_in.c
index 6ed566411..a5b14959f 100644
--- a/src/src/spool_in.c
+++ b/src/src/spool_in.c
@@ -284,6 +284,9 @@ sender_ident = NULL;
sender_local = FALSE;
sender_set_untrusted = FALSE;
smtp_active_hostname = primary_hostname;
+#ifndef COMPILE_UTILITY
+spool_file_wireformat = FALSE;
+#endif
tree_nonrecipients = NULL;
#ifdef EXPERIMENTAL_BRIGHTMAIL
@@ -394,10 +397,11 @@ sender_address[n-3] = 0;
/* time */
if (Ufgets(big_buffer, big_buffer_size, f) == NULL) goto SPOOL_READ_ERROR;
-if (sscanf(CS big_buffer, "%d %d", &received_time, &warning_count) != 2)
+if (sscanf(CS big_buffer, TIME_T_FMT " %d", &received_time.tv_sec, &warning_count) != 2)
goto SPOOL_FORMAT_ERROR;
+received_time.tv_usec = 0;
-message_age = time(NULL) - received_time;
+message_age = time(NULL) - received_time.tv_sec;
#ifndef COMPILE_UTILITY
DEBUG(D_deliver) debug_printf("user=%s uid=%ld gid=%ld sender=%s\n",
@@ -570,7 +574,8 @@ for (;;)
break;
case 'l':
- if (Ustrcmp(p, "ocal") == 0) sender_local = TRUE;
+ if (Ustrcmp(p, "ocal") == 0)
+ sender_local = TRUE;
else if (Ustrcmp(big_buffer, "-localerror") == 0)
local_error_message = TRUE;
else if (Ustrncmp(p, "ocal_scan ", 10) == 0)
@@ -590,6 +595,12 @@ for (;;)
case 'r':
if (Ustrncmp(p, "eceived_protocol", 16) == 0)
received_protocol = string_copy(big_buffer + 19);
+ else if (Ustrncmp(p, "eceived_time_usec", 17) == 0)
+ {
+ unsigned usec;
+ if (sscanf(CS big_buffer + 21, "%u", &usec) == 1)
+ received_time.tv_usec = usec;
+ }
break;
case 's':
@@ -603,6 +614,10 @@ for (;;)
else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
spam_score_int = string_copy(big_buffer + 16);
#endif
+#ifndef COMPILE_UTILITY
+ else if (Ustrncmp(p, "pool_file_wireformat", 20) == 0)
+ spool_file_wireformat = TRUE;
+#endif
#if defined(SUPPORT_I18N) && !defined(COMPILE_UTILITY)
else if (Ustrncmp(p, "mtputf8", 7) == 0)
message_smtputf8 = TRUE;
diff --git a/src/src/spool_mbox.c b/src/src/spool_mbox.c
index b1de39e7d..432634094 100644
--- a/src/src/spool_mbox.c
+++ b/src/src/spool_mbox.c
@@ -19,11 +19,17 @@ extern int spam_ok;
int spool_mbox_ok = 0;
uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
-/* returns a pointer to the FILE, and puts the size in bytes into mbox_file_size
- * normally, source_file_override is NULL */
+/*
+Create an MBOX-style message file from the spooled files.
+
+Returns a pointer to the FILE, and puts the size in bytes into mbox_file_size.
+If mbox_fname is non-null, fill in a pointer to the name.
+Normally, source_file_override is NULL
+*/
FILE *
-spool_mbox(unsigned long *mbox_file_size, const uschar *source_file_override)
+spool_mbox(unsigned long *mbox_file_size, const uschar *source_file_override,
+ uschar ** mbox_fname)
{
uschar message_subdir[2];
uschar buffer[16384];
@@ -35,10 +41,13 @@ FILE *yield = NULL;
header_line *my_headerlist;
struct stat statbuf;
int i, j;
-void *reset_point = store_get(0);
+void *reset_point;
+
+mbox_path = string_sprintf("%s/scan/%s/%s.eml",
+ spool_directory, message_id, message_id);
+if (mbox_fname) *mbox_fname = mbox_path;
-mbox_path = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id,
- message_id);
+reset_point = store_get(0);
/* Skip creation if already spooled out as mbox file */
if (!spool_mbox_ok)
@@ -53,8 +62,8 @@ if (!spool_mbox_ok)
}
/* open [message_id].eml file for writing */
- mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE);
- if (mbox_file == NULL)
+
+ if (!(mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE)))
{
log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
"scan file %s", mbox_path));
@@ -71,33 +80,25 @@ if (!spool_mbox_ok)
"${if def:sender_address{X-Envelope-From: <${sender_address}>\n}}"
"${if def:recipients{X-Envelope-To: ${recipients}\n}}");
- if (temp_string != NULL)
- {
- i = fwrite(temp_string, Ustrlen(temp_string), 1, mbox_file);
- if (i != 1)
+ if (temp_string)
+ if (fwrite(temp_string, Ustrlen(temp_string), 1, mbox_file) != 1)
{
log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
mailbox headers to %s", mbox_path);
goto OUT;
}
- }
- /* write all header lines to mbox file */
- my_headerlist = header_list;
- for (my_headerlist = header_list; my_headerlist != NULL;
- my_headerlist = my_headerlist->next)
- {
- /* skip deleted headers */
- if (my_headerlist->type == '*') continue;
+ /* write all non-deleted header lines to mbox file */
- i = fwrite(my_headerlist->text, my_headerlist->slen, 1, mbox_file);
- if (i != 1)
- {
- log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
- message headers to %s", mbox_path);
- goto OUT;
- }
- }
+ for (my_headerlist = header_list; my_headerlist;
+ my_headerlist = my_headerlist->next)
+ if (my_headerlist->type != '*')
+ if (fwrite(my_headerlist->text, my_headerlist->slen, 1, mbox_file) != 1)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
+ message headers to %s", mbox_path);
+ goto OUT;
+ }
/* End headers */
if (fwrite("\n", 1, 1, mbox_file) != 1)
@@ -108,7 +109,7 @@ if (!spool_mbox_ok)
}
/* copy body file */
- if (source_file_override == NULL)
+ if (!source_file_override)
{
message_subdir[1] = '\0';
for (i = 0; i < 2; i++)
@@ -142,18 +143,32 @@ if (!spool_mbox_ok)
do
{
- j = fread(buffer, 1, sizeof(buffer), data_file);
+ uschar * s;
+
+ if (!spool_file_wireformat || source_file_override)
+ j = fread(buffer, 1, sizeof(buffer), data_file);
+ else /* needs CRLF -> NL */
+ if ((s = US fgets(CS buffer, sizeof(buffer), data_file)))
+ {
+ uschar * p = s + Ustrlen(s) - 1;
+
+ if (*p == '\n' && p[-1] == '\r')
+ *--p = '\n';
+ else if (*p == '\r')
+ ungetc(*p--, data_file);
+
+ j = p - buffer;
+ }
+ else
+ j = 0;
if (j > 0)
- {
- i = fwrite(buffer, j, 1, mbox_file);
- if (i != 1)
+ if (fwrite(buffer, j, 1, mbox_file) != 1)
{
log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
message body to %s", mbox_path);
goto OUT;
}
- }
} while (j > 0);
(void)fclose(mbox_file);
@@ -201,8 +216,7 @@ if (spool_mbox_ok && !no_mbox_unspool)
mbox_path = string_sprintf("%s/scan/%s", spool_directory, spooled_message_id);
- tempdir = opendir(CS mbox_path);
- if (!tempdir)
+ if (!(tempdir = opendir(CS mbox_path)))
{
debug_printf("Unable to opendir(%s): %s\n", mbox_path, strerror(errno));
/* Just in case we still can: */
@@ -210,7 +224,7 @@ if (spool_mbox_ok && !no_mbox_unspool)
return;
}
/* loop thru dir & delete entries */
- while((entry = readdir(tempdir)) != NULL)
+ while((entry = readdir(tempdir)))
{
uschar *name = US entry->d_name;
int dummy;
@@ -218,7 +232,7 @@ if (spool_mbox_ok && !no_mbox_unspool)
file_path = string_sprintf("%s/%s", mbox_path, name);
debug_printf("unspool_mbox(): unlinking '%s'\n", file_path);
- dummy = unlink(CS file_path);
+ dummy = unlink(CS file_path); dummy = dummy; /* compiler quietening */
}
closedir(tempdir);
diff --git a/src/src/spool_out.c b/src/src/spool_out.c
index 652506fb3..449662253 100644
--- a/src/src/spool_out.c
+++ b/src/src/spool_out.c
@@ -154,26 +154,28 @@ fprintf(f, "%s-H\n", message_id);
fprintf(f, "%.63s %ld %ld\n", originator_login, (long int)originator_uid,
(long int)originator_gid);
fprintf(f, "<%s>\n", sender_address);
-fprintf(f, "%d %d\n", received_time, warning_count);
+fprintf(f, "%d %d\n", (int)received_time.tv_sec, warning_count);
+
+fprintf(f, "-received_time_usec .%06d\n", (int)received_time.tv_usec);
/* If there is information about a sending host, remember it. The HELO
data can be set for local SMTP as well as remote. */
-if (sender_helo_name != NULL)
+if (sender_helo_name)
fprintf(f, "-helo_name %s\n", sender_helo_name);
-if (sender_host_address != NULL)
+if (sender_host_address)
{
fprintf(f, "-host_address %s.%d\n", sender_host_address, sender_host_port);
- if (sender_host_name != NULL)
+ if (sender_host_name)
fprintf(f, "-host_name %s\n", sender_host_name);
- if (sender_host_authenticated != NULL)
+ if (sender_host_authenticated)
fprintf(f, "-host_auth %s\n", sender_host_authenticated);
}
/* Also about the interface a message came in on */
-if (interface_address != NULL)
+if (interface_address)
fprintf(f, "-interface_address %s.%d\n", interface_address, interface_port);
if (smtp_active_hostname != primary_hostname)
@@ -183,11 +185,11 @@ if (smtp_active_hostname != primary_hostname)
likely to be the same as originator_login, but will be different if
the originator was root, forcing a different ident. */
-if (sender_ident != NULL) fprintf(f, "-ident %s\n", sender_ident);
+if (sender_ident) fprintf(f, "-ident %s\n", sender_ident);
/* Ditto for the received protocol */
-if (received_protocol != NULL)
+if (received_protocol)
fprintf(f, "-received_protocol %s\n", received_protocol);
/* Preserve any ACL variables that are set. */
@@ -197,14 +199,17 @@ tree_walk(acl_var_m, &acl_var_write, f);
/* Now any other data that needs to be remembered. */
-fprintf(f, "-body_linecount %d\n", body_linecount);
+if (spool_file_wireformat)
+ fprintf(f, "-spool_file_wireformat\n");
+else
+ fprintf(f, "-body_linecount %d\n", body_linecount);
fprintf(f, "-max_received_linelength %d\n", max_received_linelength);
if (body_zerocount > 0) fprintf(f, "-body_zerocount %d\n", body_zerocount);
-if (authenticated_id != NULL)
+if (authenticated_id)
fprintf(f, "-auth_id %s\n", authenticated_id);
-if (authenticated_sender != NULL)
+if (authenticated_sender)
fprintf(f, "-auth_sender %s\n", authenticated_sender);
if (allow_unqualified_recipient) fprintf(f, "-allow_unqualified_recipient\n");
@@ -258,7 +263,7 @@ if (message_smtputf8)
/* Write the dsn flags to the spool header file */
DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
-if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
+if (dsn_envid) fprintf(f, "-dsn_envid %s\n", dsn_envid);
DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret);
@@ -313,7 +318,7 @@ various other headers, or an asterisk for old headers that have been rewritten.
These are saved as a record for debugging. Don't included them in the message's
size. */
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
{
fprintf(f, "%03d%c %s", h->slen, h->type, h->text);
size_correction += 5;
diff --git a/src/src/std-crypto.c b/src/src/std-crypto.c
index 8ccef122b..d41e2a195 100644
--- a/src/src/std-crypto.c
+++ b/src/src/std-crypto.c
@@ -961,26 +961,27 @@ struct dh_constant {
/* KEEP SORTED ALPHABETICALLY;
* duplicate PEM are okay, if we want aliases, but names must be alphabetical */
static struct dh_constant dh_constants[] = {
- { "default", dh_exim_20160529_3 },
- { "exim.dev.20160529.1", dh_exim_20160529_1 },
- { "exim.dev.20160529.2", dh_exim_20160529_2 },
- { "exim.dev.20160529.3", dh_exim_20160529_3 },
- { "ffdhe2048", dh_ffdhe2048_pem },
- { "ffdhe3072", dh_ffdhe3072_pem },
- { "ffdhe4096", dh_ffdhe4096_pem },
- { "ffdhe6144", dh_ffdhe6144_pem },
- { "ffdhe8192", dh_ffdhe8192_pem },
- { "ike1", dh_ike_1_pem },
- { "ike14", dh_ike_14_pem },
- { "ike15", dh_ike_15_pem },
- { "ike16", dh_ike_16_pem },
- { "ike17", dh_ike_17_pem },
- { "ike18", dh_ike_18_pem },
- { "ike2", dh_ike_2_pem },
- { "ike22", dh_ike_22_pem },
- { "ike23", dh_ike_23_pem },
- { "ike24", dh_ike_24_pem },
- { "ike5", dh_ike_5_pem },
+ /* label pem */
+ { "default", dh_exim_20160529_3 },
+ { "exim.dev.20160529.1", dh_exim_20160529_1 },
+ { "exim.dev.20160529.2", dh_exim_20160529_2 },
+ { "exim.dev.20160529.3", dh_exim_20160529_3 },
+ { "ffdhe2048", dh_ffdhe2048_pem },
+ { "ffdhe3072", dh_ffdhe3072_pem },
+ { "ffdhe4096", dh_ffdhe4096_pem },
+ { "ffdhe6144", dh_ffdhe6144_pem },
+ { "ffdhe8192", dh_ffdhe8192_pem },
+ { "ike1", dh_ike_1_pem },
+ { "ike14", dh_ike_14_pem },
+ { "ike15", dh_ike_15_pem },
+ { "ike16", dh_ike_16_pem },
+ { "ike17", dh_ike_17_pem },
+ { "ike18", dh_ike_18_pem },
+ { "ike2", dh_ike_2_pem },
+ { "ike22", dh_ike_22_pem },
+ { "ike23", dh_ike_23_pem },
+ { "ike24", dh_ike_24_pem },
+ { "ike5", dh_ike_5_pem },
};
static const int dh_constants_count =
sizeof(dh_constants) / sizeof(struct dh_constant);
diff --git a/src/src/store.c b/src/src/store.c
index 8628954b5..12db584ce 100644
--- a/src/src/store.c
+++ b/src/src/store.c
@@ -205,7 +205,7 @@ DEBUG(D_memory)
(void) VALGRIND_MAKE_MEM_UNDEFINED(store_last_get[store_pool], size);
/* Update next pointer and number of bytes left in the current block. */
-next_yield[store_pool] = (void *)((char *)next_yield[store_pool] + size);
+next_yield[store_pool] = (void *)(CS next_yield[store_pool] + size);
yield_length[store_pool] -= size;
return store_last_get[store_pool];
@@ -273,7 +273,7 @@ int rounded_oldsize = oldsize;
if (rounded_oldsize % alignment != 0)
rounded_oldsize += alignment - (rounded_oldsize % alignment);
-if ((char *)ptr + rounded_oldsize != (char *)(next_yield[store_pool]) ||
+if (CS ptr + rounded_oldsize != CS (next_yield[store_pool]) ||
inc > yield_length[store_pool] + rounded_oldsize - oldsize)
return FALSE;
@@ -295,7 +295,7 @@ DEBUG(D_memory)
#endif /* COMPILE_UTILITY */
if (newsize % alignment != 0) newsize += alignment - (newsize % alignment);
-next_yield[store_pool] = (char *)ptr + newsize;
+next_yield[store_pool] = CS ptr + newsize;
yield_length[store_pool] -= newsize - rounded_oldsize;
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr + oldsize, inc);
return TRUE;
@@ -455,7 +455,7 @@ storeblock *b;
for (b = chainbase[store_pool]; b != NULL; b = b->next)
{
storeblock *bb = b->next;
- if (bb != NULL && (char *)block == (char *)bb + ALIGNED_SIZEOF_STOREBLOCK)
+ if (bb != NULL && CS block == CS bb + ALIGNED_SIZEOF_STOREBLOCK)
{
b->next = bb->next;
pool_malloc -= bb->length + ALIGNED_SIZEOF_STOREBLOCK;
diff --git a/src/src/string.c b/src/src/string.c
index cec59506d..2de595afb 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -42,7 +42,7 @@ int yield = 4;
/* If an optional mask is permitted, check for it. If found, pass back the
offset. */
-if (maskptr != NULL)
+if (maskptr)
{
const uschar *ss = s + Ustrlen(s);
*maskptr = 0;
@@ -79,7 +79,7 @@ if (Ustrchr(s, ':') != NULL)
if we hit the / that introduces a mask or the % that introduces the
interface specifier (scope id) of a link-local address. */
- if (*s == 0 || *s == '%' || *s == '/') return had_double_colon? yield : 0;
+ if (*s == 0 || *s == '%' || *s == '/') return had_double_colon ? yield : 0;
/* If a component starts with an additional colon, we have hit a double
colon. This is permitted to appear once only, and counts as at least
@@ -135,13 +135,16 @@ if (Ustrchr(s, ':') != NULL)
for (i = 0; i < 4; i++)
{
+ long n;
+ uschar * end;
+
if (i != 0 && *s++ != '.') return 0;
- if (!isdigit(*s++)) return 0;
- if (isdigit(*s) && isdigit(*(++s))) s++;
+ n = strtol(CCS s, CSS &end, 10);
+ if (n > 255 || n < 0 || end <= s || end > s+3) return 0;
+ s = end;
}
-return (*s == 0 || (*s == '/' && maskptr != NULL && *maskptr != 0))?
- yield : 0;
+return !*s || (*s == '/' && maskptr && *maskptr != 0) ? yield : 0;
}
#endif /* COMPILE_UTILITY */
@@ -965,21 +968,43 @@ else
*listptr = s;
return buffer;
}
-#endif /* COMPILE_UTILITY */
-#ifndef COMPILE_UTILITY
+static const uschar *
+Ustrnchr(const uschar * s, int c, unsigned * len)
+{
+unsigned siz = *len;
+while (siz)
+ {
+ if (!*s) return NULL;
+ if (*s == c)
+ {
+ *len = siz;
+ return s;
+ }
+ s++;
+ siz--;
+ }
+return NULL;
+}
+
+
/************************************************
* Add element to separated list *
************************************************/
-/* This function is used to build a list, returning
-an allocated null-terminated growable string. The
-given element has any embedded separator characters
+/* This function is used to build a list, returning an allocated null-terminated
+growable string. The given element has any embedded separator characters
doubled.
+Despite having the same growable-string interface as string_cat() the list is
+always returned null-terminated.
+
Arguments:
list points to the start of the list that is being built, or NULL
if this is a new list that has no contents yet
+ sz (ptr to) amount of memory allocated for list; zero for a new list
+ off (ptr to) current list length in chars (insert point for next addition),
+ zero for a new list
sep list separator character
ele new element to be appended to the list
@@ -987,78 +1012,49 @@ Returns: pointer to the start of the list, changed if copied for expansion.
*/
uschar *
-string_append_listele(uschar * list, uschar sep, const uschar * ele)
+string_append_listele(uschar * list, int * sz, int * off,
+ uschar sep, const uschar * ele)
{
-uschar * new = NULL;
-int sz = 0, off = 0;
uschar * sp;
if (list)
- {
- new = string_cat (new, &sz, &off, list);
- new = string_catn(new, &sz, &off, &sep, 1);
- }
+ list = string_catn(list, sz, off, &sep, 1);
while((sp = Ustrchr(ele, sep)))
{
- new = string_catn(new, &sz, &off, ele, sp-ele+1);
- new = string_catn(new, &sz, &off, &sep, 1);
+ list = string_catn(list, sz, off, ele, sp-ele+1);
+ list = string_catn(list, sz, off, &sep, 1);
ele = sp+1;
}
-new = string_cat(new, &sz, &off, ele);
-new[off] = '\0';
-return new;
+list = string_cat(list, sz, off, ele);
+list[*off] = '\0';
+return list;
}
-static const uschar *
-Ustrnchr(const uschar * s, int c, unsigned * len)
-{
-unsigned siz = *len;
-while (siz)
- {
- if (!*s) return NULL;
- if (*s == c)
- {
- *len = siz;
- return s;
- }
- s++;
- siz--;
- }
-return NULL;
-}
-
uschar *
-string_append_listele_n(uschar * list, uschar sep, const uschar * ele,
- unsigned len)
+string_append_listele_n(uschar * list, int * sz, int * off,
+ uschar sep, const uschar * ele, unsigned len)
{
-uschar * new = NULL;
-int sz = 0, off = 0;
const uschar * sp;
if (list)
- {
- new = string_cat (new, &sz, &off, list);
- new = string_catn(new, &sz, &off, &sep, 1);
- }
+ list = string_catn(list, sz, off, &sep, 1);
while((sp = Ustrnchr(ele, sep, &len)))
{
- new = string_catn(new, &sz, &off, ele, sp-ele+1);
- new = string_catn(new, &sz, &off, &sep, 1);
+ list = string_catn(list, sz, off, ele, sp-ele+1);
+ list = string_catn(list, sz, off, &sep, 1);
ele = sp+1;
len--;
}
-new = string_catn(new, &sz, &off, ele, len);
-new[off] = '\0';
-return new;
+list = string_catn(list, sz, off, ele, len);
+list[*off] = '\0';
+return list;
}
-#endif /* COMPILE_UTILITY */
-#ifndef COMPILE_UTILITY
/*************************************************
* Add chars to string *
*************************************************/
@@ -1078,7 +1074,7 @@ Arguments:
characters, updated to the new offset
s points to characters to add
count count of characters to add; must not exceed the length of s, if s
- is a C string. If -1 given, strlen(s) is used.
+ is a C string.
If string is given as NULL, *size and *ptr should both be zero.
@@ -1359,20 +1355,18 @@ while (*fp != 0)
switch(length)
{
case L_SHORT:
- case L_NORMAL: sprintf(CS p, newformat, va_arg(ap, int)); break;
- case L_LONG: sprintf(CS p, newformat, va_arg(ap, long int)); break;
- case L_LONGLONG: sprintf(CS p, newformat, va_arg(ap, LONGLONG_T)); break;
- case L_SIZE: sprintf(CS p, newformat, va_arg(ap, size_t)); break;
+ case L_NORMAL: p += sprintf(CS p, newformat, va_arg(ap, int)); break;
+ case L_LONG: p += sprintf(CS p, newformat, va_arg(ap, long int)); break;
+ case L_LONGLONG: p += sprintf(CS p, newformat, va_arg(ap, LONGLONG_T)); break;
+ case L_SIZE: p += sprintf(CS p, newformat, va_arg(ap, size_t)); break;
}
- while (*p) p++;
break;
case 'p':
if (p >= last - 24) { yield = FALSE; goto END_FORMAT; }
strncpy(newformat, item_start, fp - item_start);
newformat[fp - item_start] = 0;
- sprintf(CS p, newformat, va_arg(ap, void *));
- while (*p) p++;
+ p += sprintf(CS p, newformat, va_arg(ap, void *));
break;
/* %f format is inherently insecure if the numbers that it may be
@@ -1392,10 +1386,9 @@ while (*fp != 0)
strncpy(newformat, item_start, fp - item_start);
newformat[fp-item_start] = 0;
if (length == L_LONGDOUBLE)
- sprintf(CS p, newformat, va_arg(ap, long double));
+ p += sprintf(CS p, newformat, va_arg(ap, long double));
else
- sprintf(CS p, newformat, va_arg(ap, double));
- while (*p) p++;
+ p += sprintf(CS p, newformat, va_arg(ap, double));
break;
/* String types */
diff --git a/src/src/structs.h b/src/src/structs.h
index 38b095f06..d8ac19ab8 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -28,11 +28,12 @@ struct router_info;
/* Structure for remembering macros for the configuration file */
typedef struct macro_item {
- struct macro_item *next;
- BOOL command_line;
- unsigned namelen;
- uschar * replacement;
- uschar name[1];
+ struct macro_item * next;
+ BOOL command_line;
+ unsigned namelen;
+ unsigned replen;
+ const uschar * name;
+ const uschar * replacement;
} macro_item;
/* Structure for bit tables for debugging and logging */
@@ -230,12 +231,15 @@ typedef struct transport_info {
#define tc_chunk_last BIT(1) /* annotate chunk SMTP cmd as LAST */
struct transport_context;
-typedef int (*tpt_chunk_cmd_cb)(int fd, struct transport_context * tctx,
- unsigned len, unsigned flags);
+typedef int (*tpt_chunk_cmd_cb)(struct transport_context *, unsigned, unsigned);
/* Structure for information about a delivery-in-progress */
typedef struct transport_context {
+ union { /* discriminated by option topt_output_string */
+ int fd; /* file descriptor to write message to */
+ uschar * msg; /* allocated string with written message */
+ } u;
transport_instance * tblock; /* transport */
struct address_item * addr;
uschar * check_string; /* string replacement */
@@ -245,6 +249,10 @@ typedef struct transport_context {
/* items below only used with option topt_use_bdat */
tpt_chunk_cmd_cb chunk_cb; /* per-datachunk callback */
void * smtp_context;
+
+ /* items below only used with option topt_output_string */
+ int msg_size;
+ int msg_ptr;
} transport_ctx;
@@ -497,6 +505,7 @@ typedef struct address_item_propagated {
#ifdef EXPERIMENTAL_SRS
uschar *srs_sender; /* Change return path when delivering */
#endif
+ BOOL ignore_error:1; /* ignore delivery error */
#ifdef SUPPORT_I18N
BOOL utf8_msg:1; /* requires SMTPUTF8 processing */
BOOL utf8_downcvt:1; /* mandatory downconvert on delivery */
@@ -504,50 +513,6 @@ typedef struct address_item_propagated {
#endif
} address_item_propagated;
-/* Bits for the flags field below */
-
-#define af_allow_file 0x00000001 /* allow file in generated address */
-#define af_allow_pipe 0x00000002 /* allow pipe in generated address */
-#define af_allow_reply 0x00000004 /* allow autoreply in generated address */
-#define af_dr_retry_exists 0x00000008 /* router retry record exists */
-#define af_expand_pipe 0x00000010 /* expand pipe arguments */
-#define af_file 0x00000020 /* file delivery; always with pfr */
-#define af_gid_set 0x00000040 /* gid field is set */
-#define af_home_expanded 0x00000080 /* home_dir is already expanded */
-#define af_ignore_error 0x00000100 /* ignore delivery error */
-#define af_initgroups 0x00000200 /* use initgroups() for local transporting */
-#define af_local_host_removed 0x00000400 /* local host was backup */
-#define af_lt_retry_exists 0x00000800 /* local transport retry exists */
-#define af_pfr 0x00001000 /* pipe or file or reply delivery */
-#define af_retry_skipped 0x00002000 /* true if retry caused some skipping */
-#define af_retry_timedout 0x00004000 /* true if retry timed out */
-#define af_uid_set 0x00008000 /* uid field is set */
-#define af_hide_child 0x00010000 /* hide child in bounce/defer msgs */
-#define af_sverify_told 0x00020000 /* sender verify failure notified */
-#define af_verify_pmfail 0x00040000 /* verify failure was postmaster callout */
-#define af_verify_nsfail 0x00080000 /* verify failure was null sender callout */
-#define af_homonym 0x00100000 /* an ancestor has same address */
-#define af_verify_routed 0x00200000 /* for cached sender verify: routed OK */
-#define af_verify_callout 0x00400000 /* for cached sender verify: callout was specified */
-#define af_include_affixes 0x00800000 /* delivered with affixes in RCPT */
-#define af_cert_verified 0x01000000 /* delivered with verified TLS cert */
-#define af_pass_message 0x02000000 /* pass message in bounces */
-#define af_bad_reply 0x04000000 /* filter could not generate autoreply */
-#ifndef DISABLE_PRDR
-# define af_prdr_used 0x08000000 /* delivery used SMTP PRDR */
-#endif
-#define af_chunking_used 0x10000000 /* delivery used SMTP CHUNKING */
-#define af_force_command 0x20000000 /* force_command in pipe transport */
-#ifdef EXPERIMENTAL_DANE
-# define af_dane_verified 0x40000000 /* TLS cert verify done with DANE */
-#endif
-#ifdef SUPPORT_I18N
-# define af_utf8_downcvt 0x80000000 /* downconvert was done for delivery */
-#endif
-
-/* These flags must be propagated when a child is created */
-
-#define af_propagate (af_ignore_error)
/* The main address structure. Note that fields that are to be copied to
generated addresses should be put in the address_item_propagated structure (see
@@ -617,12 +582,54 @@ typedef struct address_item {
uid_t uid; /* uid for transporting */
gid_t gid; /* gid for transporting */
- unsigned int flags; /* a row of bits, defined above */
+ /* flags */
+ struct {
+ BOOL af_allow_file:1; /* allow file in generated address */
+ BOOL af_allow_pipe:1; /* allow pipe in generated address */
+ BOOL af_allow_reply:1; /* allow autoreply in generated address */
+ BOOL af_dr_retry_exists:1; /* router retry record exists */
+ BOOL af_expand_pipe:1; /* expand pipe arguments */
+ BOOL af_file:1; /* file delivery; always with pfr */
+ BOOL af_gid_set:1; /* gid field is set */
+ BOOL af_home_expanded:1; /* home_dir is already expanded */
+ BOOL af_initgroups:1; /* use initgroups() for local transporting */
+ BOOL af_local_host_removed:1; /* local host was backup */
+ BOOL af_lt_retry_exists:1; /* local transport retry exists */
+ BOOL af_pfr:1; /* pipe or file or reply delivery */
+ BOOL af_retry_skipped:1; /* true if retry caused some skipping */
+ BOOL af_retry_timedout:1; /* true if retry timed out */
+ BOOL af_uid_set:1; /* uid field is set */
+ BOOL af_hide_child:1; /* hide child in bounce/defer msgs */
+ BOOL af_sverify_told:1; /* sender verify failure notified */
+ BOOL af_verify_pmfail:1; /* verify failure was postmaster callout */
+ BOOL af_verify_nsfail:1; /* verify failure was null sender callout */
+ BOOL af_homonym:1; /* an ancestor has same address */
+ BOOL af_verify_routed:1; /* for cached sender verify: routed OK */
+ BOOL af_verify_callout:1; /* for cached sender verify: callout was specified */
+ BOOL af_include_affixes:1; /* delivered with affixes in RCPT */
+ BOOL af_cert_verified:1; /* delivered with verified TLS cert */
+ BOOL af_pass_message:1; /* pass message in bounces */
+ BOOL af_bad_reply:1; /* filter could not generate autoreply */
+ BOOL af_tcp_fastopen:1; /* delivery used TCP Fast Open */
+#ifndef DISABLE_PRDR
+ BOOL af_prdr_used:1; /* delivery used SMTP PRDR */
+#endif
+ BOOL af_chunking_used:1; /* delivery used SMTP CHUNKING */
+ BOOL af_force_command:1; /* force_command in pipe transport */
+#ifdef EXPERIMENTAL_DANE
+ BOOL af_dane_verified:1; /* TLS cert verify done with DANE */
+#endif
+#ifdef SUPPORT_I18N
+ BOOL af_utf8_downcvt:1; /* downconvert was done for delivery */
+#endif
+ } flags;
+
unsigned int domain_cache[(MAX_NAMED_LIST * 2)/32];
unsigned int localpart_cache[(MAX_NAMED_LIST * 2)/32];
int mode; /* mode for local transporting to a file */
int more_errno; /* additional error information */
/* (may need to hold a timestamp) */
+ unsigned int delivery_usec; /* subsecond part of delivery time */
short int basic_errno; /* status after failure */
unsigned short child_count; /* number of child addresses */
@@ -860,11 +867,13 @@ typedef BOOL (*oicf) (uschar *message_id, void *data);
/* DKIM information for transport */
struct ob_dkim {
uschar *dkim_domain;
+ uschar *dkim_identity;
uschar *dkim_private_key;
uschar *dkim_selector;
uschar *dkim_canon;
uschar *dkim_sign_headers;
uschar *dkim_strict;
+ uschar *dkim_hash;
BOOL dot_stuffed;
};
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 8836bb259..d54c560f7 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -60,6 +60,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
#if GNUTLS_VERSION_NUMBER >= 0x030014
# define SUPPORT_SYSDEFAULT_CABUNDLE
#endif
+#if GNUTLS_VERSION_NUMBER >= 0x030109
+# define SUPPORT_CORK
+#endif
#ifndef DISABLE_OCSP
# include <gnutls/ocsp.h>
@@ -136,16 +139,45 @@ typedef struct exim_gnutls_state {
} exim_gnutls_state_st;
static const exim_gnutls_state_st exim_gnutls_state_init = {
- NULL, NULL, NULL, VERIFY_NONE, -1, -1, FALSE, FALSE, FALSE,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL,
+ .session = NULL,
+ .x509_cred = NULL,
+ .priority_cache = NULL,
+ .verify_requirement = VERIFY_NONE,
+ .fd_in = -1,
+ .fd_out = -1,
+ .peer_cert_verified = FALSE,
+ .trigger_sni_changes =FALSE,
+ .have_set_peerdn = FALSE,
+ .host = NULL,
+ .peercert = NULL,
+ .peerdn = NULL,
+ .ciphersuite = NULL,
+ .received_sni = NULL,
+
+ .tls_certificate = NULL,
+ .tls_privatekey = NULL,
+ .tls_sni = NULL,
+ .tls_verify_certificates = NULL,
+ .tls_crl = NULL,
+ .tls_require_ciphers =NULL,
+
+ .exp_tls_certificate = NULL,
+ .exp_tls_privatekey = NULL,
+ .exp_tls_verify_certificates = NULL,
+ .exp_tls_crl = NULL,
+ .exp_tls_require_ciphers = NULL,
+ .exp_tls_ocsp_file = NULL,
+ .exp_tls_verify_cert_hostnames = NULL,
#ifndef DISABLE_EVENT
- NULL,
+ .event_action = NULL,
#endif
- NULL,
- NULL, 0, 0, 0, 0,
+ .tlsp = NULL,
+
+ .xfer_buffer = NULL,
+ .xfer_buffer_lwm = 0,
+ .xfer_buffer_hwm = 0,
+ .xfer_eof = 0,
+ .xfer_error = 0,
};
/* Not only do we have our own APIs which don't pass around state, assuming
@@ -1648,7 +1680,7 @@ int ret;
if ((ret = gnutls_load_file(ptr, ocsp_response)) < 0)
{
DEBUG(D_tls) debug_printf("Failed to load ocsp stapling file %s\n",
- (char *)ptr);
+ CS ptr);
tls_in.ocsp = OCSP_NOT_RESP;
return GNUTLS_E_NO_CERTIFICATE_STATUS;
}
@@ -1745,7 +1777,7 @@ exim_gnutls_state_st * state = NULL;
if (tls_in.active >= 0)
{
tls_error(US"STARTTLS received after TLS started", "", NULL, errstr);
- smtp_printf("554 Already in TLS\r\n");
+ smtp_printf("554 Already in TLS\r\n", FALSE);
return FAIL;
}
@@ -1806,7 +1838,7 @@ mode, the fflush() happens when smtp_getc() is called. */
if (!state->tlsp->on_connect)
{
- smtp_printf("220 TLS go ahead\r\n");
+ smtp_printf("220 TLS go ahead\r\n", FALSE);
fflush(smtp_out);
}
@@ -1885,6 +1917,7 @@ and initialize appropriately. */
state->xfer_buffer = store_malloc(ssl_xfer_buffer_size);
receive_getc = tls_getc;
+receive_getbuf = tls_getbuf;
receive_get_cache = tls_get_cache;
receive_ungetc = tls_ungetc;
receive_feof = tls_feof;
@@ -2154,6 +2187,75 @@ if ((state_server.session == NULL) && (state_client.session == NULL))
+static BOOL
+tls_refill(unsigned lim)
+{
+exim_gnutls_state_st * state = &state_server;
+ssize_t inbytes;
+
+DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%p, %p, %u)\n",
+ state->session, state->xfer_buffer, ssl_xfer_buffer_size);
+
+if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
+ MIN(ssl_xfer_buffer_size, lim));
+alarm(0);
+
+/* Timeouts do not get this far; see command_timeout_handler().
+ A zero-byte return appears to mean that the TLS session has been
+ closed down, not that the socket itself has been closed down. Revert to
+ non-TLS handling. */
+
+if (sigalrm_seen)
+ {
+ DEBUG(D_tls) debug_printf("Got tls read timeout\n");
+ state->xfer_error = 1;
+ return FALSE;
+ }
+
+else if (inbytes == 0)
+ {
+ DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
+
+ receive_getc = smtp_getc;
+ receive_getbuf = smtp_getbuf;
+ receive_get_cache = smtp_get_cache;
+ receive_ungetc = smtp_ungetc;
+ receive_feof = smtp_feof;
+ receive_ferror = smtp_ferror;
+ receive_smtp_buffered = smtp_buffered;
+
+ gnutls_deinit(state->session);
+ gnutls_certificate_free_credentials(state->x509_cred);
+
+ state->session = NULL;
+ state->tlsp->active = -1;
+ state->tlsp->bits = 0;
+ state->tlsp->certificate_verified = FALSE;
+ tls_channelbinding_b64 = NULL;
+ state->tlsp->cipher = NULL;
+ state->tlsp->peercert = NULL;
+ state->tlsp->peerdn = NULL;
+
+ return FALSE;
+ }
+
+/* Handle genuine errors */
+
+else if (inbytes < 0)
+ {
+ record_io_error(state, (int) inbytes, US"recv", NULL);
+ state->xfer_error = 1;
+ return FALSE;
+ }
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(state->xfer_buffer, inbytes);
+#endif
+state->xfer_buffer_hwm = (int) inbytes;
+state->xfer_buffer_lwm = 0;
+return TRUE;
+}
+
/*************************************************
* TLS version of getc *
*************************************************/
@@ -2171,77 +2273,41 @@ Returns: the next character or EOF
int
tls_getc(unsigned lim)
{
-exim_gnutls_state_st *state = &state_server;
-if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
- {
- ssize_t inbytes;
-
- DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%p, %p, %u)\n",
- state->session, state->xfer_buffer, ssl_xfer_buffer_size);
-
- if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
- inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
- MIN(ssl_xfer_buffer_size, lim));
- alarm(0);
-
- /* Timeouts do not get this far; see command_timeout_handler().
- A zero-byte return appears to mean that the TLS session has been
- closed down, not that the socket itself has been closed down. Revert to
- non-TLS handling. */
-
- if (sigalrm_seen)
- {
- DEBUG(D_tls) debug_printf("Got tls read timeout\n");
- state->xfer_error = 1;
- return EOF;
- }
-
- else if (inbytes == 0)
- {
- DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
-
- receive_getc = smtp_getc;
- receive_get_cache = smtp_get_cache;
- receive_ungetc = smtp_ungetc;
- receive_feof = smtp_feof;
- receive_ferror = smtp_ferror;
- receive_smtp_buffered = smtp_buffered;
+exim_gnutls_state_st * state = &state_server;
- gnutls_deinit(state->session);
- gnutls_certificate_free_credentials(state->x509_cred);
+if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
+ if (!tls_refill(lim))
+ return state->xfer_error ? EOF : smtp_getc(lim);
- state->session = NULL;
- state->tlsp->active = -1;
- state->tlsp->bits = 0;
- state->tlsp->certificate_verified = FALSE;
- tls_channelbinding_b64 = NULL;
- state->tlsp->cipher = NULL;
- state->tlsp->peercert = NULL;
- state->tlsp->peerdn = NULL;
+/* Something in the buffer; return next uschar */
- return smtp_getc(lim);
- }
+return state->xfer_buffer[state->xfer_buffer_lwm++];
+}
- /* Handle genuine errors */
+uschar *
+tls_getbuf(unsigned * len)
+{
+exim_gnutls_state_st * state = &state_server;
+unsigned size;
+uschar * buf;
- else if (inbytes < 0)
+if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
+ if (!tls_refill(*len))
{
- record_io_error(state, (int) inbytes, US"recv", NULL);
- state->xfer_error = 1;
- return EOF;
+ if (!state->xfer_error) return smtp_getbuf(len);
+ *len = 0;
+ return NULL;
}
-#ifndef DISABLE_DKIM
- dkim_exim_verify_feed(state->xfer_buffer, inbytes);
-#endif
- state->xfer_buffer_hwm = (int) inbytes;
- state->xfer_buffer_lwm = 0;
- }
-
-/* Something in the buffer; return next uschar */
-return state->xfer_buffer[state->xfer_buffer_lwm++];
+if ((size = state->xfer_buffer_hwm - state->xfer_buffer_lwm) > *len)
+ size = *len;
+buf = &state->xfer_buffer[state->xfer_buffer_lwm];
+state->xfer_buffer_lwm += size;
+*len = size;
+return buf;
}
+
void
tls_get_cache()
{
@@ -2254,6 +2320,14 @@ if (n > 0)
}
+BOOL
+tls_could_read(void)
+{
+return state_server.xfer_buffer_lwm < state_server.xfer_buffer_hwm
+ || gnutls_record_check_pending(state_server.session) > 0;
+}
+
+
/*************************************************
@@ -2313,19 +2387,27 @@ Arguments:
is_server channel specifier
buff buffer of data
len number of bytes
+ more more data expected soon
Returns: the number of bytes after a successful write,
-1 after a failed write
*/
int
-tls_write(BOOL is_server, const uschar *buff, size_t len)
+tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more)
{
ssize_t outbytes;
size_t left = len;
exim_gnutls_state_st *state = is_server ? &state_server : &state_client;
+#ifdef SUPPORT_CORK
+static BOOL corked = FALSE;
+
+if (more && !corked) gnutls_record_cork(state->session);
+#endif
+
+DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__,
+ buff, left, more ? ", more" : "");
-DEBUG(D_tls) debug_printf("tls_do_write(%p, " SIZE_T_FMT ")\n", buff, left);
while (left > 0)
{
DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %p, " SIZE_T_FMT ")\n",
@@ -2356,6 +2438,14 @@ if (len > INT_MAX)
len = INT_MAX;
}
+#ifdef SUPPORT_CORK
+if (more != corked)
+ {
+ if (!more) (void) gnutls_record_uncork(state->session, 0);
+ corked = more;
+ }
+#endif
+
return (int) len;
}
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 4a41ba192..c0ed6f992 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -69,6 +69,7 @@ functions from the OpenSSL library. */
#ifndef LIBRESSL_VERSION_NUMBER
# if OPENSSL_VERSION_NUMBER >= 0x010100000L
# define EXIM_HAVE_OPENSSL_CHECKHOST
+# define EXIM_HAVE_OPENSSL_DH_BITS
# endif
# if OPENSSL_VERSION_NUMBER >= 0x010000000L \
&& (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
@@ -383,11 +384,13 @@ dn[sizeof(dn)-1] = '\0';
if (preverify_ok == 0)
{
- log_write(0, LOG_MAIN, "[%s] SSL verify error: depth=%d error=%s cert=%s",
- tlsp == &tls_out ? deliver_host_address : sender_host_address,
- depth,
- X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)),
- dn);
+ uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])",
+ *verify_mode, sender_host_address)
+ : US"";
+ log_write(0, LOG_MAIN, "[%s] SSL verify error%s: depth=%d error=%s cert=%s",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ extra, depth,
+ X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)), dn);
*calledp = TRUE;
if (!*optionalp)
{
@@ -448,7 +451,7 @@ else
if (rc < 0)
{
log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
- deliver_host_address);
+ tlsp == &tls_out ? deliver_host_address : sender_host_address);
name = NULL;
}
break;
@@ -458,10 +461,14 @@ else
if (!tls_is_name_for_cert(verify_cert_hostnames, cert))
#endif
{
+ uschar * extra = verify_mode
+ ? string_sprintf(" (during %c-verify for [%s])",
+ *verify_mode, sender_host_address)
+ : US"";
log_write(0, LOG_MAIN,
- "[%s] SSL verify error: certificate name mismatch: "
- "DN=\"%s\" H=\"%s\"",
- deliver_host_address, dn, verify_cert_hostnames);
+ "[%s] SSL verify error%s: certificate name mismatch: DN=\"%s\" H=\"%s\"",
+ tlsp == &tls_out ? deliver_host_address : sender_host_address,
+ extra, dn, verify_cert_hostnames);
*calledp = TRUE;
if (!*optionalp)
{
@@ -595,6 +602,7 @@ BIO *bio;
DH *dh;
uschar *dhexpanded;
const char *pem;
+int dh_bitsize;
if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
return FALSE;
@@ -635,21 +643,34 @@ if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)))
return FALSE;
}
+/* note: our default limit of 2236 is not a multiple of 8; the limit comes from
+ * an NSS limit, and the GnuTLS APIs handle bit-sizes fine, so we went with
+ * 2236. But older OpenSSL can only report in bytes (octets), not bits.
+ * If someone wants to dance at the edge, then they can raise the limit or use
+ * current libraries. */
+#ifdef EXIM_HAVE_OPENSSL_DH_BITS
+/* Added in commit 26c79d5641d; `git describe --contains` says OpenSSL_1_1_0-pre1~1022
+ * This predates OpenSSL_1_1_0 (before a, b, ...) so is in all 1.1.0 */
+dh_bitsize = DH_bits(dh);
+#else
+dh_bitsize = 8 * DH_size(dh);
+#endif
+
/* Even if it is larger, we silently return success rather than cause things
* to fail out, so that a too-large DH will not knock out all TLS; it's a
* debatable choice. */
-if ((8*DH_size(dh)) > tls_dh_max_bits)
+if (dh_bitsize > tls_dh_max_bits)
{
DEBUG(D_tls)
- debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d",
- 8*DH_size(dh), tls_dh_max_bits);
+ debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d\n",
+ dh_bitsize, tls_dh_max_bits);
}
else
{
SSL_CTX_set_tmp_dh(sctx, dh);
DEBUG(D_tls)
debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
- dhexpanded ? dhexpanded : US"default", 8*DH_size(dh));
+ dhexpanded ? dhexpanded : US"default", dh_bitsize);
}
DH_free(dh);
@@ -727,7 +748,7 @@ if (Ustrcmp(exp_curve, "auto") == 0)
#if OPENSSL_VERSION_NUMBER < 0x10002000L
DEBUG(D_tls) debug_printf(
"ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
- exp_curve = "prime256v1";
+ exp_curve = US"prime256v1";
#else
# if defined SSL_CTRL_SET_ECDH_AUTO
DEBUG(D_tls) debug_printf(
@@ -1418,9 +1439,9 @@ tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
#endif
address_item *addr, tls_ext_ctx_cb ** cbp, uschar ** errstr)
{
+SSL_CTX * ctx;
long init_options;
int rc;
-BOOL okay;
tls_ext_ctx_cb * cbinfo;
cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
@@ -1461,9 +1482,8 @@ when OpenSSL is built without SSLv2 support.
By disabling with openssl_options, we can let admins re-enable with the
existing knob. */
-*ctxp = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method());
-
-if (!*ctxp) return tls_error(US"SSL_CTX_new", host, NULL, errstr);
+if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())))
+ return tls_error(US"SSL_CTX_new", host, NULL, errstr);
/* It turns out that we need to seed the random number generator this early in
order to get the full complement of ciphers to work. It took me roughly a day
@@ -1479,9 +1499,9 @@ if (!RAND_status())
gettimeofday(&r.tv, NULL);
r.p = getpid();
- RAND_seed((uschar *)(&r), sizeof(r));
- RAND_seed((uschar *)big_buffer, big_buffer_size);
- if (addr != NULL) RAND_seed((uschar *)addr, sizeof(addr));
+ RAND_seed(US (&r), sizeof(r));
+ RAND_seed(US big_buffer, big_buffer_size);
+ if (addr != NULL) RAND_seed(US addr, sizeof(addr));
if (!RAND_status())
return tls_error(US"RAND_status", host,
@@ -1491,10 +1511,10 @@ if (!RAND_status())
/* Set up the information callback, which outputs if debugging is at a suitable
level. */
-DEBUG(D_tls) SSL_CTX_set_info_callback(*ctxp, (void (*)())info_callback);
+DEBUG(D_tls) SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
/* Automatically re-try reads/writes after renegotiation. */
-(void) SSL_CTX_set_mode(*ctxp, SSL_MODE_AUTO_RETRY);
+(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
/* Apply administrator-supplied work-arounds.
Historically we applied just one requested option,
@@ -1505,31 +1525,34 @@ grandfathered in the first one as the default value for "openssl_options".
No OpenSSL version number checks: the options we accept depend upon the
availability of the option value macros from OpenSSL. */
-okay = tls_openssl_options_parse(openssl_options, &init_options);
-if (!okay)
+if (!tls_openssl_options_parse(openssl_options, &init_options))
return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
if (init_options)
{
DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
- if (!(SSL_CTX_set_options(*ctxp, init_options)))
+ if (!(SSL_CTX_set_options(ctx, init_options)))
return tls_error(string_sprintf(
"SSL_CTX_set_option(%#lx)", init_options), host, NULL, errstr);
}
else
DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
+/* Disable session cache unconditionally */
+
+(void) SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+
/* Initialize with DH parameters if supplied */
/* Initialize ECDH temp key parameter selection */
-if ( !init_dh(*ctxp, dhparam, host, errstr)
- || !init_ecdh(*ctxp, host, errstr)
+if ( !init_dh(ctx, dhparam, host, errstr)
+ || !init_ecdh(ctx, host, errstr)
)
return DEFER;
/* Set up certificate and key (and perhaps OCSP info) */
-if ((rc = tls_expand_session_files(*ctxp, cbinfo, errstr)) != OK)
+if ((rc = tls_expand_session_files(ctx, cbinfo, errstr)) != OK)
return rc;
/* If we need to handle SNI or OCSP, do so */
@@ -1552,14 +1575,14 @@ if (host == NULL) /* server */
callback is invoked. */
if (cbinfo->u_ocsp.server.file)
{
- SSL_CTX_set_tlsext_status_cb(server_ctx, tls_server_stapling_cb);
- SSL_CTX_set_tlsext_status_arg(server_ctx, cbinfo);
+ SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
+ SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
}
# endif
/* We always do this, so that $tls_sni is available even if not used in
tls_certificate */
- SSL_CTX_set_tlsext_servername_callback(*ctxp, tls_servername_cb);
- SSL_CTX_set_tlsext_servername_arg(*ctxp, cbinfo);
+ SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
+ SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
}
# ifndef DISABLE_OCSP
else /* client */
@@ -1570,8 +1593,8 @@ else /* client */
DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
return FAIL;
}
- SSL_CTX_set_tlsext_status_cb(*ctxp, tls_client_stapling_cb);
- SSL_CTX_set_tlsext_status_arg(*ctxp, cbinfo);
+ SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
+ SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
}
# endif
#endif
@@ -1580,15 +1603,16 @@ cbinfo->verify_cert_hostnames = NULL;
#ifdef EXIM_HAVE_EPHEM_RSA_KEX
/* Set up the RSA callback */
-SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
+SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
#endif
/* Finally, set the timeout, and we are done */
-SSL_CTX_set_timeout(*ctxp, ssl_session_timeout);
+SSL_CTX_set_timeout(ctx, ssl_session_timeout);
DEBUG(D_tls) debug_printf("Initialized TLS\n");
*cbp = cbinfo;
+*ctxp = ctx;
return OK;
}
@@ -1699,6 +1723,7 @@ uschar *expcerts, *expcrl;
if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr))
return DEFER;
+DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
if (expcerts && *expcerts)
{
@@ -1871,7 +1896,7 @@ static uschar cipherbuf[256];
if (tls_in.active >= 0)
{
tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr);
- smtp_printf("554 Already in TLS\r\n");
+ smtp_printf("554 Already in TLS\r\n", FALSE);
return FAIL;
}
@@ -1955,7 +1980,7 @@ mode, the fflush() happens when smtp_getc() is called. */
SSL_set_session_id_context(server_ssl, sid_ctx, Ustrlen(sid_ctx));
if (!tls_in.on_connect)
{
- smtp_printf("220 TLS go ahead\r\n");
+ smtp_printf("220 TLS go ahead\r\n", FALSE);
fflush(smtp_out);
}
@@ -2012,6 +2037,7 @@ ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
ssl_xfer_eof = ssl_xfer_error = 0;
receive_getc = tls_getc;
+receive_getbuf = tls_getbuf;
receive_get_cache = tls_get_cache;
receive_ungetc = tls_ungetc;
receive_feof = tls_feof;
@@ -2348,6 +2374,74 @@ return OK;
+static BOOL
+tls_refill(unsigned lim)
+{
+int error;
+int inbytes;
+
+DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
+ ssl_xfer_buffer, ssl_xfer_buffer_size);
+
+if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
+ MIN(ssl_xfer_buffer_size, lim));
+error = SSL_get_error(server_ssl, inbytes);
+alarm(0);
+
+/* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been
+closed down, not that the socket itself has been closed down. Revert to
+non-SSL handling. */
+
+if (error == SSL_ERROR_ZERO_RETURN)
+ {
+ DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
+
+ receive_getc = smtp_getc;
+ receive_getbuf = smtp_getbuf;
+ receive_get_cache = smtp_get_cache;
+ receive_ungetc = smtp_ungetc;
+ receive_feof = smtp_feof;
+ receive_ferror = smtp_ferror;
+ receive_smtp_buffered = smtp_buffered;
+
+ SSL_free(server_ssl);
+ server_ssl = NULL;
+ tls_in.active = -1;
+ tls_in.bits = 0;
+ tls_in.cipher = NULL;
+ tls_in.peerdn = NULL;
+ tls_in.sni = NULL;
+
+ return FALSE;
+ }
+
+/* Handle genuine errors */
+
+else if (error == SSL_ERROR_SSL)
+ {
+ ERR_error_string(ERR_get_error(), ssl_errstring);
+ log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
+ ssl_xfer_error = 1;
+ return FALSE;
+ }
+
+else if (error != SSL_ERROR_NONE)
+ {
+ DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
+ ssl_xfer_error = 1;
+ return FALSE;
+ }
+
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
+#endif
+ssl_xfer_buffer_hwm = inbytes;
+ssl_xfer_buffer_lwm = 0;
+return TRUE;
+}
+
+
/*************************************************
* TLS version of getc *
*************************************************/
@@ -2365,74 +2459,37 @@ int
tls_getc(unsigned lim)
{
if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
- {
- int error;
- int inbytes;
-
- DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
- ssl_xfer_buffer, ssl_xfer_buffer_size);
-
- if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
- inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
- MIN(ssl_xfer_buffer_size, lim));
- error = SSL_get_error(server_ssl, inbytes);
- alarm(0);
+ if (!tls_refill(lim))
+ return ssl_xfer_error ? EOF : smtp_getc(lim);
- /* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been
- closed down, not that the socket itself has been closed down. Revert to
- non-SSL handling. */
-
- if (error == SSL_ERROR_ZERO_RETURN)
- {
- DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
-
- receive_getc = smtp_getc;
- receive_get_cache = smtp_get_cache;
- receive_ungetc = smtp_ungetc;
- receive_feof = smtp_feof;
- receive_ferror = smtp_ferror;
- receive_smtp_buffered = smtp_buffered;
-
- SSL_free(server_ssl);
- server_ssl = NULL;
- tls_in.active = -1;
- tls_in.bits = 0;
- tls_in.cipher = NULL;
- tls_in.peerdn = NULL;
- tls_in.sni = NULL;
-
- return smtp_getc(lim);
- }
+/* Something in the buffer; return next uschar */
- /* Handle genuine errors */
+return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+}
- else if (error == SSL_ERROR_SSL)
- {
- ERR_error_string(ERR_get_error(), ssl_errstring);
- log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
- ssl_xfer_error = 1;
- return EOF;
- }
+uschar *
+tls_getbuf(unsigned * len)
+{
+unsigned size;
+uschar * buf;
- else if (error != SSL_ERROR_NONE)
+if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
+ if (!tls_refill(*len))
{
- DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
- ssl_xfer_error = 1;
- return EOF;
+ if (!ssl_xfer_error) return smtp_getbuf(len);
+ *len = 0;
+ return NULL;
}
-#ifndef DISABLE_DKIM
- dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
-#endif
- ssl_xfer_buffer_hwm = inbytes;
- ssl_xfer_buffer_lwm = 0;
- }
-
-/* Something in the buffer; return next uschar */
-
-return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+if ((size = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm) > *len)
+ size = *len;
+buf = &ssl_xfer_buffer[ssl_xfer_buffer_lwm];
+ssl_xfer_buffer_lwm += size;
+*len = size;
+return buf;
}
+
void
tls_get_cache()
{
@@ -2444,6 +2501,12 @@ if (n > 0)
}
+BOOL
+tls_could_read(void)
+{
+return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm || SSL_pending(server_ssl) > 0;
+}
+
/*************************************************
* Read bytes from TLS channel *
@@ -2497,6 +2560,7 @@ Arguments:
is_server channel specifier
buff buffer of data
len number of bytes
+ more further data expected soon
Returns: the number of bytes after a successful write,
-1 after a failed write
@@ -2505,15 +2569,32 @@ Used by both server-side and client-side TLS.
*/
int
-tls_write(BOOL is_server, const uschar *buff, size_t len)
+tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more)
{
-int outbytes;
-int error;
-int left = len;
+int outbytes, error, left;
SSL *ssl = is_server ? server_ssl : client_ssl;
+static uschar * corked = NULL;
+static int c_size = 0, c_len = 0;
+
+DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
+ buff, (unsigned long)len, more ? ", more" : "");
+
+/* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when
+"more" is notified. This hack is only ok if small amounts are involved AND only
+one stream does it, in one context (i.e. no store reset). Currently it is used
+for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */
+
+if (is_server && (more || corked))
+ {
+ corked = string_catn(corked, &c_size, &c_len, buff, len);
+ if (more)
+ return len;
+ buff = CUS corked;
+ len = c_len;
+ corked = NULL; c_size = c_len = 0;
+ }
-DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left);
-while (left > 0)
+for (left = len; left > 0;)
{
DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left);
outbytes = SSL_write(ssl, CS buff, left);
@@ -2738,7 +2819,7 @@ if (!RAND_status())
gettimeofday(&r.tv, NULL);
r.p = getpid();
- RAND_seed((uschar *)(&r), sizeof(r));
+ RAND_seed(US (&r), sizeof(r));
}
/* We're after pseudo-random, not random; if we still don't have enough data
in the internal PRNG then our options are limited. We could sleep and hope
@@ -2950,7 +3031,7 @@ uschar *s, *end;
uschar keep_c;
BOOL adding, item_parsed;
-result = 0L;
+result = SSL_OP_NO_TICKET;
/* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
* from default because it increases BEAST susceptibility. */
#ifdef SSL_OP_NO_SSLv2
@@ -2960,7 +3041,7 @@ result |= SSL_OP_NO_SSLv2;
result |= SSL_OP_SINGLE_DH_USE;
#endif
-if (option_spec == NULL)
+if (!option_spec)
{
*results = result;
return TRUE;
diff --git a/src/src/tls.c b/src/src/tls.c
index a5cb35bd9..c93eb4579 100644
--- a/src/src/tls.c
+++ b/src/src/tls.c
@@ -264,6 +264,7 @@ uschar * ele;
uschar * match = NULL;
int len;
uschar * list = NULL;
+int size = 0, pos = 0;
while ((ele = string_nextinlist(&mod, &insep, NULL, 0)))
if (ele[0] != '>')
@@ -278,7 +279,7 @@ while ((ele = string_nextinlist(CUSS &dn, &insep, NULL, 0)))
if ( !match
|| Ustrncmp(ele, match, len) == 0 && ele[len] == '='
)
- list = string_append_listele(list, outsep, ele+len+1);
+ list = string_append_listele(list, &size, &pos, outsep, ele+len+1);
return list;
}
diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c
index 296398ae9..65d01214a 100644
--- a/src/src/tlscert-gnu.c
+++ b/src/src/tlscert-gnu.c
@@ -182,8 +182,8 @@ if ((ret = gnutls_x509_crt_get_serial((gnutls_x509_crt_t)cert,
bin, &sz)))
return g_err("gs0", __FUNCTION__, ret);
-for(dp = txt, sp = bin; sz; dp += 2, sp++, sz--)
- sprintf(CS dp, "%.2x", *sp);
+for(dp = txt, sp = bin; sz; sz--)
+ dp += sprintf(CS dp, "%.2x", *sp++);
for(sp = txt; sp[0]=='0' && sp[1]; ) sp++; /* leading zeroes */
return string_copy(sp);
}
@@ -205,8 +205,8 @@ cp1 = store_get(len*4+1);
if (gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, CS cp1, &len) != 0)
return g_err("gs1", __FUNCTION__, ret);
-for(cp3 = cp2 = cp1+len; cp1 < cp2; cp3 += 3, cp1++)
- sprintf(CS cp3, "%.2x ", *cp1);
+for(cp3 = cp2 = cp1+len; cp1 < cp2; cp1++)
+ cp3 += sprintf(CS cp3, "%.2x ", *cp1);
cp3[-1]= '\0';
return cp2;
@@ -269,8 +269,8 @@ if (ret < 0)
/* binary data, DER encoded */
/* just dump for now */
-for(cp3 = cp2 = cp1+siz; cp1 < cp2; cp3 += 3, cp1++)
- sprintf(CS cp3, "%.2x ", *cp1);
+for(cp3 = cp2 = cp1+siz; cp1 < cp2; cp1++)
+ cp3 += sprintf(CS cp3, "%.2x ", *cp1);
cp3[-1]= '\0';
return cp2;
@@ -280,6 +280,7 @@ uschar *
tls_cert_subject_altname(void * cert, uschar * mod)
{
uschar * list = NULL;
+int lsize = 0, llen = 0;
int index;
size_t siz;
int ret;
@@ -332,7 +333,7 @@ for(index = 0;; index++)
case GNUTLS_SAN_RFC822NAME: tag = US"MAIL"; break;
default: continue; /* ignore unrecognised types */
}
- list = string_append_listele(list, sep,
+ list = string_append_listele(list, &lsize, &llen, sep,
match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
}
/*NOTREACHED*/
@@ -347,6 +348,7 @@ int ret;
uschar sep = '\n';
int index;
uschar * list = NULL;
+int lsize = 0, llen = 0;
if (mod)
if (*mod == '>' && *++mod) sep = *mod++;
@@ -361,8 +363,8 @@ for(index = 0;; index++)
if (ret < 0)
return g_err("gai", __FUNCTION__, ret);
- list = string_append_listele(list, sep,
- string_copyn(uri.data, uri.size));
+ list = string_append_listele_n(list, &lsize, &llen, sep,
+ uri.data, uri.size);
}
/*NOTREACHED*/
@@ -384,6 +386,7 @@ size_t siz;
uschar sep = '\n';
int index;
uschar * list = NULL;
+int lsize = 0, llen = 0;
uschar * ele;
if (mod)
@@ -403,13 +406,12 @@ for(index = 0;; index++)
return g_err("gc0", __FUNCTION__, ret);
}
- ele = store_get(siz+1);
+ ele = store_get(siz);
if ((ret = gnutls_x509_crt_get_crl_dist_points(
(gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0)
return g_err("gc1", __FUNCTION__, ret);
- ele[siz] = '\0';
- list = string_append_listele(list, sep, ele);
+ list = string_append_listele_n(list, &lsize, &llen, sep, ele, siz);
}
/*NOTREACHED*/
}
@@ -457,8 +459,8 @@ cp = store_get(siz*3+1);
if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0)
return g_err("gf1", __FUNCTION__, ret);
-for (cp3 = cp2 = cp+siz; cp < cp2; cp++, cp3+=2)
- sprintf(CS cp3, "%02X",*cp);
+for (cp3 = cp2 = cp+siz; cp < cp2; cp++)
+ cp3 += sprintf(CS cp3, "%02X", *cp);
return cp2;
}
diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c
index 690f95081..87623a879 100644
--- a/src/src/tlscert-openssl.c
+++ b/src/src/tlscert-openssl.c
@@ -331,8 +331,7 @@ cp3 = cp2 = store_get(len*3+1);
while(len)
{
- sprintf(CS cp2, "%.2x ", *cp1++);
- cp2 += 3;
+ cp2 += sprintf(CS cp2, "%.2x ", *cp1++);
len--;
}
cp2[-1] = '\0';
@@ -344,6 +343,7 @@ uschar *
tls_cert_subject_altname(void * cert, uschar * mod)
{
uschar * list = NULL;
+int lsize = 0, llen = 0;
STACK_OF(GENERAL_NAME) * san = (STACK_OF(GENERAL_NAME) *)
X509_get_ext_d2i((X509 *)cert, NID_subject_alt_name, NULL, NULL);
uschar osep = '\n';
@@ -394,7 +394,7 @@ while (sk_GENERAL_NAME_num(san) > 0)
ele = string_copyn(ele, len);
if (Ustrlen(ele) == len) /* ignore any with embedded nul */
- list = string_append_listele(list, osep,
+ list = string_append_listele(list, &lsize, &llen, osep,
match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
}
@@ -411,6 +411,7 @@ int adsnum = sk_ACCESS_DESCRIPTION_num(ads);
int i;
uschar sep = '\n';
uschar * list = NULL;
+int size = 0, len = 0;
if (mod)
if (*mod == '>' && *++mod) sep = *mod++;
@@ -420,11 +421,9 @@ for (i = 0; i < adsnum; i++)
ACCESS_DESCRIPTION * ad = sk_ACCESS_DESCRIPTION_value(ads, i);
if (ad && OBJ_obj2nid(ad->method) == NID_ad_OCSP)
- {
- uschar * ele = ASN1_STRING_data(ad->location->d.ia5);
- int len = ASN1_STRING_length(ad->location->d.ia5);
- list = string_append_listele_n(list, sep, ele, len);
- }
+ list = string_append_listele_n(list, &size, &len, sep,
+ ASN1_STRING_data(ad->location->d.ia5),
+ ASN1_STRING_length(ad->location->d.ia5));
}
sk_ACCESS_DESCRIPTION_free(ads);
return list;
@@ -441,6 +440,7 @@ int dpsnum = sk_DIST_POINT_num(dps);
int i;
uschar sep = '\n';
uschar * list = NULL;
+int size = 0, len = 0;
if (mod)
if (*mod == '>' && *++mod) sep = *mod++;
@@ -457,11 +457,9 @@ if (dps) for (i = 0; i < dpsnum; i++)
if ( (np = sk_GENERAL_NAME_value(names, j))
&& np->type == GEN_URI
)
- {
- uschar * ele = ASN1_STRING_data(np->d.uniformResourceIdentifier);
- int len = ASN1_STRING_length(np->d.uniformResourceIdentifier);
- list = string_append_listele_n(list, sep, ele, len);
- }
+ list = string_append_listele_n(list, &size, &len, sep,
+ ASN1_STRING_data(np->d.uniformResourceIdentifier),
+ ASN1_STRING_length(np->d.uniformResourceIdentifier));
}
sk_DIST_POINT_free(dps);
return list;
diff --git a/src/src/tod.c b/src/src/tod.c
index 5f451ba96..76b6d2da9 100644
--- a/src/src/tod.c
+++ b/src/src/tod.c
@@ -13,7 +13,7 @@
/* #define TESTING_LOG_DATESTAMP */
-static uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss +zzzz")];
+static uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss.ddd +zzzz")];
/*************************************************
@@ -52,159 +52,173 @@ Returns: pointer to fixed buffer containing the timestamp
uschar *
tod_stamp(int type)
{
-time_t now;
-struct tm *t;
+struct timeval now;
+struct tm * t;
+int off = 0;
-if (type == tod_epoch_l)
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- /* Unix epoch/usec format */
- (void) sprintf(CS timebuf, TIME_T_FMT "%06ld", tv.tv_sec, (long) tv.tv_usec );
- return timebuf;
- }
-
-now = time(NULL);
-
-/* Vary log type according to timezone requirement */
-
-if (type == tod_log) type = log_timezone? tod_log_zone : tod_log_bare;
+gettimeofday(&now, NULL);
/* Styles that don't need local time */
-else if (type == tod_epoch)
+switch(type)
{
- (void) sprintf(CS timebuf, TIME_T_FMT, now); /* Unix epoch format */
- return timebuf; /* NB the above will be wrong if time_t is FP */
+ case tod_epoch:
+ (void) sprintf(CS timebuf, TIME_T_FMT, now.tv_sec); /* Unix epoch format */
+ return timebuf; /* NB the above will be wrong if time_t is FP */
+
+ case tod_epoch_l:
+ /* Unix epoch/usec format */
+ (void) sprintf(CS timebuf, TIME_T_FMT "%06ld", now.tv_sec, (long) now.tv_usec );
+ return timebuf;
+
+ case tod_zulu:
+ t = gmtime(&now.tv_sec);
+ (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ",
+ 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min,
+ t->tm_sec);
+ return timebuf;
}
-else if (type == tod_zulu)
- {
- t = gmtime(&now);
- (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ",
- 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min,
- t->tm_sec);
- return timebuf;
- }
+/* Vary log type according to timezone requirement */
+
+if (type == tod_log) type = log_timezone ? tod_log_zone : tod_log_bare;
/* Convert to local time or UTC */
-t = timestamps_utc? gmtime(&now) : localtime(&now);
+t = timestamps_utc ? gmtime(&now.tv_sec) : localtime(&now.tv_sec);
switch(type)
{
case tod_log_bare: /* Format used in logging without timezone */
- (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d",
- 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,
- t->tm_hour, t->tm_min, t->tm_sec);
- break;
+ off = sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d",
+ 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,
+ t->tm_hour, t->tm_min, t->tm_sec);
+ break;
- /* Format used as suffix of log file name when 'log_datestamp' is active. For
- testing purposes, it changes the file every second. */
+ /* Format used as suffix of log file name when 'log_datestamp' is active. For
+ testing purposes, it changes the file every second. */
- #ifdef TESTING_LOG_DATESTAMP
+#ifdef TESTING_LOG_DATESTAMP
case tod_log_datestamp_daily:
case tod_log_datestamp_monthly:
- (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
- 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
- break;
+ off = sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
+ 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
+ break;
- #else
+#else
case tod_log_datestamp_daily:
- (void) sprintf(CS timebuf, "%04d%02d%02d",
- 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
- break;
+ off = sprintf(CS timebuf, "%04d%02d%02d",
+ 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
+ break;
case tod_log_datestamp_monthly:
- (void) sprintf(CS timebuf, "%04d%02d",
- 1900 + t->tm_year, 1 + t->tm_mon);
- break;
- #endif
-
- /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
- ("UUCP Mail Interchange Format Standard") but only by example, not by
- explicit definition. The examples show no timezone offsets, and some MUAs
- appear to be sensitive to this, so Exim has been changed to remove the
- timezone offsets that originally appeared. */
+#ifndef COMPILE_UTILITY
+ off = sprintf(CS timebuf, "%04d%02d",
+ 1900 + t->tm_year, 1 + t->tm_mon);
+#endif
+ break;
+#endif
+
+ /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
+ ("UUCP Mail Interchange Format Standard") but only by example, not by
+ explicit definition. The examples show no timezone offsets, and some MUAs
+ appear to be sensitive to this, so Exim has been changed to remove the
+ timezone offsets that originally appeared. */
case tod_bsdin:
- {
- int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t);
- Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t);
- }
- break;
-
- /* Other types require the GMT offset to be calculated, or just set up in the
- case of UTC timestamping. We need to take a copy of the local time first. */
-
- default:
- {
- int diff_hour, diff_min;
- struct tm local;
- memcpy(&local, t, sizeof(struct tm));
-
- if (timestamps_utc)
{
- diff_hour = diff_min = 0;
- }
- else
- {
- struct tm *gmt = gmtime(&now);
- diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
- if (local.tm_year != gmt->tm_year)
- diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
- else if (local.tm_yday != gmt->tm_yday)
- diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
- diff_hour = diff_min/60;
- diff_min = abs(diff_min - diff_hour*60);
+ int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t);
+ Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t);
}
+ break;
+
+ /* Other types require the GMT offset to be calculated, or just set up in the
+ case of UTC timestamping. We need to take a copy of the local time first. */
- switch(type)
+ default:
{
- case tod_log_zone: /* Format used in logging with timezone */
- (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d",
- 1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
- local.tm_hour, local.tm_min, local.tm_sec,
- diff_hour, diff_min);
- break;
-
- case tod_zone: /* Just the timezone offset */
- (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min);
- break;
-
- /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */
-
- #ifdef SUPPORT_MBX
- case tod_mbx:
- {
- int len;
- (void) sprintf(CS timebuf, "%02d-", local.tm_mday);
- len = Ustrlen(timebuf);
- len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S",
- &local);
- (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
- }
- break;
- #endif
-
- /* tod_full: format used in Received: headers (use as default just in case
- called with a junk type value) */
-
- default:
- {
- int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local);
- (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
- len += Ustrlen(timebuf + len);
- len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S",
- &local);
- (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
- }
- break;
+ int diff_hour, diff_min;
+ struct tm local;
+ memcpy(&local, t, sizeof(struct tm));
+
+ if (timestamps_utc)
+ diff_hour = diff_min = 0;
+ else
+ {
+ struct tm * gmt = gmtime(&now.tv_sec);
+
+ diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
+ if (local.tm_year != gmt->tm_year)
+ diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
+ else if (local.tm_yday != gmt->tm_yday)
+ diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
+ diff_hour = diff_min/60;
+ diff_min = abs(diff_min - diff_hour*60);
+ }
+
+ switch(type)
+ {
+ case tod_log_zone: /* Format used in logging with timezone */
+#ifndef COMPILE_UTILITY
+ if (LOGGING(millisec))
+ (void) sprintf(CS timebuf,
+ "%04d-%02d-%02d %02d:%02d:%02d.%03d %+03d%02d",
+ 1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
+ local.tm_hour, local.tm_min, local.tm_sec, (int)(now.tv_usec/1000),
+ diff_hour, diff_min);
+ else
+#endif
+ (void) sprintf(CS timebuf,
+ "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d",
+ 1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
+ local.tm_hour, local.tm_min, local.tm_sec,
+ diff_hour, diff_min);
+ break;
+
+ case tod_zone: /* Just the timezone offset */
+ (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min);
+ break;
+
+ /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */
+
+ #ifdef SUPPORT_MBX
+ case tod_mbx:
+ {
+ int len;
+ (void) sprintf(CS timebuf, "%02d-", local.tm_mday);
+ len = Ustrlen(timebuf);
+ len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S",
+ &local);
+ (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
+ }
+ break;
+ #endif
+
+ /* tod_full: format used in Received: headers (use as default just in case
+ called with a junk type value) */
+
+ default:
+ {
+ int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local);
+ (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
+ len += Ustrlen(timebuf + len);
+ len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S",
+ &local);
+ (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
+ }
+ break;
+ }
}
- }
- break;
+ break;
}
+#ifndef COMPILE_UTILITY
+if (LOGGING(millisec) && off > 0)
+ (void) sprintf(CS timebuf + off, ".%03d", (int)(now.tv_usec/1000));
+#else
+off = off; /* Compiler quietening */
+#endif
+
return timebuf;
}
diff --git a/src/src/transport.c b/src/src/transport.c
index aca33762b..5d4102ef8 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -11,35 +11,13 @@ transports. */
#include "exim.h"
-#ifdef HAVE_LINUX_SENDFILE
-#include <sys/sendfile.h>
-#endif
-
-/* Structure for keeping list of addresses that have been added to
-Envelope-To:, in order to avoid duplication. */
-
-struct aci {
- struct aci *next;
- address_item *ptr;
- };
-
-
-/* Static data for write_chunk() */
-
-static uschar *chunk_ptr; /* chunk pointer */
-static uschar *nl_check; /* string to look for at line start */
-static int nl_check_length; /* length of same */
-static uschar *nl_escape; /* string to insert */
-static int nl_escape_length; /* length of same */
-static int nl_partial_match; /* length matched at chunk end */
-
-
/* Generic options for transports, all of which live inside transport_instance
data blocks and which therefore have the opt_public flag set. Note that there
are other options living inside this structure which can be set only from
certain transports. */
optionlist optionlist_transports[] = {
+ /* name type value */
{ "*expand_group", opt_stringptr|opt_hidden|opt_public,
(void *)offsetof(transport_instance, expand_gid) },
{ "*expand_user", opt_stringptr|opt_hidden|opt_public,
@@ -110,21 +88,47 @@ optionlist optionlist_transports[] = {
int optionlist_transports_size = nelem(optionlist_transports);
+#ifdef MACRO_PREDEF
+
+# include "macro_predef.h"
void
-readconf_options_transports(void)
+options_transports(void)
{
struct transport_info * ti;
+uschar buf[64];
-readconf_options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);
+options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);
for (ti = transports_available; ti->driver_name[0]; ti++)
{
- macro_create(string_sprintf("_DRIVER_TRANSPORT_%T", ti->driver_name), US"y", FALSE, TRUE);
- readconf_options_from_list(ti->options, (unsigned)*ti->options_count, US"TRANSPORT", ti->driver_name);
+ spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", ti->driver_name);
+ builtin_macro_create(buf);
+ options_from_list(ti->options, (unsigned)*ti->options_count, US"TRANSPORT", ti->driver_name);
}
}
+#else /*!MACRO_PREDEF*/
+
+/* Structure for keeping list of addresses that have been added to
+Envelope-To:, in order to avoid duplication. */
+
+struct aci {
+ struct aci *next;
+ address_item *ptr;
+ };
+
+
+/* Static data for write_chunk() */
+
+static uschar *chunk_ptr; /* chunk pointer */
+static uschar *nl_check; /* string to look for at line start */
+static int nl_check_length; /* length of same */
+static uschar *nl_escape; /* string to insert */
+static int nl_escape_length; /* length of same */
+static int nl_partial_match; /* length matched at chunk end */
+
+
/*************************************************
* Initialize transport list *
*************************************************/
@@ -204,19 +208,21 @@ evermore, so stick a maximum repetition count on the loop to act as a
longstop.
Arguments:
- fd file descriptor to write to
+ tctx transport context: file descriptor or string to write to
block block of bytes to write
len number of bytes to write
+ more further data expected soon
Returns: TRUE on success, FALSE on failure (with errno preserved);
transport_count is incremented by the number of bytes written
*/
-BOOL
-transport_write_block(int fd, uschar *block, int len)
+static BOOL
+transport_write_block_fd(transport_ctx * tctx, uschar *block, int len, BOOL more)
{
int i, rc, save_errno;
int local_timeout = transport_write_timeout;
+int fd = tctx->u.fd;
/* This loop is for handling incomplete writes and other retries. In most
normal cases, it is only ever executed once. */
@@ -224,8 +230,8 @@ normal cases, it is only ever executed once. */
for (i = 0; i < 100; i++)
{
DEBUG(D_transport)
- debug_printf("writing data block fd=%d size=%d timeout=%d\n",
- fd, len, local_timeout);
+ debug_printf("writing data block fd=%d size=%d timeout=%d%s\n",
+ fd, len, local_timeout, more ? " (more expected)" : "");
/* This code makes use of alarm() in order to implement the timeout. This
isn't a very tidy way of doing things. Using non-blocking I/O with select()
@@ -234,10 +240,14 @@ for (i = 0; i < 100; i++)
if (transport_write_timeout <= 0) /* No timeout wanted */
{
- #ifdef SUPPORT_TLS
- if (tls_out.active == fd) rc = tls_write(FALSE, block, len); else
- #endif
- rc = write(fd, block, len);
+ rc =
+#ifdef SUPPORT_TLS
+ tls_out.active == fd ? tls_write(FALSE, block, len, more) :
+#endif
+#ifdef MSG_MORE
+ more ? send(fd, block, len, MSG_MORE) :
+#endif
+ write(fd, block, len);
save_errno = errno;
}
@@ -246,12 +256,16 @@ for (i = 0; i < 100; i++)
else
{
alarm(local_timeout);
+
+ rc =
#ifdef SUPPORT_TLS
- if (tls_out.active == fd)
- rc = tls_write(FALSE, block, len);
- else
+ tls_out.active == fd ? tls_write(FALSE, block, len, more) :
#endif
- rc = write(fd, block, len);
+#ifdef MSG_MORE
+ more ? send(fd, block, len, MSG_MORE) :
+#endif
+ write(fd, block, len);
+
save_errno = errno;
local_timeout = alarm(0);
if (sigalrm_seen)
@@ -323,6 +337,25 @@ return FALSE;
}
+BOOL
+transport_write_block(transport_ctx * tctx, uschar *block, int len, BOOL more)
+{
+if (!(tctx->options & topt_output_string))
+ return transport_write_block_fd(tctx, block, len, more);
+
+/* Write to expanding-string. NOTE: not NUL-terminated */
+
+if (!tctx->u.msg)
+ {
+ tctx->u.msg = store_get(tctx->msg_size = 1024);
+ tctx->msg_ptr = 0;
+ }
+
+tctx->u.msg = string_catn(tctx->u.msg, &tctx->msg_size, &tctx->msg_ptr, block, len);
+return TRUE;
+}
+
+
/*************************************************
@@ -342,17 +375,29 @@ Returns: the yield of transport_write_block()
BOOL
transport_write_string(int fd, const char *format, ...)
{
+transport_ctx tctx = {{0}};
va_list ap;
va_start(ap, format);
if (!string_vformat(big_buffer, big_buffer_size, format, ap))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong formatted string in transport");
va_end(ap);
-return transport_write_block(fd, big_buffer, Ustrlen(big_buffer));
+tctx.u.fd = fd;
+return transport_write_block(&tctx, big_buffer, Ustrlen(big_buffer), FALSE);
}
+void
+transport_write_reset(int options)
+{
+if (!(options & topt_continuation)) chunk_ptr = deliver_out_buffer;
+nl_partial_match = -1;
+nl_check_length = nl_escape_length = 0;
+}
+
+
+
/*************************************************
* Write character chunk *
*************************************************/
@@ -366,18 +411,18 @@ Static data is used to handle the case when the last character of the previous
chunk was NL, or matched part of the data that has to be escaped.
Arguments:
- fd file descript to write to
+ tctx transport context - processing to be done during output,
+ and file descriptor to write to
chunk pointer to data to write
len length of data to write
- tctx transport context - processing to be done during output
In addition, the static nl_xxx variables must be set as required.
Returns: TRUE on success, FALSE on failure (with errno preserved)
*/
-static BOOL
-write_chunk(int fd, transport_ctx * tctx, uschar *chunk, int len)
+BOOL
+write_chunk(transport_ctx * tctx, uschar *chunk, int len)
{
uschar *start = chunk;
uschar *end = chunk + len;
@@ -433,27 +478,36 @@ for (ptr = start; ptr < end; ptr++)
/* If CHUNKING, prefix with BDAT (size) NON-LAST. Also, reap responses
from previous SMTP commands. */
- if (tctx && tctx->options & topt_use_bdat && tctx->chunk_cb)
+ if (tctx->options & topt_use_bdat && tctx->chunk_cb)
{
- if ( tctx->chunk_cb(fd, tctx, (unsigned)len, 0) != OK
- || !transport_write_block(fd, deliver_out_buffer, len)
- || tctx->chunk_cb(fd, tctx, 0, tc_reap_prev) != OK
+ if ( tctx->chunk_cb(tctx, (unsigned)len, 0) != OK
+ || !transport_write_block(tctx, deliver_out_buffer, len, FALSE)
+ || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK
)
return FALSE;
}
else
- if (!transport_write_block(fd, deliver_out_buffer, len))
+ if (!transport_write_block(tctx, deliver_out_buffer, len, FALSE))
return FALSE;
chunk_ptr = deliver_out_buffer;
}
+ /* Remove CR before NL if required */
+
+ if ( *ptr == '\r' && ptr[1] == '\n'
+ && !(tctx->options & topt_use_crlf)
+ && spool_file_wireformat
+ )
+ ptr++;
+
if ((ch = *ptr) == '\n')
{
int left = end - ptr - 1; /* count of chars left after NL */
/* Insert CR before NL if required */
- if (tctx && tctx->options & topt_use_crlf) *chunk_ptr++ = '\r';
+ if (tctx->options & topt_use_crlf && !spool_file_wireformat)
+ *chunk_ptr++ = '\r';
*chunk_ptr++ = '\n';
transport_newlines++;
@@ -569,15 +623,15 @@ Arguments:
pplist address of anchor of the list of addresses not to output
pdlist address of anchor of the list of processed addresses
first TRUE if this is the first address; set it FALSE afterwards
- fd the file descriptor to write to
tctx transport context - processing to be done during output
+ and the file descriptor to write to
Returns: FALSE if writing failed
*/
static BOOL
write_env_to(address_item *p, struct aci **pplist, struct aci **pdlist,
- BOOL *first, int fd, transport_ctx * tctx)
+ BOOL *first, transport_ctx * tctx)
{
address_item *pp;
struct aci *ppp;
@@ -599,7 +653,7 @@ for (pp = p;; pp = pp->parent)
address_item *dup;
for (dup = addr_duplicate; dup; dup = dup->next)
if (dup->dupof == pp) /* a dup of our address */
- if (!write_env_to(dup, pplist, pdlist, first, fd, tctx))
+ if (!write_env_to(dup, pplist, pdlist, first, tctx))
return FALSE;
if (!pp->parent) break;
}
@@ -616,9 +670,9 @@ ppp->next = *pplist;
*pplist = ppp;
ppp->ptr = pp;
-if (!*first && !write_chunk(fd, tctx, US",\n ", 3)) return FALSE;
+if (!*first && !write_chunk(tctx, US",\n ", 3)) return FALSE;
*first = FALSE;
-return write_chunk(fd, tctx, pp->address, Ustrlen(pp->address));
+return write_chunk(tctx, pp->address, Ustrlen(pp->address));
}
@@ -632,15 +686,14 @@ Globals:
Arguments:
addr (chain of) addresses (for extra headers), or NULL;
only the first address is used
- fd file descriptor to write the message to
tctx transport context
sendfn function for output (transport or verify)
Returns: TRUE on success; FALSE on failure.
*/
BOOL
-transport_headers_send(int fd, transport_ctx * tctx,
- BOOL (*sendfn)(int fd, transport_ctx * tctx, uschar * s, int len))
+transport_headers_send(transport_ctx * tctx,
+ BOOL (*sendfn)(transport_ctx * tctx, uschar * s, int len))
{
header_line *h;
const uschar *list;
@@ -700,7 +753,7 @@ for (h = header_list; h; h = h->next) if (h->type != htype_old)
if ((hh = rewrite_header(h, NULL, NULL, tblock->rewrite_rules,
tblock->rewrite_existflags, FALSE)))
{
- if (!sendfn(fd, tctx, hh->text, hh->slen)) return FALSE;
+ if (!sendfn(tctx, hh->text, hh->slen)) return FALSE;
store_reset(reset_point);
continue; /* With the next header line */
}
@@ -708,15 +761,13 @@ for (h = header_list; h; h = h->next) if (h->type != htype_old)
/* Either no rewriting rules, or it didn't get rewritten */
- if (!sendfn(fd, tctx, h->text, h->slen)) return FALSE;
+ if (!sendfn(tctx, h->text, h->slen)) return FALSE;
}
/* Header removed */
else
- {
DEBUG(D_transport) debug_printf("removed header line:\n%s---\n", h->text);
- }
}
/* Add on any address-specific headers. If there are multiple addresses,
@@ -743,7 +794,7 @@ if (addr)
hprev = h;
if (i == 1)
{
- if (!sendfn(fd, tctx, h->text, h->slen)) return FALSE;
+ if (!sendfn(tctx, h->text, h->slen)) return FALSE;
DEBUG(D_transport)
debug_printf("added header line(s):\n%s---\n", h->text);
}
@@ -768,8 +819,8 @@ if (tblock && (list = CUS tblock->add_headers))
int len = Ustrlen(s);
if (len > 0)
{
- if (!sendfn(fd, tctx, s, len)) return FALSE;
- if (s[len-1] != '\n' && !sendfn(fd, tctx, US"\n", 1))
+ if (!sendfn(tctx, s, len)) return FALSE;
+ if (s[len-1] != '\n' && !sendfn(tctx, US"\n", 1))
return FALSE;
DEBUG(D_transport)
{
@@ -785,7 +836,7 @@ if (tblock && (list = CUS tblock->add_headers))
/* Separate headers from body with a blank line */
-return sendfn(fd, tctx, US"\n", 1);
+return sendfn(tctx, US"\n", 1);
}
@@ -818,8 +869,10 @@ can include timeouts for certain transports, which are requested by setting
transport_write_timeout non-zero.
Arguments:
- fd file descriptor to write the message to
tctx
+ (fd, msg) Either and fd, to write the message to,
+ or a string: if null write message to allocated space
+ otherwire take content as headers.
addr (chain of) addresses (for extra headers), or NULL;
only the first address is used
tblock optional transport instance block (NULL signifies NULL/0):
@@ -851,17 +904,16 @@ Returns: TRUE on success; FALSE (with errno) on failure.
*/
static BOOL
-internal_transport_write_message(int fd, transport_ctx * tctx, int size_limit)
+internal_transport_write_message(transport_ctx * tctx, int size_limit)
{
-int len;
+int len, size = 0;
/* Initialize pointer in output buffer. */
-chunk_ptr = deliver_out_buffer;
+transport_write_reset(tctx->options);
/* Set up the data for start-of-line data checking and escaping */
-nl_partial_match = -1;
if (tctx->check_string && tctx->escape_string)
{
nl_check = tctx->check_string;
@@ -869,8 +921,6 @@ if (tctx->check_string && tctx->escape_string)
nl_escape = tctx->escape_string;
nl_escape_length = Ustrlen(nl_escape);
}
-else
- nl_check_length = nl_escape_length = 0;
/* Whether the escaping mechanism is applied to headers or not is controlled by
an option (set for SMTP, not otherwise). Negate the length if not wanted till
@@ -880,10 +930,14 @@ if (!(tctx->options & topt_escape_headers))
nl_check_length = -nl_check_length;
/* Write the headers if required, including any that have to be added. If there
-are header rewriting rules, apply them. */
+are header rewriting rules, apply them. The datasource is not the -D spoolfile
+so temporarily hide the global that adjusts for its format. */
if (!(tctx->options & topt_no_headers))
{
+ BOOL save_wireformat = spool_file_wireformat;
+ spool_file_wireformat = FALSE;
+
/* Add return-path: if requested. */
if (tctx->options & topt_add_return_path)
@@ -891,7 +945,7 @@ if (!(tctx->options & topt_no_headers))
uschar buffer[ADDRESS_MAXLENGTH + 20];
int n = sprintf(CS buffer, "Return-path: <%.*s>\n", ADDRESS_MAXLENGTH,
return_path);
- if (!write_chunk(fd, tctx, buffer, n)) return FALSE;
+ if (!write_chunk(tctx, buffer, n)) goto bad;
}
/* Add envelope-to: if requested */
@@ -904,19 +958,18 @@ if (!(tctx->options & topt_no_headers))
struct aci *dlist = NULL;
void *reset_point = store_get(0);
- if (!write_chunk(fd, tctx, US"Envelope-to: ", 13)) return FALSE;
+ if (!write_chunk(tctx, US"Envelope-to: ", 13)) goto bad;
/* Pick up from all the addresses. The plist and dlist variables are
anchors for lists of addresses already handled; they have to be defined at
this level because write_env_to() calls itself recursively. */
for (p = tctx->addr; p; p = p->next)
- if (!write_env_to(p, &plist, &dlist, &first, fd, tctx))
- return FALSE;
+ if (!write_env_to(p, &plist, &dlist, &first, tctx)) goto bad;
/* Add a final newline and reset the store used for tracking duplicates */
- if (!write_chunk(fd, tctx, US"\n", 1)) return FALSE;
+ if (!write_chunk(tctx, US"\n", 1)) goto bad;
store_reset(reset_point);
}
@@ -924,9 +977,11 @@ if (!(tctx->options & topt_no_headers))
if (tctx->options & topt_add_delivery_date)
{
- uschar buffer[100];
- int n = sprintf(CS buffer, "Delivery-date: %s\n", tod_stamp(tod_full));
- if (!write_chunk(fd, tctx, buffer, n)) return FALSE;
+ uschar * s = tod_stamp(tod_full);
+
+ if ( !write_chunk(tctx, US"Delivery-date: ", 15)
+ || !write_chunk(tctx, s, Ustrlen(s))
+ || !write_chunk(tctx, US"\n", 1)) goto bad;
}
/* Then the message's headers. Don't write any that are flagged as "old";
@@ -935,8 +990,14 @@ if (!(tctx->options & topt_no_headers))
match any entries therein. Then check addr->prop.remove_headers too, provided that
addr is not NULL. */
- if (!transport_headers_send(fd, tctx, &write_chunk))
+ if (!transport_headers_send(tctx, &write_chunk))
+ {
+bad:
+ spool_file_wireformat = save_wireformat;
return FALSE;
+ }
+
+ spool_file_wireformat = save_wireformat;
}
/* When doing RFC3030 CHUNKING output, work out how much data would be in a
@@ -954,7 +1015,7 @@ suboptimal. */
if (tctx->options & topt_use_bdat)
{
off_t fsize;
- int hsize, size = 0;
+ int hsize;
if ((hsize = chunk_ptr - deliver_out_buffer) < 0)
hsize = 0;
@@ -965,8 +1026,11 @@ if (tctx->options & topt_use_bdat)
if (size_limit > 0 && fsize > size_limit)
fsize = size_limit;
size = hsize + fsize;
- if (tctx->options & topt_use_crlf)
+ if (tctx->options & topt_use_crlf && !spool_file_wireformat)
size += body_linecount; /* account for CRLF-expansion */
+
+ /* With topt_use_bdat we never do dot-stuffing; no need to
+ account for any expansion due to that. */
}
/* If the message is large, emit first a non-LAST chunk with just the
@@ -979,20 +1043,20 @@ if (tctx->options & topt_use_bdat)
{
DEBUG(D_transport)
debug_printf("sending small initial BDAT; hsize=%d\n", hsize);
- if ( tctx->chunk_cb(fd, tctx, hsize, 0) != OK
- || !transport_write_block(fd, deliver_out_buffer, hsize)
- || tctx->chunk_cb(fd, tctx, 0, tc_reap_prev) != OK
+ if ( tctx->chunk_cb(tctx, hsize, 0) != OK
+ || !transport_write_block(tctx, deliver_out_buffer, hsize, FALSE)
+ || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK
)
return FALSE;
chunk_ptr = deliver_out_buffer;
size -= hsize;
}
- /* Emit a LAST datachunk command. */
+ /* Emit a LAST datachunk command, and unmark the context for further
+ BDAT commands. */
- if (tctx->chunk_cb(fd, tctx, size, tc_chunk_last) != OK)
+ if (tctx->chunk_cb(tctx, size, tc_chunk_last) != OK)
return FALSE;
-
tctx->options &= ~topt_use_bdat;
}
@@ -1002,6 +1066,52 @@ negative in cases where it isn't to apply to the headers). Then ensure the body
is positioned at the start of its file (following the message id), then write
it, applying the size limit if required. */
+/* If we have a wireformat -D file (CRNL lines, non-dotstuffed, no ending dot)
+and we want to send a body without dotstuffing or ending-dot, in-clear,
+then we can just dump it using sendfile.
+This should get used for CHUNKING output and also for writing the -K file for
+dkim signing, when we had CHUNKING input. */
+
+#ifdef OS_SENDFILE
+if ( spool_file_wireformat
+ && !(tctx->options & (topt_no_body | topt_end_dot))
+ && !nl_check_length
+ && tls_out.active != tctx->u.fd
+ )
+ {
+ ssize_t copied = 0;
+ off_t offset = SPOOL_DATA_START_OFFSET;
+
+ /* Write out any header data in the buffer */
+
+ if ((len = chunk_ptr - deliver_out_buffer) > 0)
+ {
+ if (!transport_write_block(tctx, deliver_out_buffer, len, TRUE))
+ return FALSE;
+ size -= len;
+ }
+
+ DEBUG(D_transport) debug_printf("using sendfile for body\n");
+
+ while(size > 0)
+ {
+ if ((copied = os_sendfile(tctx->u.fd, deliver_datafile, &offset, size)) <= 0) break;
+ size -= copied;
+ }
+ return copied >= 0;
+ }
+#else
+DEBUG(D_transport) debug_printf("cannot use sendfile for body: no support\n");
+#endif
+
+DEBUG(D_transport)
+ if (!(tctx->options & topt_no_body))
+ debug_printf("cannot use sendfile for body: %s\n",
+ !spool_file_wireformat ? "spoolfile not wireformat"
+ : tctx->options & topt_end_dot ? "terminating dot wanted"
+ : nl_check_length ? "dot- or From-stuffing wanted"
+ : "TLS output wanted");
+
if (!(tctx->options & topt_no_body))
{
int size = size_limit;
@@ -1013,7 +1123,7 @@ if (!(tctx->options & topt_no_body))
while ( (len = MAX(DELIVER_IN_BUFFER_SIZE, size)) > 0
&& (len = read(deliver_datafile, deliver_in_buffer, len)) > 0)
{
- if (!write_chunk(fd, tctx, deliver_in_buffer, len))
+ if (!write_chunk(tctx, deliver_in_buffer, len))
return FALSE;
size -= len;
}
@@ -1029,202 +1139,15 @@ nl_check_length = nl_escape_length = 0;
/* If requested, add a terminating "." line (SMTP output). */
-if (tctx->options & topt_end_dot && !write_chunk(fd, tctx, US".\n", 2))
+if (tctx->options & topt_end_dot && !write_chunk(tctx, US".\n", 2))
return FALSE;
/* Write out any remaining data in the buffer before returning. */
return (len = chunk_ptr - deliver_out_buffer) <= 0 ||
- transport_write_block(fd, deliver_out_buffer, len);
-}
-
-
-#ifndef DISABLE_DKIM
-
-/***************************************************************************************************
-* External interface to write the message, while signing it with DKIM and/or Domainkeys *
-***************************************************************************************************/
-
-/* This function is a wrapper around transport_write_message().
- It is only called from the smtp transport if DKIM or Domainkeys support
- is compiled in. The function sets up a replacement fd into a -K file,
- then calls the normal function. This way, the exact bits that exim would
- have put "on the wire" will end up in the file (except for TLS
- encapsulation, which is the very very last thing). When we are done
- signing the file, send the signed message down the original fd (or TLS fd).
-
-Arguments:
- as for internal_transport_write_message() above, with additional arguments
- for DKIM.
-
-Returns: TRUE on success; FALSE (with errno) for any failure
-*/
-
-BOOL
-dkim_transport_write_message(int out_fd, transport_ctx * tctx,
- struct ob_dkim * dkim, const uschar ** err)
-{
-int dkim_fd;
-int save_errno = 0;
-BOOL rc;
-uschar * dkim_spool_name;
-uschar * dkim_signature = NULL;
-int sread = 0, wwritten = 0, siglen = 0, options;
-off_t k_file_size;
-const uschar * errstr;
-
-/* If we can't sign, just call the original function. */
-
-if (!(dkim->dkim_private_key && dkim->dkim_domain && dkim->dkim_selector))
- return transport_write_message(out_fd, tctx, 0);
-
-dkim_spool_name = spool_fname(US"input", message_subdir, message_id,
- string_sprintf("-%d-K", (int)getpid()));
-
-if ((dkim_fd = Uopen(dkim_spool_name, O_RDWR|O_CREAT|O_TRUNC, SPOOL_MODE)) < 0)
- {
- /* Can't create spool file. Ugh. */
- rc = FALSE;
- save_errno = errno;
- *err = string_sprintf("dkim spoolfile create: %s", strerror(errno));
- goto CLEANUP;
- }
-
-/* Call original function to write the -K file; does the CRLF expansion
-(but, in the CHUNKING case, not dot-stuffing and dot-termination). */
-
-options = tctx->options;
-tctx->options &= ~topt_use_bdat;
-rc = transport_write_message(dkim_fd, tctx, 0);
-tctx->options = options;
-
-/* Save error state. We must clean up before returning. */
-if (!rc)
- {
- save_errno = errno;
- goto CLEANUP;
- }
-
-/* Rewind file and feed it to the goats^W DKIM lib */
-dkim->dot_stuffed = !!(options & topt_end_dot);
-lseek(dkim_fd, 0, SEEK_SET);
-if ((dkim_signature = dkim_exim_sign(dkim_fd, dkim, &errstr)))
- siglen = Ustrlen(dkim_signature);
-else if (dkim->dkim_strict)
- {
- uschar *dkim_strict_result = expand_string(dkim->dkim_strict);
- if (dkim_strict_result)
- if ( (strcmpic(dkim->dkim_strict,US"1") == 0) ||
- (strcmpic(dkim->dkim_strict,US"true") == 0) )
- {
- /* Set errno to something halfway meaningful */
- save_errno = EACCES;
- log_write(0, LOG_MAIN, "DKIM: message could not be signed,"
- " and dkim_strict is set. Deferring message delivery.");
- *err = errstr;
- rc = FALSE;
- goto CLEANUP;
- }
- }
-
-#ifndef HAVE_LINUX_SENDFILE
-if (options & topt_use_bdat)
-#endif
- k_file_size = lseek(dkim_fd, 0, SEEK_END); /* Fetch file size */
-
-if (options & topt_use_bdat)
- {
-
- /* On big messages output a precursor chunk to get any pipelined
- MAIL & RCPT commands flushed, then reap the responses so we can
- error out on RCPT rejects before sending megabytes. */
-
- if (siglen + k_file_size > DELIVER_OUT_BUFFER_SIZE && siglen > 0)
- {
- if ( tctx->chunk_cb(out_fd, tctx, siglen, 0) != OK
- || !transport_write_block(out_fd, dkim_signature, siglen)
- || tctx->chunk_cb(out_fd, tctx, 0, tc_reap_prev) != OK
- )
- goto err;
- siglen = 0;
- }
-
- if (tctx->chunk_cb(out_fd, tctx, siglen + k_file_size, tc_chunk_last) != OK)
- goto err;
- }
-
-if(siglen > 0 && !transport_write_block(out_fd, dkim_signature, siglen))
- goto err;
-
-#ifdef HAVE_LINUX_SENDFILE
-/* We can use sendfile() to shove the file contents
- to the socket. However only if we don't use TLS,
- as then there's another layer of indirection
- before the data finally hits the socket. */
-if (tls_out.active != out_fd)
- {
- ssize_t copied = 0;
- off_t offset = 0;
-
- /* Rewind file */
- lseek(dkim_fd, 0, SEEK_SET);
-
- while(copied >= 0 && offset < k_file_size)
- copied = sendfile(out_fd, dkim_fd, &offset, k_file_size - offset);
- if (copied < 0)
- goto err;
- }
-else
-
-#endif
-
- {
- /* Rewind file */
- lseek(dkim_fd, 0, SEEK_SET);
-
- /* Send file down the original fd */
- while((sread = read(dkim_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) >0)
- {
- uschar * p = deliver_out_buffer;
- /* write the chunk */
-
- while (sread)
- {
-#ifdef SUPPORT_TLS
- wwritten = tls_out.active == out_fd
- ? tls_write(FALSE, p, sread)
- : write(out_fd, CS p, sread);
-#else
- wwritten = write(out_fd, CS p, sread);
-#endif
- if (wwritten == -1)
- goto err;
- p += wwritten;
- sread -= wwritten;
- }
- }
-
- if (sread == -1)
- {
- save_errno = errno;
- rc = FALSE;
- }
- }
-
-CLEANUP:
- /* unlink -K file */
- (void)close(dkim_fd);
- Uunlink(dkim_spool_name);
- errno = save_errno;
- return rc;
-
-err:
- save_errno = errno;
- rc = FALSE;
- goto CLEANUP;
+ transport_write_block(tctx, deliver_out_buffer, len, FALSE);
}
-#endif
@@ -1236,9 +1159,9 @@ err:
the real work, passing over all the arguments from this function. Otherwise,
set up a filtering process, fork another process to call the internal function
to write to the filter, and in this process just suck from the filter and write
-down the given fd. At the end, tidy up the pipes and the processes.
+down the fd in the transport context. At the end, tidy up the pipes and the
+processes.
-XXX
Arguments: as for internal_transport_write_message() above
Returns: TRUE on success; FALSE (with errno) for any failure
@@ -1246,15 +1169,13 @@ Returns: TRUE on success; FALSE (with errno) for any failure
*/
BOOL
-transport_write_message(int fd, transport_ctx * tctx, int size_limit)
+transport_write_message(transport_ctx * tctx, int size_limit)
{
BOOL last_filter_was_NL = TRUE;
+BOOL save_spool_file_wireformat = spool_file_wireformat;
int rc, len, yield, fd_read, fd_write, save_errno;
int pfd[2] = {-1, -1};
pid_t filter_pid, write_pid;
-static transport_ctx dummy_tctx = {0};
-
-if (!tctx) tctx = &dummy_tctx;
transport_filter_timed_out = FALSE;
@@ -1265,7 +1186,7 @@ if ( !transport_filter_argv
|| !*transport_filter_argv
|| !**transport_filter_argv
)
- return internal_transport_write_message(fd, tctx, size_limit);
+ return internal_transport_write_message(tctx, size_limit);
/* Otherwise the message must be written to a filter process and read back
before being written to the incoming fd. First set up the special processing to
@@ -1295,11 +1216,11 @@ yield = FALSE;
write_pid = (pid_t)(-1);
{
- int bits = fcntl(fd, F_GETFD);
- (void)fcntl(fd, F_SETFD, bits | FD_CLOEXEC);
+ int bits = fcntl(tctx->u.fd, F_GETFD);
+ (void)fcntl(tctx->u.fd, F_SETFD, bits | FD_CLOEXEC);
filter_pid = child_open(USS transport_filter_argv, NULL, 077,
&fd_write, &fd_read, FALSE);
- (void)fcntl(fd, F_SETFD, bits & ~FD_CLOEXEC);
+ (void)fcntl(tctx->u.fd, F_SETFD, bits & ~FD_CLOEXEC);
}
if (filter_pid < 0) goto TIDY_UP; /* errno set */
@@ -1319,10 +1240,11 @@ if ((write_pid = fork()) == 0)
(void)close(pfd[pipe_read]);
nl_check_length = nl_escape_length = 0;
+ tctx->u.fd = fd_write;
tctx->check_string = tctx->escape_string = NULL;
tctx->options &= ~(topt_use_crlf | topt_end_dot | topt_use_bdat);
- rc = internal_transport_write_message(fd_write, tctx, size_limit);
+ rc = internal_transport_write_message(tctx, size_limit);
save_errno = errno;
if ( write(pfd[pipe_write], (void *)&rc, sizeof(BOOL))
@@ -1331,6 +1253,8 @@ if ((write_pid = fork()) == 0)
!= sizeof(int)
|| write(pfd[pipe_write], (void *)&tctx->addr->more_errno, sizeof(int))
!= sizeof(int)
+ || write(pfd[pipe_write], (void *)&tctx->addr->delivery_usec, sizeof(int))
+ != sizeof(int)
)
rc = FALSE; /* compiler quietening */
_exit(0);
@@ -1367,8 +1291,10 @@ DEBUG(D_transport) debug_printf("copying from the filter\n");
/* Copy the output of the filter, remembering if the last character was NL. If
no data is returned, that counts as "ended with NL" (default setting of the
-variable is TRUE). */
+variable is TRUE). The output should always be unix-format as we converted
+any wireformat source on writing input to the filter. */
+spool_file_wireformat = FALSE;
chunk_ptr = deliver_out_buffer;
for (;;)
@@ -1389,7 +1315,7 @@ for (;;)
if (len > 0)
{
- if (!write_chunk(fd, tctx, deliver_in_buffer, len)) goto TIDY_UP;
+ if (!write_chunk(tctx, deliver_in_buffer, len)) goto TIDY_UP;
last_filter_was_NL = (deliver_in_buffer[len-1] == '\n');
}
@@ -1408,6 +1334,7 @@ there has been an error, kill the processes before waiting for them, just to be
sure. Also apply a paranoia timeout. */
TIDY_UP:
+spool_file_wireformat = save_spool_file_wireformat;
save_errno = errno;
(void)close(fd_read);
@@ -1452,7 +1379,9 @@ if (write_pid > 0)
else if (!ok)
{
int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
- dummy = read(pfd[pipe_read], (void *)&(tctx->addr->more_errno), sizeof(int));
+ dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int));
+ dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_usec, sizeof(int));
+ dummy = dummy; /* compiler quietening */
yield = FALSE;
}
}
@@ -1475,8 +1404,8 @@ if (yield)
nl_check_length = nl_escape_length = 0;
if ( tctx->options & topt_end_dot
&& ( last_filter_was_NL
- ? !write_chunk(fd, tctx, US".\n", 2)
- : !write_chunk(fd, tctx, US"\n.\n", 3)
+ ? !write_chunk(tctx, US".\n", 2)
+ : !write_chunk(tctx, US"\n.\n", 3)
) )
yield = FALSE;
@@ -1484,7 +1413,7 @@ if (yield)
else
yield = (len = chunk_ptr - deliver_out_buffer) <= 0
- || transport_write_block(fd, deliver_out_buffer, len);
+ || transport_write_block(tctx, deliver_out_buffer, len, FALSE);
}
else
errno = save_errno; /* From some earlier error */
@@ -1541,7 +1470,6 @@ Returns: nothing
void
transport_update_waiting(host_item *hostlist, uschar *tpname)
{
-uschar buffer[256];
const uschar *prevname = US"";
host_item *host;
open_db dbblock;
@@ -1551,19 +1479,20 @@ DEBUG(D_transport) debug_printf("updating wait-%s database\n", tpname);
/* Open the database for this transport */
-sprintf(CS buffer, "wait-%.200s", tpname);
-dbm_file = dbfn_open(buffer, O_RDWR, &dbblock, TRUE);
-if (dbm_file == NULL) return;
+if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", tpname),
+ O_RDWR, &dbblock, TRUE)))
+ return;
/* Scan the list of hosts for which this message is waiting, and ensure
that the message id is in each host record. */
-for (host = hostlist; host!= NULL; host = host->next)
+for (host = hostlist; host; host = host->next)
{
BOOL already = FALSE;
dbdata_wait *host_record;
uschar *s;
int i, host_length;
+ uschar buffer[256];
/* Skip if this is the same host as we just processed; otherwise remember
the name for next time. */
@@ -1573,8 +1502,7 @@ for (host = hostlist; host!= NULL; host = host->next)
/* Look up the host record; if there isn't one, make an empty one. */
- host_record = dbfn_read(dbm_file, host->name);
- if (host_record == NULL)
+ if (!(host_record = dbfn_read(dbm_file, host->name)))
{
host_record = store_get(sizeof(dbdata_wait) + MESSAGE_ID_LENGTH);
host_record->count = host_record->sequence = 0;
@@ -1588,10 +1516,8 @@ for (host = hostlist; host!= NULL; host = host->next)
for (s = host_record->text; s < host_record->text + host_length;
s += MESSAGE_ID_LENGTH)
- {
if (Ustrncmp(s, message_id, MESSAGE_ID_LENGTH) == 0)
{ already = TRUE; break; }
- }
/* If we haven't found this message in the main record, search any
continuation records that exist. */
@@ -1600,15 +1526,12 @@ for (host = hostlist; host!= NULL; host = host->next)
{
dbdata_wait *cont;
sprintf(CS buffer, "%.200s:%d", host->name, i);
- cont = dbfn_read(dbm_file, buffer);
- if (cont != NULL)
+ if ((cont = dbfn_read(dbm_file, buffer)))
{
int clen = cont->count * MESSAGE_ID_LENGTH;
for (s = cont->text; s < cont->text + clen; s += MESSAGE_ID_LENGTH)
- {
if (Ustrncmp(s, message_id, MESSAGE_ID_LENGTH) == 0)
{ already = TRUE; break; }
- }
}
}
@@ -1704,7 +1627,6 @@ dbdata_wait *host_record;
int host_length;
open_db dbblock;
open_db *dbm_file;
-uschar buffer[256];
int i;
struct stat statbuf;
@@ -1731,9 +1653,9 @@ if (local_message_max > 0 && continue_sequence >= local_message_max)
/* Open the waiting information database. */
-sprintf(CS buffer, "wait-%.200s", transport_name);
-dbm_file = dbfn_open(buffer, O_RDWR, &dbblock, TRUE);
-if (dbm_file == NULL) return FALSE;
+if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", transport_name),
+ O_RDWR, &dbblock, TRUE)))
+ return FALSE;
/* See if there is a record for this host; if not, there's nothing to do. */
@@ -1849,13 +1771,13 @@ while (1)
}
}
-/* Jeremy: check for a continuation record, this code I do not know how to
-test but the code should work */
+ /* Check for a continuation record. */
while (host_length <= 0)
{
int i;
dbdata_wait * newr = NULL;
+ uschar buffer[256];
/* Search for a continuation */
@@ -1934,6 +1856,70 @@ return TRUE;
* Deliver waiting message down same socket *
*************************************************/
+/* Just the regain-root-privilege exec portion */
+void
+transport_do_pass_socket(const uschar *transport_name, const uschar *hostname,
+ const uschar *hostaddress, uschar *id, int socket_fd)
+{
+int i = 20;
+const uschar **argv;
+
+/* Set up the calling arguments; use the standard function for the basics,
+but we have a number of extras that may be added. */
+
+argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
+
+if (smtp_authenticated) argv[i++] = US"-MCA";
+if (smtp_peer_options & OPTION_CHUNKING) argv[i++] = US"-MCK";
+if (smtp_peer_options & OPTION_DSN) argv[i++] = US"-MCD";
+if (smtp_peer_options & OPTION_PIPE) argv[i++] = US"-MCP";
+if (smtp_peer_options & OPTION_SIZE) argv[i++] = US"-MCS";
+#ifdef SUPPORT_TLS
+if (smtp_peer_options & OPTION_TLS)
+ if (tls_out.active >= 0 || continue_proxy_cipher)
+ {
+ argv[i++] = US"-MCt";
+ argv[i++] = sending_ip_address;
+ argv[i++] = string_sprintf("%d", sending_port);
+ argv[i++] = tls_out.active >= 0 ? tls_out.cipher : continue_proxy_cipher;
+ }
+ else
+ argv[i++] = US"-MCT";
+#endif
+
+if (queue_run_pid != (pid_t)0)
+ {
+ argv[i++] = US"-MCQ";
+ argv[i++] = string_sprintf("%d", queue_run_pid);
+ argv[i++] = string_sprintf("%d", queue_run_pipe);
+ }
+
+argv[i++] = US"-MC";
+argv[i++] = US transport_name;
+argv[i++] = US hostname;
+argv[i++] = US hostaddress;
+argv[i++] = string_sprintf("%d", continue_sequence + 1);
+argv[i++] = id;
+argv[i++] = NULL;
+
+/* Arrange for the channel to be on stdin. */
+
+if (socket_fd != 0)
+ {
+ (void)dup2(socket_fd, 0);
+ (void)close(socket_fd);
+ }
+
+DEBUG(D_exec) debug_print_argv(argv);
+exim_nullstd(); /* Ensure std{out,err} exist */
+execv(CS argv[0], (char *const *)argv);
+
+DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno));
+_exit(errno); /* Note: must be _exit(), NOT exit() */
+}
+
+
+
/* Fork a new exim process to deliver the message, and do a re-exec, both to
get a clean delivery process, and to regain root privilege in cases where it
has been given away.
@@ -1959,69 +1945,20 @@ DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
if ((pid = fork()) == 0)
{
- int i = 19;
- const uschar **argv;
-
/* Disconnect entirely from the parent process. If we are running in the
test harness, wait for a bit to allow the previous process time to finish,
write the log, etc., so that the output is always in the same order for
automatic comparison. */
- if ((pid = fork()) != 0) _exit(EXIT_SUCCESS);
- if (running_in_test_harness) sleep(1);
-
- /* Set up the calling arguments; use the standard function for the basics,
- but we have a number of extras that may be added. */
-
- argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
-
- if (smtp_authenticated) argv[i++] = US"-MCA";
-
- if (smtp_peer_options & PEER_OFFERED_CHUNKING) argv[i++] = US"-MCK";
- if (smtp_peer_options & PEER_OFFERED_DSN) argv[i++] = US"-MCD";
- if (smtp_peer_options & PEER_OFFERED_PIPE) argv[i++] = US"-MCP";
- if (smtp_peer_options & PEER_OFFERED_SIZE) argv[i++] = US"-MCS";
-#ifdef SUPPORT_TLS
- if (smtp_peer_options & PEER_OFFERED_TLS)
- if (tls_out.active >= 0 || continue_proxy)
- {
- argv[i++] = US"-MCt";
- argv[i++] = sending_ip_address;
- argv[i++] = string_sprintf("%d", sending_port);
- }
- else
- argv[i++] = US"-MCT";
-#endif
-
- if (queue_run_pid != (pid_t)0)
+ if ((pid = fork()) != 0)
{
- argv[i++] = US"-MCQ";
- argv[i++] = string_sprintf("%d", queue_run_pid);
- argv[i++] = string_sprintf("%d", queue_run_pipe);
+ DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid);
+ _exit(EXIT_SUCCESS);
}
+ if (running_in_test_harness) sleep(1);
- argv[i++] = US"-MC";
- argv[i++] = US transport_name;
- argv[i++] = US hostname;
- argv[i++] = US hostaddress;
- argv[i++] = string_sprintf("%d", continue_sequence + 1);
- argv[i++] = id;
- argv[i++] = NULL;
-
- /* Arrange for the channel to be on stdin. */
-
- if (socket_fd != 0)
- {
- (void)dup2(socket_fd, 0);
- (void)close(socket_fd);
- }
-
- DEBUG(D_exec) debug_print_argv(argv);
- exim_nullstd(); /* Ensure std{out,err} exist */
- execv(CS argv[0], (char *const *)argv);
-
- DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno));
- _exit(errno); /* Note: must be _exit(), NOT exit() */
+ transport_do_pass_socket(transport_name, hostname, hostaddress,
+ id, socket_fd);
}
/* If the process creation succeeded, wait for the first-level child, which
@@ -2032,7 +1969,7 @@ if (pid > 0)
{
int rc;
while ((rc = wait(&status)) != pid && (rc >= 0 || errno != ECHILD));
- DEBUG(D_transport) debug_printf("transport_pass_socket succeeded\n");
+ DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (inter-pid %d)\n", pid);
return TRUE;
}
else
@@ -2114,7 +2051,7 @@ while (*s != 0 && argcount < max_args)
while (isspace(*s)) s++;
}
-argv[argcount] = (uschar *)0;
+argv[argcount] = US 0;
/* If *s != 0 we have run out of argument slots. */
@@ -2150,7 +2087,7 @@ $recipients. */
DEBUG(D_transport)
{
debug_printf("direct command:\n");
- for (i = 0; argv[i] != (uschar *)0; i++)
+ for (i = 0; argv[i] != US 0; i++)
debug_printf(" argv[%d] = %s\n", i, string_printing(argv[i]));
}
@@ -2160,7 +2097,7 @@ if (expand_arguments)
addr->parent != NULL &&
Ustrcmp(addr->parent->address, "system-filter") == 0;
- for (i = 0; argv[i] != (uschar *)0; i++)
+ for (i = 0; argv[i] != US 0; i++)
{
/* Handle special fudge for passing an address list */
@@ -2244,7 +2181,7 @@ if (expand_arguments)
while (isspace(*s)) s++; /* strip space after arg */
}
- address_pipe_argv[address_pipe_argcount] = (uschar *)0;
+ address_pipe_argv[address_pipe_argcount] = US 0;
/* If *s != 0 we have run out of argument slots. */
if (*s != 0)
@@ -2292,7 +2229,7 @@ if (expand_arguments)
* [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0]
*/
for (address_pipe_i = 0;
- address_pipe_argv[address_pipe_i] != (uschar *)0;
+ address_pipe_argv[address_pipe_i] != US 0;
address_pipe_i++)
{
argv[i++] = address_pipe_argv[address_pipe_i];
@@ -2333,7 +2270,7 @@ if (expand_arguments)
DEBUG(D_transport)
{
debug_printf("direct command after expansion:\n");
- for (i = 0; argv[i] != (uschar *)0; i++)
+ for (i = 0; argv[i] != US 0; i++)
debug_printf(" argv[%d] = %s\n", i, string_printing(argv[i]));
}
}
@@ -2341,6 +2278,7 @@ if (expand_arguments)
return TRUE;
}
+#endif /*!MACRO_PREDEF*/
/* vi: aw ai sw=2
*/
/* End of transport.c */
diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c
index 9b3379be2..3b463c644 100644
--- a/src/src/transports/appendfile.c
+++ b/src/src/transports/appendfile.c
@@ -14,22 +14,6 @@
#endif
-/* Encodings for mailbox formats, and their names. MBX format is actually
-supported only if SUPPORT_MBX is set. */
-
-enum { mbf_unix, mbf_mbx, mbf_smail, mbf_maildir, mbf_mailstore };
-
-static const char *mailbox_formats[] = {
- "unix", "mbx", "smail", "maildir", "mailstore" };
-
-
-/* Check warn threshold only if quota size set or not a percentage threshold
- percentage check should only be done if quota > 0 */
-
-#define THRESHOLD_CHECK (ob->quota_warn_threshold_value > 0 && \
- (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
-
-
/* Options specific to the appendfile transport. They must be in alphabetic
order (note that "_" comes before the lower case letters). Some of them are
stored in the publicly visible instance block - these are flagged with the
@@ -170,6 +154,16 @@ address can appear in the tables drtables.c. */
int appendfile_transport_options_count =
sizeof(appendfile_transport_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+appendfile_transport_options_block appendfile_transport_option_defaults = {0};
+void appendfile_transport_init(transport_instance *tblock) {}
+BOOL appendfile_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else /*!MACRO_PREDEF*/
+
/* Default private options block for the appendfile transport. */
appendfile_transport_options_block appendfile_transport_option_defaults = {
@@ -234,10 +228,28 @@ appendfile_transport_options_block appendfile_transport_option_defaults = {
FALSE, /* mailstore_format */
FALSE, /* mbx_format */
FALSE, /* quota_warn_threshold_is_percent */
- TRUE /* quota_is_inclusive */
+ TRUE, /* quota_is_inclusive */
+ FALSE, /* quota_no_check */
+ FALSE /* quota_filecount_no_check */
};
+/* Encodings for mailbox formats, and their names. MBX format is actually
+supported only if SUPPORT_MBX is set. */
+
+enum { mbf_unix, mbf_mbx, mbf_smail, mbf_maildir, mbf_mailstore };
+
+static const char *mailbox_formats[] = {
+ "unix", "mbx", "smail", "maildir", "mailstore" };
+
+
+/* Check warn threshold only if quota size set or not a percentage threshold
+ percentage check should only be done if quota > 0 */
+
+#define THRESHOLD_CHECK (ob->quota_warn_threshold_value > 0 && \
+ (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
+
+
/*************************************************
* Setup entry point *
@@ -285,9 +297,11 @@ mailbox_filecount */
for (i = 0; i < 5; i++)
{
double d;
+ int no_check = 0;
uschar *which = NULL;
- if (q == NULL) d = default_value; else
+ if (q == NULL) d = default_value;
+ else
{
uschar *rest;
uschar *s = expand_string(q);
@@ -321,6 +335,15 @@ for (i = 0; i < 5; i++)
rest++;
}
+
+ /* For quota and quota_filecount there may be options
+ appended. Currently only "no_check", so we can be lazy parsing it */
+ if (i < 2 && Ustrstr(rest, "/no_check") == rest)
+ {
+ no_check = 1;
+ rest += sizeof("/no_check") - 1;
+ }
+
while (isspace(*rest)) rest++;
if (*rest != 0)
@@ -338,12 +361,14 @@ for (i = 0; i < 5; i++)
case 0:
if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4) which = US"quota";
ob->quota_value = (off_t)d;
+ ob->quota_no_check = no_check;
q = ob->quota_filecount;
break;
case 1:
if (d >= 2.0*1024.0*1024.0*1024.0) which = US"quota_filecount";
ob->quota_filecount_value = (int)d;
+ ob->quota_filecount_no_check = no_check;
q = ob->quota_warn_threshold;
break;
@@ -630,7 +655,7 @@ for (h = &host; h; h = h->next)
/* Connect never fails for a UDP socket, so don't set a timeout. */
- (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0, FALSE);
+ (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0, NULL);
rc = send(sock, buffer, Ustrlen(buffer) + 1, 0);
(void)close(sock);
@@ -916,6 +941,9 @@ copy_mbx_message(int to_fd, int from_fd, off_t saved_size)
int used;
off_t size;
struct stat statbuf;
+transport_ctx tctx = {{0}};
+
+tctx.u.fd = to_fd;
/* If the current mailbox size is zero, write a header block */
@@ -928,7 +956,7 @@ if (saved_size == 0)
(long int)time(NULL));
for (i = 0; i < MBX_NUSERFLAGS; i++)
sprintf (CS(s += Ustrlen(s)), "\015\012");
- if (!transport_write_block (to_fd, deliver_out_buffer, MBX_HDRSIZE))
+ if (!transport_write_block (&tctx, deliver_out_buffer, MBX_HDRSIZE, FALSE))
return DEFER;
}
@@ -946,7 +974,7 @@ used = Ustrlen(deliver_out_buffer);
/* Rewind the temporary file, and copy it over in chunks. */
-lseek(from_fd, 0 , SEEK_SET);
+if (lseek(from_fd, 0 , SEEK_SET) < 0) return DEFER;
while (size > 0)
{
@@ -957,7 +985,7 @@ while (size > 0)
if (len == 0) errno = ERRNO_MBXLENGTH;
return DEFER;
}
- if (!transport_write_block(to_fd, deliver_out_buffer, used + len))
+ if (!transport_write_block(&tctx, deliver_out_buffer, used + len, FALSE))
return DEFER;
size -= len;
used = 0;
@@ -1380,10 +1408,13 @@ else
DEBUG(D_transport)
{
debug_printf("appendfile: mode=%o notify_comsat=%d quota=" OFF_T_FMT
+ "%s%s"
" warning=" OFF_T_FMT "%s\n"
" %s=%s format=%s\n message_prefix=%s\n message_suffix=%s\n "
"maildir_use_size_file=%s\n",
mode, ob->notify_comsat, ob->quota_value,
+ ob->quota_no_check? " (no_check)" : "",
+ ob->quota_filecount_no_check? " (no_check_filecount)" : "",
ob->quota_warn_threshold_value,
ob->quota_warn_threshold_is_percent? "%" : "",
isdirectory? "directory" : "file",
@@ -2774,21 +2805,33 @@ if (!disable_quota && ob->quota_value > 0)
debug_printf(" file count quota = %d count = %d\n",
ob->quota_filecount_value, mailbox_filecount);
}
+
if (mailbox_size + (ob->quota_is_inclusive? message_size:0) > ob->quota_value)
{
- DEBUG(D_transport) debug_printf("mailbox quota exceeded\n");
- yield = DEFER;
- errno = ERRNO_EXIMQUOTA;
- }
- else if (ob->quota_filecount_value > 0 &&
- mailbox_filecount + (ob->quota_is_inclusive ? 1:0) >
- ob->quota_filecount_value)
- {
- DEBUG(D_transport) debug_printf("mailbox file count quota exceeded\n");
- yield = DEFER;
- errno = ERRNO_EXIMQUOTA;
- filecount_msg = US" filecount";
+
+ if (!ob->quota_no_check)
+ {
+ DEBUG(D_transport) debug_printf("mailbox quota exceeded\n");
+ yield = DEFER;
+ errno = ERRNO_EXIMQUOTA;
+ }
+ else DEBUG(D_transport) debug_printf("mailbox quota exceeded but ignored\n");
+
}
+
+ if (ob->quota_filecount_value > 0
+ && mailbox_filecount + (ob->quota_is_inclusive ? 1:0) >
+ ob->quota_filecount_value)
+ if(!ob->quota_filecount_no_check)
+ {
+ DEBUG(D_transport) debug_printf("mailbox file count quota exceeded\n");
+ yield = DEFER;
+ errno = ERRNO_EXIMQUOTA;
+ filecount_msg = US" filecount";
+ }
+ else DEBUG(D_transport) if (ob->quota_filecount_no_check)
+ debug_printf("mailbox file count quota exceeded but ignored\n");
+
}
/* If we are writing in MBX format, what we actually do is to write the message
@@ -2874,13 +2917,14 @@ at initialization time. */
if (yield == OK)
{
transport_ctx tctx = {
+ {fd},
tblock,
addr,
ob->check_string,
ob->escape_string,
ob->options
};
- if (!transport_write_message(fd, &tctx, 0))
+ if (!transport_write_message(&tctx, 0))
yield = DEFER;
}
@@ -3373,4 +3417,5 @@ put in the first address of a batch. */
return FALSE;
}
+#endif /*!MACRO_PREDEF*/
/* End of transport/appendfile.c */
diff --git a/src/src/transports/appendfile.h b/src/src/transports/appendfile.h
index 52dc3baca..70330857d 100644
--- a/src/src/transports/appendfile.h
+++ b/src/src/transports/appendfile.h
@@ -70,6 +70,8 @@ typedef struct {
BOOL mbx_format;
BOOL quota_warn_threshold_is_percent;
BOOL quota_is_inclusive;
+ BOOL quota_no_check;
+ BOOL quota_filecount_no_check;
} appendfile_transport_options_block;
/* Restricted creation options */
diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c
index f07cd83cf..9f6e2acaf 100644
--- a/src/src/transports/autoreply.c
+++ b/src/src/transports/autoreply.c
@@ -62,6 +62,17 @@ address can appear in the tables drtables.c. */
int autoreply_transport_options_count =
sizeof(autoreply_transport_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+autoreply_transport_options_block autoreply_transport_option_defaults = {0};
+void autoreply_transport_init(transport_instance *tblock) {}
+BOOL autoreply_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the autoreply transport. */
autoreply_transport_options_block autoreply_transport_option_defaults = {
@@ -335,33 +346,22 @@ else
file_expand = ob->file_expand;
return_message = ob->return_message;
- if ((from != NULL &&
- (from = checkexpand(from, addr, tblock->name, cke_hdr)) == NULL) ||
- (reply_to != NULL &&
- (reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr)) == NULL) ||
- (to != NULL &&
- (to = checkexpand(to, addr, tblock->name, cke_hdr)) == NULL) ||
- (cc != NULL &&
- (cc = checkexpand(cc, addr, tblock->name, cke_hdr)) == NULL) ||
- (bcc != NULL &&
- (bcc = checkexpand(bcc, addr, tblock->name, cke_hdr)) == NULL) ||
- (subject != NULL &&
- (subject = checkexpand(subject, addr, tblock->name, cke_hdr)) == NULL) ||
- (headers != NULL &&
- (headers = checkexpand(headers, addr, tblock->name, cke_text)) == NULL) ||
- (text != NULL &&
- (text = checkexpand(text, addr, tblock->name, cke_text)) == NULL) ||
- (file != NULL &&
- (file = checkexpand(file, addr, tblock->name, cke_file)) == NULL) ||
- (logfile != NULL &&
- (logfile = checkexpand(logfile, addr, tblock->name, cke_file)) == NULL) ||
- (oncelog != NULL &&
- (oncelog = checkexpand(oncelog, addr, tblock->name, cke_file)) == NULL) ||
- (oncerepeat != NULL &&
- (oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file)) == NULL))
+ if ( from && !(from = checkexpand(from, addr, tblock->name, cke_hdr))
+ || reply_to && !(reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr))
+ || to && !(to = checkexpand(to, addr, tblock->name, cke_hdr))
+ || cc && !(cc = checkexpand(cc, addr, tblock->name, cke_hdr))
+ || bcc && !(bcc = checkexpand(bcc, addr, tblock->name, cke_hdr))
+ || subject && !(subject = checkexpand(subject, addr, tblock->name, cke_hdr))
+ || headers && !(headers = checkexpand(headers, addr, tblock->name, cke_text))
+ || text && !(text = checkexpand(text, addr, tblock->name, cke_text))
+ || file && !(file = checkexpand(file, addr, tblock->name, cke_file))
+ || logfile && !(logfile = checkexpand(logfile, addr, tblock->name, cke_file))
+ || oncelog && !(oncelog = checkexpand(oncelog, addr, tblock->name, cke_file))
+ || oncerepeat && !(oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file))
+ )
return FALSE;
- if (oncerepeat != NULL)
+ if (oncerepeat)
{
once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE);
if (once_repeat_sec < 0)
@@ -377,11 +377,11 @@ else
/* If the never_mail option is set, we have to scan all the recipients and
remove those that match. */
-if (ob->never_mail != NULL)
+if (ob->never_mail)
{
const uschar *never_mail = expand_string(ob->never_mail);
- if (never_mail == NULL)
+ if (!never_mail)
{
addr->transport_return = FAIL;
addr->message = string_sprintf("Failed to expand \"%s\" for "
@@ -389,11 +389,11 @@ if (ob->never_mail != NULL)
return FALSE;
}
- if (to != NULL) check_never_mail(&to, never_mail);
- if (cc != NULL) check_never_mail(&cc, never_mail);
- if (bcc != NULL) check_never_mail(&bcc, never_mail);
+ if (to) check_never_mail(&to, never_mail);
+ if (cc) check_never_mail(&cc, never_mail);
+ if (bcc) check_never_mail(&bcc, never_mail);
- if (to == NULL && cc == NULL && bcc == NULL)
+ if (!to && !cc && !bcc)
{
DEBUG(D_transport)
debug_printf("*** all recipients removed by never_mail\n");
@@ -419,7 +419,7 @@ recipient, the effect might not be quite as envisaged. If once_file_size is
set, instead of a dbm file, we use a regular file containing a circular buffer
recipient cache. */
-if (oncelog != NULL && *oncelog != 0 && to != NULL)
+if (oncelog && *oncelog != 0 && to)
{
time_t then = 0;
@@ -427,7 +427,7 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
if (ob->once_file_size > 0)
{
- uschar *p;
+ uschar * p, * nextp;
struct stat statbuf;
cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode);
@@ -464,18 +464,16 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
zero. If we find a match, put the time into "then", and the place where it
was found into "cache_time". Otherwise, "then" is left at zero. */
- p = cache_buff;
- while (p < cache_buff + cache_size)
+ for (p = cache_buff; p < cache_buff + cache_size; p = nextp)
{
uschar *s = p + sizeof(time_t);
- uschar *nextp = s + Ustrlen(s) + 1;
+ nextp = s + Ustrlen(s) + 1;
if (Ustrcmp(to, s) == 0)
{
memcpy(&then, p, sizeof(time_t));
cache_time = p;
break;
}
- p = nextp;
}
}
@@ -484,8 +482,12 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
else
{
EXIM_DATUM key_datum, result_datum;
- EXIM_DBOPEN(oncelog, O_RDWR|O_CREAT, ob->mode, &dbm_file);
- if (dbm_file == NULL)
+ uschar * dirname = string_copy(oncelog);
+ uschar * s;
+
+ if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
+ EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
+ if (!dbm_file)
{
addr->transport_return = DEFER;
addr->message = string_sprintf("Failed to open %s file %s when sending "
@@ -509,10 +511,9 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
can be abolished. */
if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t))
- {
memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t));
- }
- else then = now;
+ else
+ then = now;
}
}
@@ -544,10 +545,10 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
/* We are going to send a message. Ensure any requested file is available. */
-if (file != NULL)
+if (file)
{
ff = Ufopen(file, "rb");
- if (ff == NULL && !ob->file_optional)
+ if (!ff && !ob->file_optional)
{
addr->transport_return = DEFER;
addr->message = string_sprintf("Failed to open file %s when sending "
@@ -568,6 +569,7 @@ if (pid < 0)
addr->message = string_sprintf("Failed to create child process to send "
"message from %s transport: %s", tblock->name, strerror(errno));
DEBUG(D_transport) debug_printf("%s\n", addr->message);
+ if (dbm_file) EXIM_DBCLOSE(dbm_file);
return FALSE;
}
@@ -577,20 +579,20 @@ are newlines in it which might, if placed earlier, screw up other headers. */
f = fdopen(fd, "wb");
-if (from != NULL) fprintf(f, "From: %s\n", from);
-if (reply_to != NULL) fprintf(f, "Reply-To: %s\n", reply_to);
-if (to != NULL) fprintf(f, "To: %s\n", to);
-if (cc != NULL) fprintf(f, "Cc: %s\n", cc);
-if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc);
-if (subject != NULL) fprintf(f, "Subject: %s\n", subject);
+if (from) fprintf(f, "From: %s\n", from);
+if (reply_to) fprintf(f, "Reply-To: %s\n", reply_to);
+if (to) fprintf(f, "To: %s\n", to);
+if (cc) fprintf(f, "Cc: %s\n", cc);
+if (bcc) fprintf(f, "Bcc: %s\n", bcc);
+if (subject) fprintf(f, "Subject: %s\n", subject);
/* Generate In-Reply-To from the message_id header; there should
always be one, but code defensively. */
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
if (h->type == htype_id) break;
-if (h != NULL)
+if (h)
{
message_id = Ustrchr(h->text, ':') + 1;
while (isspace(*message_id)) message_id++;
@@ -600,12 +602,12 @@ if (h != NULL)
/* Generate a References header if there is at least one of Message-ID:,
References:, or In-Reply-To: (see RFC 2822). */
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
if (h->type != htype_old && strncmpic(US"References:", h->text, 11) == 0)
break;
-if (h == NULL)
- for (h = header_list; h != NULL; h = h->next)
+if (!h)
+ for (h = header_list; h; h = h->next)
if (h->type != htype_old && strncmpic(US"In-Reply-To:", h->text, 12) == 0)
break;
@@ -614,10 +616,10 @@ limit, some systems do not like headers growing beyond recognition.
Keep the first message ID for the thread root and the last few for
the position inside the thread, up to a maximum of 12 altogether. */
-if (h != NULL || message_id != NULL)
+if (h || message_id)
{
fprintf(f, "References:");
- if (h != NULL)
+ if (h)
{
uschar *s, *id, *error;
uschar *referenced_ids[12];
@@ -628,7 +630,7 @@ if (h != NULL || message_id != NULL)
parse_allow_group = FALSE;
while (*s != 0 && (s = parse_message_id(s, &id, &error)) != NULL)
{
- if (reference_count == sizeof(referenced_ids)/sizeof(uschar *))
+ if (reference_count == nelem(referenced_ids))
{
memmove(referenced_ids + 1, referenced_ids + 2,
sizeof(referenced_ids) - 2*sizeof(uschar *));
@@ -641,8 +643,8 @@ if (h != NULL || message_id != NULL)
/* The message id will have a newline on the end of it. */
- if (message_id != NULL) fprintf(f, " %s", message_id);
- else fprintf(f, "\n");
+ if (message_id) fprintf(f, " %s", message_id);
+ else fprintf(f, "\n");
}
/* Add an Auto-Submitted: header */
@@ -651,16 +653,16 @@ fprintf(f, "Auto-Submitted: auto-replied\n");
/* Add any specially requested headers */
-if (headers != NULL) fprintf(f, "%s\n", headers);
+if (headers) fprintf(f, "%s\n", headers);
fprintf(f, "\n");
-if (text != NULL)
+if (text)
{
fprintf(f, "%s", CS text);
if (text[Ustrlen(text)-1] != '\n') fprintf(f, "\n");
}
-if (ff != NULL)
+if (ff)
{
while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
{
@@ -669,11 +671,11 @@ if (ff != NULL)
uschar *s = expand_string(big_buffer);
DEBUG(D_transport)
{
- if (s == NULL)
+ if (!s)
debug_printf("error while expanding line from file:\n %s\n %s\n",
big_buffer, expand_string_message);
}
- fprintf(f, "%s", (s == NULL)? CS big_buffer : CS s);
+ fprintf(f, "%s", s ? CS s : CS big_buffer);
}
else fprintf(f, "%s", CS big_buffer);
}
@@ -692,6 +694,7 @@ if (return_message)
:
US"------ This is a copy of the message, including all the headers.\n";
transport_ctx tctx = {
+ {fileno(f)},
tblock,
addr,
NULL, NULL,
@@ -720,7 +723,7 @@ if (return_message)
fflush(f);
transport_count = 0;
- transport_write_message(fileno(f), &tctx, bounce_return_size_limit);
+ transport_write_message(&tctx, bounce_return_size_limit);
}
/* End the message and wait for the child process to end; no timeout. */
@@ -744,30 +747,32 @@ if (cache_fd >= 0)
{
uschar *from = cache_buff;
int size = cache_size;
- (void)lseek(cache_fd, 0, SEEK_SET);
- if (cache_time == NULL)
+ if (lseek(cache_fd, 0, SEEK_SET) == 0)
{
- cache_time = from + size;
- memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
- size += add_size;
-
- if (cache_size > 0 && size > ob->once_file_size)
+ if (!cache_time)
{
- from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
- size -= (from - cache_buff);
+ cache_time = from + size;
+ memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
+ size += add_size;
+
+ if (cache_size > 0 && size > ob->once_file_size)
+ {
+ from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
+ size -= (from - cache_buff);
+ }
}
- }
- memcpy(cache_time, &now, sizeof(time_t));
- if(write(cache_fd, from, size) != size)
- DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
- "transport\n", oncelog, tblock->name);
+ memcpy(cache_time, &now, sizeof(time_t));
+ if(write(cache_fd, from, size) != size)
+ DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
+ "transport\n", oncelog, tblock->name);
+ }
}
/* Update DBM file */
-else if (dbm_file != NULL)
+else if (dbm_file)
{
EXIM_DATUM key_datum, value_datum;
EXIM_DATUM_INIT(key_datum); /* Some DBM libraries need to have */
@@ -789,7 +794,6 @@ try will skip, of course. However, if there were no recipients in the
message, we do not fail. */
if (rc != 0)
- {
if (rc == EXIT_NORECIPIENTS)
{
DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n",
@@ -802,7 +806,6 @@ if (rc != 0)
"transport (%d)", tblock->name, rc);
goto END_OFF;
}
- }
/* Log the sending of the message if successful and required. If the file
fails to open, it's hard to know what to do. We cannot write to the Exim
@@ -813,7 +816,7 @@ file opened for appending, in order to avoid interleaving of output from
different processes. The log_buffer can be used exactly as for main log
writing. */
-if (logfile != NULL)
+if (logfile)
{
int log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode);
if (log_fd >= 0)
@@ -822,37 +825,37 @@ if (logfile != NULL)
DEBUG(D_transport) debug_printf("logging message details\n");
sprintf(CS ptr, "%s\n", tod_stamp(tod_log));
while(*ptr) ptr++;
- if (from != NULL)
+ if (from)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" From: %s\n", from);
while(*ptr) ptr++;
}
- if (to != NULL)
+ if (to)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" To: %s\n", to);
while(*ptr) ptr++;
}
- if (cc != NULL)
+ if (cc)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" Cc: %s\n", cc);
while(*ptr) ptr++;
}
- if (bcc != NULL)
+ if (bcc)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" Bcc: %s\n", bcc);
while(*ptr) ptr++;
}
- if (subject != NULL)
+ if (subject)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" Subject: %s\n", subject);
while(*ptr) ptr++;
}
- if (headers != NULL)
+ if (headers)
{
(void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
" %s\n", headers);
@@ -868,7 +871,7 @@ if (logfile != NULL)
}
END_OFF:
-if (dbm_file != NULL) EXIM_DBCLOSE(dbm_file);
+if (dbm_file) EXIM_DBCLOSE(dbm_file);
if (cache_fd > 0) (void)close(cache_fd);
DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
@@ -876,4 +879,5 @@ DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
return FALSE;
}
+#endif /*!MACRO_PREDEF*/
/* End of transport/autoreply.c */
diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c
index c4606ef8b..f26050fdc 100644
--- a/src/src/transports/lmtp.c
+++ b/src/src/transports/lmtp.c
@@ -40,6 +40,17 @@ address can appear in the tables drtables.c. */
int lmtp_transport_options_count =
sizeof(lmtp_transport_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+lmtp_transport_options_block lmtp_transport_option_defaults = {0};
+void lmtp_transport_init(transport_instance *tblock) {}
+BOOL lmtp_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the lmtp transport. */
lmtp_transport_options_block lmtp_transport_option_defaults = {
@@ -610,6 +621,7 @@ if (send_data)
{
BOOL ok;
transport_ctx tctx = {
+ {fd_in},
tblock,
addrlist,
US".", US"..",
@@ -634,7 +646,7 @@ if (send_data)
debug_printf(" LMTP>> writing message and terminating \".\"\n");
transport_count = 0;
- ok = transport_write_message(fd_in, &tctx, 0);
+ ok = transport_write_message(&tctx, 0);
/* Failure can either be some kind of I/O disaster (including timeout),
or the failure of a transport filter or the expansion of added headers. */
@@ -663,7 +675,7 @@ if (send_data)
{
const uschar *s = string_printing(buffer);
/* de-const safe here as string_printing known to have alloc'n'copied */
- addr->message = (s == buffer)? (uschar *)string_copy(s) : US s;
+ addr->message = (s == buffer)? US string_copy(s) : US s;
}
}
/* If the response has failed badly, use it for all the remaining pending
@@ -790,4 +802,5 @@ MINUS_N:
return FALSE;
}
+#endif /*!MACRO_PREDEF*/
/* End of transport/lmtp.c */
diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c
index 8b87e4a95..be0256061 100644
--- a/src/src/transports/pipe.c
+++ b/src/src/transports/pipe.c
@@ -95,6 +95,17 @@ address can appear in the tables drtables.c. */
int pipe_transport_options_count =
sizeof(pipe_transport_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+pipe_transport_options_block pipe_transport_option_defaults = {0};
+void pipe_transport_init(transport_instance *tblock) {}
+BOOL pipe_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the pipe transport. */
pipe_transport_options_block pipe_transport_option_defaults = {
@@ -516,7 +527,7 @@ if (expand_arguments)
}
else argv[2] = cmd;
-argv[3] = (uschar *)0;
+argv[3] = US 0;
return TRUE;
}
@@ -552,6 +563,7 @@ const uschar *envlist = ob->environment;
uschar *cmd, *ss;
uschar *eol = ob->use_crlf ? US"\r\n" : US"\n";
transport_ctx tctx = {
+ {0},
tblock,
addr,
ob->check_string,
@@ -684,10 +696,9 @@ if (envlist)
}
}
-while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size))
- != NULL)
+while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size)))
{
- if (envcount > sizeof(envp)/sizeof(uschar *) - 2)
+ if (envcount > nelem(envp) - 2)
{
addr->transport_return = DEFER;
addr->message = string_sprintf("too many environment settings for "
@@ -739,6 +750,7 @@ if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0)
strerror(errno));
return FALSE;
}
+tctx.u.fd = fd_in;
/* Now fork a process to handle the output that comes down the pipe. */
@@ -829,7 +841,7 @@ if (ob->message_prefix != NULL)
expand_string_message);
return FALSE;
}
- if (!transport_write_block(fd_in, prefix, Ustrlen(prefix)))
+ if (!transport_write_block(&tctx, prefix, Ustrlen(prefix), FALSE))
goto END_WRITE;
}
@@ -857,7 +869,7 @@ if (ob->use_bsmtp)
/* Now the actual message */
-if (!transport_write_message(fd_in, &tctx, 0))
+if (!transport_write_message(&tctx, 0))
goto END_WRITE;
/* Now any configured suffix */
@@ -873,7 +885,7 @@ if (ob->message_suffix)
expand_string_message);
return FALSE;
}
- if (!transport_write_block(fd_in, suffix, Ustrlen(suffix)))
+ if (!transport_write_block(&tctx, suffix, Ustrlen(suffix), FALSE))
goto END_WRITE;
}
@@ -1150,4 +1162,5 @@ if (addr->transport_return != OK)
return FALSE;
}
+#endif /*!MACRO_PREDEF*/
/* End of transport/pipe.c */
diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c
index 7f10706c1..bc4ed3f40 100644
--- a/src/src/transports/queuefile.c
+++ b/src/src/transports/queuefile.c
@@ -20,12 +20,25 @@ optionlist queuefile_transport_options[] = {
(void *)offsetof(queuefile_transport_options_block, dirname) },
};
+
/* Size of the options list. An extern variable has to be used so that its
address can appear in the tables drtables.c. */
int queuefile_transport_options_count =
sizeof(queuefile_transport_options) / sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+queuefile_transport_options_block queuefile_transport_option_defaults = {0};
+void queuefile_transport_init(transport_instance *tblock) {}
+BOOL queuefile_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else /*!MACRO_PREDEF*/
+
+
+
/* Default private options block for the appendfile transport. */
queuefile_transport_options_block queuefile_transport_option_defaults = {
@@ -254,3 +267,5 @@ if (sdfd >= 0) (void) close(sdfd);
put in the first address of a batch. */
return FALSE;
}
+
+#endif /*!MACRO_PREDEF*/
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 52e04b8a5..461b26c4a 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -43,6 +43,10 @@ optionlist smtp_transport_options[] = {
(void *)offsetof(smtp_transport_options_block, dkim.dkim_canon) },
{ "dkim_domain", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, dkim.dkim_domain) },
+ { "dkim_hash", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, dkim.dkim_hash) },
+ { "dkim_identity", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, dkim.dkim_identity) },
{ "dkim_private_key", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, dkim.dkim_private_key) },
{ "dkim_selector", opt_stringptr,
@@ -186,88 +190,104 @@ address can appear in the tables drtables.c. */
int smtp_transport_options_count =
sizeof(smtp_transport_options)/sizeof(optionlist);
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+smtp_transport_options_block smtp_transport_option_defaults = {0};
+void smtp_transport_init(transport_instance *tblock) {}
+BOOL smtp_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+void smtp_transport_closedown(transport_instance *tblock) {}
+
+#else /*!MACRO_PREDEF*/
+
+
/* Default private options block for the smtp transport. */
smtp_transport_options_block smtp_transport_option_defaults = {
- NULL, /* hosts */
- NULL, /* fallback_hosts */
- NULL, /* hostlist */
- NULL, /* fallback_hostlist */
- NULL, /* authenticated_sender */
- US"$primary_hostname", /* helo_data */
- NULL, /* interface */
- NULL, /* port */
- US"smtp", /* protocol */
- NULL, /* DSCP */
- NULL, /* serialize_hosts */
- NULL, /* hosts_try_auth */
- NULL, /* hosts_require_auth */
- US"*", /* hosts_try_chunking */
+ .hosts = NULL,
+ .hosts = NULL,
+ .hostlist = NULL,
+ .fallback_hostlist = NULL,
+ .authenticated_sender = NULL,
+ .helo_data = US"$primary_hostname",
+ .interface = NULL,
+ .port = NULL,
+ .protocol = US"smtp",
+ .dscp = NULL,
+ .serialize_hosts = NULL,
+ .hosts_try_auth = NULL,
+ .hosts_require_auth = NULL,
+ .hosts_try_chunking = US"*",
#ifdef EXPERIMENTAL_DANE
- NULL, /* hosts_try_dane */
- NULL, /* hosts_require_dane */
+ .hosts_try_dane = NULL,
+ .hosts_require_dane = NULL,
#endif
- NULL, /* hosts_try_fastopen */
+ .hosts_try_fastopen = NULL,
#ifndef DISABLE_PRDR
- US"*", /* hosts_try_prdr */
+ .hosts_try_prdr = US"*",
#endif
#ifndef DISABLE_OCSP
- US"*", /* hosts_request_ocsp (except under DANE; tls_client_start()) */
- NULL, /* hosts_require_ocsp */
+ .hosts_request_ocsp = US"*", /* hosts_request_ocsp (except under DANE; tls_client_start()) */
+ .hosts_require_ocsp = NULL,
+#endif
+ .hosts_require_tls = NULL,
+ .hosts_avoid_tls = NULL,
+ .hosts_verify_avoid_tls = NULL,
+ .hosts_avoid_pipelining = NULL,
+ .hosts_avoid_esmtp = NULL,
+#ifdef SUPPORT_TLS
+ .hosts_nopass_tls = NULL,
+ .hosts_noproxy_tls = US"*",
#endif
- NULL, /* hosts_require_tls */
- NULL, /* hosts_avoid_tls */
- NULL, /* hosts_verify_avoid_tls */
- NULL, /* hosts_avoid_pipelining */
- NULL, /* hosts_avoid_esmtp */
- NULL, /* hosts_nopass_tls */
- US"*", /* hosts_noproxy_tls */
- 5*60, /* command_timeout */
- 5*60, /* connect_timeout; shorter system default overrides */
- 5*60, /* data timeout */
- 10*60, /* final timeout */
- 1024, /* size_addition */
- 5, /* hosts_max_try */
- 50, /* hosts_max_try_hardlimit */
- TRUE, /* address_retry_include_sender */
- FALSE, /* allow_localhost */
- FALSE, /* authenticated_sender_force */
- FALSE, /* gethostbyname */
- TRUE, /* dns_qualify_single */
- FALSE, /* dns_search_parents */
- { NULL, NULL }, /* dnssec_domains {request,require} */
- TRUE, /* delay_after_cutoff */
- FALSE, /* hosts_override */
- FALSE, /* hosts_randomize */
- TRUE, /* keepalive */
- FALSE, /* lmtp_ignore_quota */
- NULL, /* expand_retry_include_ip_address */
- TRUE /* retry_include_ip_address */
+ .command_timeout = 5*60,
+ .connect_timeout = 5*60,
+ .data_timeout = 5*60,
+ .final_timeout = 10*60,
+ .size_addition = 1024,
+ .hosts_max_try = 5,
+ .hosts_max_try_hardlimit = 50,
+ .address_retry_include_sender = TRUE,
+ .allow_localhost = FALSE,
+ .authenticated_sender_force = FALSE,
+ .gethostbyname = FALSE,
+ .dns_qualify_single = TRUE,
+ .dns_search_parents = FALSE,
+ .dnssec = { .request=NULL, .require=NULL },
+ .delay_after_cutoff = TRUE,
+ .hosts_override = FALSE,
+ .hosts_randomize = FALSE,
+ .keepalive = TRUE,
+ .lmtp_ignore_quota = FALSE,
+ .expand_retry_include_ip_address = NULL,
+ .retry_include_ip_address = TRUE,
#ifdef SUPPORT_SOCKS
- ,NULL /* socks_proxy */
+ .socks_proxy = NULL,
#endif
#ifdef SUPPORT_TLS
- ,NULL, /* tls_certificate */
- NULL, /* tls_crl */
- NULL, /* tls_privatekey */
- NULL, /* tls_require_ciphers */
- NULL, /* tls_sni */
- US"system", /* tls_verify_certificates */
- EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
- /* tls_dh_min_bits */
- TRUE, /* tls_tempfail_tryclear */
- NULL, /* tls_verify_hosts */
- US"*", /* tls_try_verify_hosts */
- US"*" /* tls_verify_cert_hostnames */
+ .tls_certificate = NULL,
+ .tls_crl = NULL,
+ .tls_privatekey = NULL,
+ .tls_require_ciphers = NULL,
+ .tls_sni = NULL,
+ .tls_verify_certificates = US"system",
+ .tls_dh_min_bits = EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
+ .tls_tempfail_tryclear = TRUE,
+ .tls_verify_hosts = NULL,
+ .tls_try_verify_hosts = US"*",
+ .tls_verify_cert_hostnames = US"*",
#endif
#ifndef DISABLE_DKIM
- , {NULL, /* dkim_canon */
- NULL, /* dkim_domain */
- NULL, /* dkim_private_key */
- NULL, /* dkim_selector */
- NULL, /* dkim_sign_headers */
- NULL, /* dkim_strict */
- FALSE} /* dot_stuffed */
+ .dkim =
+ {.dkim_domain = NULL,
+ .dkim_identity = NULL,
+ .dkim_private_key = NULL,
+ .dkim_selector = NULL,
+ .dkim_canon = NULL,
+ .dkim_sign_headers = NULL,
+ .dkim_strict = NULL,
+ .dkim_hash = US"sha256",
+ .dot_stuffed = FALSE},
#endif
};
@@ -794,7 +814,9 @@ with an address by scanning for the next address whose status is PENDING_DEFER.
while (count-- > 0)
{
- while (addr->transport_return != PENDING_DEFER) addr = addr->next;
+ while (addr->transport_return != PENDING_DEFER)
+ if (!(addr = addr->next))
+ return -2;
/* The address was accepted */
addr->host_used = sx->host;
@@ -1002,7 +1024,7 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
If one is found, attempt to authenticate by calling its client function.
*/
- for (au = auths; !smtp_authenticated && au != NULL; au = au->next)
+ for (au = auths; !smtp_authenticated && au; au = au->next)
{
uschar *p = names;
if (!au->client ||
@@ -1019,7 +1041,7 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
/* Loop to scan supported server mechanisms */
- while (*p != 0)
+ while (*p)
{
int rc;
int len = Ustrlen(au->public_name);
@@ -1182,20 +1204,24 @@ tlsa_lookup(const host_item * host, dns_answer * dnsa, BOOL dane_required)
/* move this out to host.c given the similarity to dns_lookup() ? */
uschar buffer[300];
const uschar * fullname = buffer;
+int rc;
+BOOL sec;
/* TLSA lookup string */
(void)sprintf(CS buffer, "_%d._tcp.%.256s", host->port, host->name);
-switch (dns_lookup(dnsa, buffer, T_TLSA, &fullname))
+rc = dns_lookup(dnsa, buffer, T_TLSA, &fullname);
+sec = dns_is_secure(dnsa);
+DEBUG(D_transport)
+ debug_printf("TLSA lookup ret %d %sDNSSEC\n", rc, sec ? "" : "not ");
+
+switch (rc)
{
case DNS_SUCCEED:
- if (!dns_is_secure(dnsa))
- {
- log_write(0, LOG_MAIN, "DANE error: TLSA lookup not DNSSEC");
- return DEFER;
- }
- return OK;
+ if (sec) return OK;
+ log_write(0, LOG_MAIN, "DANE error: TLSA lookup not DNSSEC");
+ /*FALLTHROUGH*/
case DNS_AGAIN:
return DEFER; /* just defer this TLS'd conn */
@@ -1296,44 +1322,44 @@ ehlo_response(uschar * buf, uschar checks)
size_t bsize = Ustrlen(buf);
#ifdef SUPPORT_TLS
-if ( checks & PEER_OFFERED_TLS
+if ( checks & OPTION_TLS
&& pcre_exec(regex_STARTTLS, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_TLS;
+ checks &= ~OPTION_TLS;
#endif
-if ( checks & PEER_OFFERED_IGNQ
+if ( checks & OPTION_IGNQ
&& pcre_exec(regex_IGNOREQUOTA, NULL, CS buf, bsize, 0,
PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_IGNQ;
+ checks &= ~OPTION_IGNQ;
-if ( checks & PEER_OFFERED_CHUNKING
+if ( checks & OPTION_CHUNKING
&& pcre_exec(regex_CHUNKING, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_CHUNKING;
+ checks &= ~OPTION_CHUNKING;
#ifndef DISABLE_PRDR
-if ( checks & PEER_OFFERED_PRDR
+if ( checks & OPTION_PRDR
&& pcre_exec(regex_PRDR, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_PRDR;
+ checks &= ~OPTION_PRDR;
#endif
#ifdef SUPPORT_I18N
-if ( checks & PEER_OFFERED_UTF8
+if ( checks & OPTION_UTF8
&& pcre_exec(regex_UTF8, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_UTF8;
+ checks &= ~OPTION_UTF8;
#endif
-if ( checks & PEER_OFFERED_DSN
+if ( checks & OPTION_DSN
&& pcre_exec(regex_DSN, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_DSN;
+ checks &= ~OPTION_DSN;
-if ( checks & PEER_OFFERED_PIPE
+if ( checks & OPTION_PIPE
&& pcre_exec(regex_PIPELINING, NULL, CS buf, bsize, 0,
PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_PIPE;
+ checks &= ~OPTION_PIPE;
-if ( checks & PEER_OFFERED_SIZE
+if ( checks & OPTION_SIZE
&& pcre_exec(regex_SIZE, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
- checks &= ~PEER_OFFERED_SIZE;
+ checks &= ~OPTION_SIZE;
return checks;
}
@@ -1345,15 +1371,22 @@ return checks;
If given a nonzero size, first flush any buffered SMTP commands
then emit the command.
-Reap previous SMTP command responses if requested.
-Reap one SMTP command response if requested.
+Reap previous SMTP command responses if requested, and always reap
+the response from a previous BDAT command.
+
+Args:
+ tctx transport context
+ chunk_size value for SMTP BDAT command
+ flags
+ tc_chunk_last add LAST option to SMTP BDAT command
+ tc_reap_prev reap response to previous SMTP commands
Returns: OK or ERROR
*/
static int
-smtp_chunk_cmd_callback(int fd, transport_ctx * tctx,
- unsigned chunk_size, unsigned flags)
+smtp_chunk_cmd_callback(transport_ctx * tctx, unsigned chunk_size,
+ unsigned flags)
{
smtp_transport_options_block * ob =
(smtp_transport_options_block *)(tctx->tblock->options_block);
@@ -1361,13 +1394,14 @@ smtp_context * sx = tctx->smtp_context;
int cmd_count = 0;
int prev_cmd_count;
-/* Write SMTP chunk header command */
+/* Write SMTP chunk header command. If not reaping responses, note that
+there may be more writes (like, the chunk data) done soon. */
if (chunk_size > 0)
{
- if((cmd_count = smtp_write_command(&sx->outblock, FALSE, "BDAT %u%s\r\n",
- chunk_size,
- flags & tc_chunk_last ? " LAST" : "")
+ if((cmd_count = smtp_write_command(&sx->outblock,
+ flags & tc_reap_prev ? SCMD_FLUSH : SCMD_MORE,
+ "BDAT %u%s\r\n", chunk_size, flags & tc_chunk_last ? " LAST" : "")
) < 0) return ERROR;
if (flags & tc_chunk_last)
data_command = string_copy(big_buffer); /* Save for later error message */
@@ -1484,6 +1518,7 @@ sx->dane_required = verify_check_given_host(&sx->ob->hosts_require_dane, sx->hos
if ((sx->max_rcpt = sx->tblock->max_addresses) == 0) sx->max_rcpt = 999999;
sx->peer_offered = 0;
+sx->avoid_option = 0;
sx->igquotstr = US"";
if (!sx->helo_data) sx->helo_data = sx->ob->helo_data;
#ifdef EXPERIMENTAL_DSN_INFO
@@ -1541,34 +1576,17 @@ if (sx->smtps)
the initial interaction and HELO/EHLO/LHLO. Connect timeout errors are handled
specially so they can be identified for retries. */
-if (continue_hostname == NULL)
+if (!continue_hostname)
{
if (sx->verify)
HDEBUG(D_verify) debug_printf("interface=%s port=%d\n", sx->interface, sx->port);
- /* This puts port into host->port */
- sx->inblock.sock = sx->outblock.sock =
- smtp_connect(sx->host, sx->host_af, sx->port, sx->interface,
- sx->ob->connect_timeout, sx->tblock);
+ /* Get the actual port the connection will use, into sx->host */
- if (sx->inblock.sock < 0)
- {
- uschar * msg = NULL;
- if (sx->verify)
- {
- msg = US strerror(errno);
- HDEBUG(D_verify) debug_printf("connect: %s\n", msg);
- }
- set_errno_nohost(sx->addrlist,
- errno == ETIMEDOUT ? ERRNO_CONNECTTIMEOUT : errno,
- sx->verify ? string_sprintf("could not connect: %s", msg)
- : NULL,
- DEFER, FALSE);
- sx->send_quit = FALSE;
- return DEFER;
- }
+ smtp_port_for_connect(sx->host, sx->port);
#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
+ /* Do TLSA lookup for DANE */
{
tls_out.dane_verified = FALSE;
tls_out.tlsa_usage = 0;
@@ -1580,7 +1598,9 @@ if (continue_hostname == NULL)
)
switch (rc = tlsa_lookup(sx->host, &tlsa_dnsa, sx->dane_required))
{
- case OK: sx->dane = TRUE; break;
+ case OK: sx->dane = TRUE;
+ sx->ob->tls_tempfail_tryclear = FALSE;
+ break;
case FAIL_FORCED: break;
default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: tlsa lookup %s",
@@ -1596,12 +1616,32 @@ if (continue_hostname == NULL)
FAIL, FALSE);
return FAIL;
}
-
- if (sx->dane)
- sx->ob->tls_tempfail_tryclear = FALSE;
}
#endif /*DANE*/
+ /* Make the TCP connection */
+
+ sx->inblock.sock = sx->outblock.sock =
+ smtp_connect(sx->host, sx->host_af, sx->interface,
+ sx->ob->connect_timeout, sx->tblock);
+
+ if (sx->inblock.sock < 0)
+ {
+ uschar * msg = NULL;
+ if (sx->verify)
+ {
+ msg = US strerror(errno);
+ HDEBUG(D_verify) debug_printf("connect: %s\n", msg);
+ }
+ set_errno_nohost(sx->addrlist,
+ errno == ETIMEDOUT ? ERRNO_CONNECTTIMEOUT : errno,
+ sx->verify ? string_sprintf("could not connect: %s", msg)
+ : NULL,
+ DEFER, FALSE);
+ sx->send_quit = FALSE;
+ return DEFER;
+ }
+
/* Expand the greeting message while waiting for the initial response. (Makes
sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
delayed till here so that $sending_interface and $sending_port are set. */
@@ -1720,7 +1760,7 @@ goto SEND_QUIT;
#ifdef SUPPORT_TLS
if (sx->smtps)
{
- smtp_peer_options |= PEER_OFFERED_TLS;
+ smtp_peer_options |= OPTION_TLS;
suppress_tls = FALSE;
sx->ob->tls_tempfail_tryclear = FALSE;
smtp_command = US"SSL-on-connect";
@@ -1730,7 +1770,7 @@ goto SEND_QUIT;
if (sx->esmtp)
{
- if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n",
+ if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n",
sx->lmtp ? "LHLO" : "EHLO", sx->helo_data) < 0)
goto SEND_FAILED;
sx->esmtp_sent = TRUE;
@@ -1763,7 +1803,7 @@ goto SEND_QUIT;
if (sx->esmtp_sent && (n = Ustrlen(sx->buffer)) < sizeof(sx->buffer)/2)
{ rsp = sx->buffer + n + 1; n = sizeof(sx->buffer) - n; }
- if (smtp_write_command(&sx->outblock, FALSE, "HELO %s\r\n", sx->helo_data) < 0)
+ if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "HELO %s\r\n", sx->helo_data) < 0)
goto SEND_FAILED;
good_response = smtp_read_response(&sx->inblock, rsp, n,
'2', sx->ob->command_timeout);
@@ -1785,25 +1825,27 @@ goto SEND_QUIT;
}
}
- sx->peer_offered = smtp_peer_options = 0;
+ sx->avoid_option = sx->peer_offered = smtp_peer_options = 0;
if (sx->esmtp || sx->lmtp)
{
sx->peer_offered = ehlo_response(sx->buffer,
- PEER_OFFERED_TLS /* others checked later */
+ OPTION_TLS /* others checked later */
);
/* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
#ifdef SUPPORT_TLS
- smtp_peer_options |= sx->peer_offered & PEER_OFFERED_TLS;
+ smtp_peer_options |= sx->peer_offered & OPTION_TLS;
#endif
}
}
-/* For continuing deliveries down the same channel, the socket is the standard
-input, and we don't need to redo EHLO here (but may need to do so for TLS - see
-below). Set up the pointer to where subsequent commands will be left, for
+/* For continuing deliveries down the same channel, having re-exec'd the socket
+is the standard input; for a socket held open from verify it is recorded
+in the cutthrough context block. Either way we don't need to redo EHLO here
+(but may need to do so for TLS - see below).
+Set up the pointer to where subsequent commands will be left, for
error messages. Note that smtp_peer_options will have been
set from the command line if they were set in the process that passed the
connection on. */
@@ -1815,19 +1857,30 @@ separate - we could match up by host ip+port as a bodge. */
else
{
- sx->inblock.sock = sx->outblock.sock = 0; /* stdin */
+ if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+ {
+ sx->inblock.sock = sx->outblock.sock = cutthrough.fd;
+ sx->host->port = sx->port = cutthrough.host.port;
+ }
+ else
+ {
+ sx->inblock.sock = sx->outblock.sock = 0; /* stdin */
+ smtp_port_for_connect(sx->host, sx->port); /* Record the port that was used */
+ }
smtp_command = big_buffer;
- sx->host->port = sx->port; /* Record the port that was used */
sx->helo_data = NULL; /* ensure we re-expand ob->helo_data */
- /* For a continued connection with TLS being proxied for us, nothing
- more to do. */
+ /* For a continued connection with TLS being proxied for us, or a
+ held-open verify connection with TLS, nothing more to do. */
- if (continue_proxy)
+ if ( continue_proxy_cipher
+ || (cutthrough.fd >= 0 && cutthrough.callout_hold_only && cutthrough.is_tls)
+ )
{
sx->peer_offered = smtp_peer_options;
- pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE);
- HDEBUG(D_transport) debug_printf("continued connection, proxied TLS\n");
+ pipelining_active = !!(smtp_peer_options & OPTION_PIPE);
+ HDEBUG(D_transport) debug_printf("continued connection, %s TLS\n",
+ continue_proxy_cipher ? "proxied" : "verify conn with");
return OK;
}
HDEBUG(D_transport) debug_printf("continued connection, no TLS\n");
@@ -1842,7 +1895,7 @@ the client not be required to use TLS. If the response is bad, copy the buffer
for error analysis. */
#ifdef SUPPORT_TLS
-if ( smtp_peer_options & PEER_OFFERED_TLS
+if ( smtp_peer_options & OPTION_TLS
&& !suppress_tls
&& verify_check_given_host(&sx->ob->hosts_avoid_tls, sx->host) != OK
&& ( !sx->verify
@@ -1850,7 +1903,7 @@ if ( smtp_peer_options & PEER_OFFERED_TLS
) )
{
uschar buffer2[4096];
- if (smtp_write_command(&sx->outblock, FALSE, "STARTTLS\r\n") < 0)
+ if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "STARTTLS\r\n") < 0)
goto SEND_FAILED;
/* If there is an I/O error, transmission of this message is deferred. If
@@ -1964,7 +2017,7 @@ if (tls_out.active >= 0)
debug_printf("not sending EHLO (host matches hosts_avoid_esmtp)\n");
}
- if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n",
+ if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n",
sx->lmtp ? "LHLO" : greeting_cmd, sx->helo_data) < 0)
goto SEND_FAILED;
good_response = smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer),
@@ -1988,7 +2041,7 @@ else if ( sx->smtps
{
errno = ERRNO_TLSREQUIRED;
message = string_sprintf("a TLS session is required, but %s",
- smtp_peer_options & PEER_OFFERED_TLS
+ smtp_peer_options & OPTION_TLS
? "an attempt to start TLS failed" : "the server did not offer TLS support");
goto TLS_FAILED;
}
@@ -2009,60 +2062,60 @@ if (continue_hostname == NULL
{
sx->peer_offered = ehlo_response(sx->buffer,
0 /* no TLS */
- | (sx->lmtp && sx->ob->lmtp_ignore_quota ? PEER_OFFERED_IGNQ : 0)
- | PEER_OFFERED_CHUNKING
- | PEER_OFFERED_PRDR
+ | (sx->lmtp && sx->ob->lmtp_ignore_quota ? OPTION_IGNQ : 0)
+ | OPTION_CHUNKING
+ | OPTION_PRDR
#ifdef SUPPORT_I18N
- | (sx->addrlist->prop.utf8_msg ? PEER_OFFERED_UTF8 : 0)
+ | (sx->addrlist->prop.utf8_msg ? OPTION_UTF8 : 0)
/*XXX if we hand peercaps on to continued-conn processes,
must not depend on this addr */
#endif
- | PEER_OFFERED_DSN
- | PEER_OFFERED_PIPE
- | (sx->ob->size_addition >= 0 ? PEER_OFFERED_SIZE : 0)
+ | OPTION_DSN
+ | OPTION_PIPE
+ | (sx->ob->size_addition >= 0 ? OPTION_SIZE : 0)
);
/* Set for IGNOREQUOTA if the response to LHLO specifies support and the
lmtp_ignore_quota option was set. */
- sx->igquotstr = sx->peer_offered & PEER_OFFERED_IGNQ ? US" IGNOREQUOTA" : US"";
+ sx->igquotstr = sx->peer_offered & OPTION_IGNQ ? US" IGNOREQUOTA" : US"";
/* If the response to EHLO specified support for the SIZE parameter, note
this, provided size_addition is non-negative. */
- smtp_peer_options |= sx->peer_offered & PEER_OFFERED_SIZE;
+ smtp_peer_options |= sx->peer_offered & OPTION_SIZE;
/* Note whether the server supports PIPELINING. If hosts_avoid_esmtp matched
the current host, esmtp will be false, so PIPELINING can never be used. If
the current host matches hosts_avoid_pipelining, don't do it. */
- if ( sx->peer_offered & PEER_OFFERED_PIPE
+ if ( sx->peer_offered & OPTION_PIPE
&& verify_check_given_host(&sx->ob->hosts_avoid_pipelining, sx->host) != OK)
- smtp_peer_options |= PEER_OFFERED_PIPE;
+ smtp_peer_options |= OPTION_PIPE;
DEBUG(D_transport) debug_printf("%susing PIPELINING\n",
- smtp_peer_options & PEER_OFFERED_PIPE ? "" : "not ");
+ smtp_peer_options & OPTION_PIPE ? "" : "not ");
- if ( sx->peer_offered & PEER_OFFERED_CHUNKING
+ if ( sx->peer_offered & OPTION_CHUNKING
&& verify_check_given_host(&sx->ob->hosts_try_chunking, sx->host) != OK)
- sx->peer_offered &= ~PEER_OFFERED_CHUNKING;
+ sx->peer_offered &= ~OPTION_CHUNKING;
- if (sx->peer_offered & PEER_OFFERED_CHUNKING)
+ if (sx->peer_offered & OPTION_CHUNKING)
{DEBUG(D_transport) debug_printf("CHUNKING usable\n");}
#ifndef DISABLE_PRDR
- if ( sx->peer_offered & PEER_OFFERED_PRDR
+ if ( sx->peer_offered & OPTION_PRDR
&& verify_check_given_host(&sx->ob->hosts_try_prdr, sx->host) != OK)
- sx->peer_offered &= ~PEER_OFFERED_PRDR;
+ sx->peer_offered &= ~OPTION_PRDR;
- if (sx->peer_offered & PEER_OFFERED_PRDR)
+ if (sx->peer_offered & OPTION_PRDR)
{DEBUG(D_transport) debug_printf("PRDR usable\n");}
#endif
/* Note if the server supports DSN */
- smtp_peer_options |= sx->peer_offered & PEER_OFFERED_DSN;
+ smtp_peer_options |= sx->peer_offered & OPTION_DSN;
DEBUG(D_transport) debug_printf("%susing DSN\n",
- sx->peer_offered & PEER_OFFERED_DSN ? "" : "not ");
+ sx->peer_offered & OPTION_DSN ? "" : "not ");
/* Note if the response to EHLO specifies support for the AUTH extension.
If it has, check that this host is one we want to authenticate to, and do
@@ -2079,7 +2132,7 @@ if (continue_hostname == NULL
}
}
}
-pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE);
+pipelining_active = !!(smtp_peer_options & OPTION_PIPE);
/* The setting up of the SMTP call is now complete. Any subsequent errors are
message-specific. */
@@ -2097,7 +2150,7 @@ if (sx->addrlist->prop.utf8_msg)
}
/* If this is an international message we need the host to speak SMTPUTF8 */
-if (sx->utf8_needed && !(sx->peer_offered & PEER_OFFERED_UTF8))
+if (sx->utf8_needed && !(sx->peer_offered & OPTION_UTF8))
{
errno = ERRNO_UTF8_FWD;
goto RESPONSE_FAILED;
@@ -2143,32 +2196,41 @@ return OK;
/* The failure happened while setting up the call; see if the failure was
a 5xx response (this will either be on connection, or following HELO - a 5xx
- after EHLO causes it to try HELO). If so, fail all addresses, as this host is
- never going to accept them. For other errors during setting up (timeouts or
- whatever), defer all addresses, and yield DEFER, so that the host is not
- tried again for a while. */
+ after EHLO causes it to try HELO). If so, and there are no more hosts to try,
+ fail all addresses, as this host is never going to accept them. For other
+ errors during setting up (timeouts or whatever), defer all addresses, and
+ yield DEFER, so that the host is not tried again for a while.
+
+ XXX This peeking for another host feels like a layering violation. We want
+ to note the host as unusable, but down here we shouldn't know if this was
+ the last host to try for the addr(list). Perhaps the upper layer should be
+ the one to do set_errno() ? The problem is that currently the addr is where
+ errno etc. are stashed, but until we run out of hosts to try the errors are
+ host-specific. Maybe we should enhance the host_item definition? */
FAILED:
sx->ok = FALSE; /* For when reached by GOTO */
-
- yield = code == '5'
+ set_errno(sx->addrlist, errno, message,
+ sx->host->next
+ ? DEFER
+ : code == '5'
#ifdef SUPPORT_I18N
- || errno == ERRNO_UTF8_FWD
+ || errno == ERRNO_UTF8_FWD
#endif
- ? FAIL : DEFER;
-
- set_errno(sx->addrlist, errno, message, yield, pass_message, sx->host
+ ? FAIL : DEFER,
+ pass_message, sx->host
#ifdef EXPERIMENTAL_DSN_INFO
, sx->smtp_greeting, sx->helo_response
#endif
);
+ yield = DEFER;
}
SEND_QUIT:
if (sx->send_quit)
- (void)smtp_write_command(&sx->outblock, FALSE, "QUIT\r\n");
+ (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n");
#ifdef SUPPORT_TLS
tls_close(FALSE, TRUE);
@@ -2177,12 +2239,7 @@ tls_close(FALSE, TRUE);
/* Close the socket, and return the appropriate value, first setting
works because the NULL setting is passed back to the calling process, and
remote_max_parallel is forced to 1 when delivering over an existing connection,
-
-If all went well and continue_more is set, we shouldn't actually get here if
-there are further addresses, as the return above will be taken. However,
-writing RSET might have failed, or there may be other addresses whose hosts are
-specified in the transports, and therefore not visible at top level, in which
-case continue_more won't get set. */
+*/
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
if (sx->send_quit)
@@ -2220,15 +2277,19 @@ int address_count;
*p = 0;
-/* If we know the receiving MTA supports the SIZE qualification,
+/* If we know the receiving MTA supports the SIZE qualification, and we know it,
send it, adding something to the message size to allow for imprecision
and things that get added en route. Exim keeps the number of lines
in a message, so we can give an accurate value for the original message, but we
need some additional to handle added headers. (Double "." characters don't get
included in the count.) */
-if (sx->peer_offered & PEER_OFFERED_SIZE)
+if ( message_size > 0
+ && sx->peer_offered & OPTION_SIZE && !(sx->avoid_option & OPTION_SIZE))
{
+/*XXX problem here under spool_files_wireformat?
+Or just forget about lines? Or inflate by a fixed proportion? */
+
sprintf(CS p, " SIZE=%d", message_size+message_linecount+sx->ob->size_addition);
while (*p) p++;
}
@@ -2238,7 +2299,7 @@ if (sx->peer_offered & PEER_OFFERED_SIZE)
request that */
sx->prdr_active = FALSE;
-if (sx->peer_offered & PEER_OFFERED_PRDR)
+if (sx->peer_offered & OPTION_PRDR)
for (addr = addrlist; addr; addr = addr->next)
if (addr->transport_return == PENDING_DEFER)
{
@@ -2257,7 +2318,7 @@ if (sx->peer_offered & PEER_OFFERED_PRDR)
/* If it supports internationalised messages, and this meesage need that,
request it */
-if ( sx->peer_offered & PEER_OFFERED_UTF8
+if ( sx->peer_offered & OPTION_UTF8
&& addrlist->prop.utf8_msg
&& !addrlist->prop.utf8_downcvt
)
@@ -2279,7 +2340,7 @@ for (sx->dsn_all_lasthop = TRUE, addr = addrlist, address_count = 0;
/* Add any DSN flags to the mail command */
-if (sx->peer_offered & PEER_OFFERED_DSN && !sx->dsn_all_lasthop)
+if (sx->peer_offered & OPTION_DSN && !sx->dsn_all_lasthop)
{
if (dsn_ret == dsn_ret_hdrs)
{ Ustrcpy(p, " RET=HDRS"); p += 9; }
@@ -2315,7 +2376,7 @@ uschar * p = sx->buffer;
/* Add any DSN flags to the rcpt command */
-if (sx->peer_offered & PEER_OFFERED_DSN && !(addr->dsn_flags & rf_dsnlasthop))
+if (sx->peer_offered & OPTION_DSN && !(addr->dsn_flags & rf_dsnlasthop))
{
if (addr->dsn_flags & rf_dsnflags)
{
@@ -2385,7 +2446,7 @@ sx->pending_MAIL = TRUE; /* The block starts with MAIL */
the delivery log line. */
if ( sx->addrlist->prop.utf8_msg
- && (sx->addrlist->prop.utf8_downcvt || !(sx->peer_offered & PEER_OFFERED_UTF8))
+ && (sx->addrlist->prop.utf8_downcvt || !(sx->peer_offered & OPTION_UTF8))
)
{
if (s = string_address_utf8_to_alabel(s, &errstr), errstr)
@@ -2398,7 +2459,7 @@ sx->pending_MAIL = TRUE; /* The block starts with MAIL */
}
#endif
- rc = smtp_write_command(&sx->outblock, pipelining_active,
+ rc = smtp_write_command(&sx->outblock, pipelining_active ? SCMD_BUFFER : SCMD_FLUSH,
"MAIL FROM:<%s>%s\r\n", s, sx->buffer);
}
@@ -2449,11 +2510,15 @@ for (addr = sx->first_addr, address_count = 0;
BOOL no_flush;
uschar * rcpt_addr;
- addr->dsn_aware = sx->peer_offered & PEER_OFFERED_DSN
+ if (tcp_out_fastopen && !tcp_out_fastopen_logged)
+ setflag(addr, af_tcp_fastopen);
+
+ addr->dsn_aware = sx->peer_offered & OPTION_DSN
? dsn_support_yes : dsn_support_no;
address_count++;
- no_flush = pipelining_active && !sx->verify && (!mua_wrapper || addr->next);
+ no_flush = pipelining_active && !sx->verify
+ && (!mua_wrapper || addr->next && address_count < sx->max_rcpt);
build_rcptcmd_options(sx, addr);
@@ -2475,8 +2540,8 @@ for (addr = sx->first_addr, address_count = 0;
}
#endif
- count = smtp_write_command(&sx->outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
- rcpt_addr, sx->igquotstr, sx->buffer);
+ count = smtp_write_command(&sx->outblock, no_flush ? SCMD_BUFFER : SCMD_FLUSH,
+ "RCPT TO:<%s>%s%s\r\n", rcpt_addr, sx->igquotstr, sx->buffer);
if (count < 0) return -5;
if (count > 0)
@@ -2501,6 +2566,7 @@ for (addr = sx->first_addr, address_count = 0;
}
} /* Loop for next address */
+tcp_out_fastopen_logged = TRUE;
sx->next_addr = addr;
return 0;
}
@@ -2511,28 +2577,29 @@ return 0;
* Proxy TLS connection for another transport process *
******************************************************/
/*
-Use the smtp-context buffer as a staging area, and select on both the slave
-process and the TLS'd fd for data to read (per the coding in ip_recv() and
+Use the given buffer as a staging area, and select on both the given fd
+and the TLS'd client-fd for data to read (per the coding in ip_recv() and
fd_ready() this is legitimate). Do blocking full-size writes, and reads
under a timeout.
Arguments:
- sx smtp context block
+ buf space to use for buffering
+ bufsiz size of buffer
proxy_fd comms to proxied process
timeout per-read timeout, seconds
*/
-static void
-smtp_proxy_tls(smtp_context * sx, int proxy_fd, int timeout)
+void
+smtp_proxy_tls(uschar * buf, size_t bsize, int proxy_fd, int timeout)
{
-fd_set fds;
+fd_set rfds, efds;
int max_fd = MAX(proxy_fd, tls_out.active) + 1;
int rc, i, fd_bits, nbytes;
set_process_info("proxying TLS connection for continued transport");
-FD_ZERO(&fds);
-FD_SET(tls_out.active, &fds);
-FD_SET(proxy_fd, &fds);
+FD_ZERO(&rfds);
+FD_SET(tls_out.active, &rfds);
+FD_SET(proxy_fd, &rfds);
for (fd_bits = 3; fd_bits; )
{
@@ -2540,11 +2607,13 @@ for (fd_bits = 3; fd_bits; )
time_t time_start = time(NULL);
/* wait for data */
+ efds = rfds;
do
{
struct timeval tv = { time_left, 0 };
- rc = select(max_fd, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv);
+ rc = select(max_fd,
+ (SELECT_ARG2_TYPE *)&rfds, NULL, (SELECT_ARG2_TYPE *)&efds, &tv);
if (rc < 0 && errno == EINTR)
if ((time_left -= time(NULL) - time_start) > 0) continue;
@@ -2554,40 +2623,48 @@ for (fd_bits = 3; fd_bits; )
DEBUG(D_transport) if (rc == 0) debug_printf("%s: timed out\n", __FUNCTION__);
return;
}
+
+ if (FD_ISSET(tls_out.active, &efds) || FD_ISSET(proxy_fd, &efds))
+ {
+ DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
+ FD_ISSET(proxy_fd, &efds) ? "proxy" : "tls");
+ return;
+ }
}
- while (rc < 0 || !(FD_ISSET(tls_out.active, &fds) || FD_ISSET(proxy_fd, &fds)));
+ while (rc < 0 || !(FD_ISSET(tls_out.active, &rfds) || FD_ISSET(proxy_fd, &rfds)));
/* handle inbound data */
- if (FD_ISSET(tls_out.active, &fds))
- if ((rc = tls_read(FALSE, sx->buffer, sizeof(sx->buffer))) <= 0)
+ if (FD_ISSET(tls_out.active, &rfds))
+ if ((rc = tls_read(FALSE, buf, bsize)) <= 0)
{
fd_bits &= ~1;
- FD_CLR(tls_out.active, &fds);
+ FD_CLR(tls_out.active, &rfds);
shutdown(proxy_fd, SHUT_WR);
+ timeout = 5;
}
else
{
for (nbytes = 0; rc - nbytes > 0; nbytes += i)
- if ((i = write(proxy_fd, sx->buffer + nbytes, rc - nbytes)) < 0) return;
+ if ((i = write(proxy_fd, buf + nbytes, rc - nbytes)) < 0) return;
}
else if (fd_bits & 1)
- FD_SET(tls_out.active, &fds);
+ FD_SET(tls_out.active, &rfds);
/* handle outbound data */
- if (FD_ISSET(proxy_fd, &fds))
- if ((rc = read(proxy_fd, sx->buffer, sizeof(sx->buffer))) <= 0)
+ if (FD_ISSET(proxy_fd, &rfds))
+ if ((rc = read(proxy_fd, buf, bsize)) <= 0)
{
- fd_bits &= ~2;
- FD_CLR(proxy_fd, &fds);
- shutdown(tls_out.active, SHUT_WR);
+ fd_bits = 0;
+ tls_close(FALSE, TRUE);
}
else
{
for (nbytes = 0; rc - nbytes > 0; nbytes += i)
- if ((i = tls_write(FALSE, sx->buffer + nbytes, rc - nbytes)) < 0) return;
+ if ((i = tls_write(FALSE, buf + nbytes, rc - nbytes, FALSE)) < 0)
+ return;
}
else if (fd_bits & 2)
- FD_SET(proxy_fd, &fds);
+ FD_SET(proxy_fd, &rfds);
}
}
#endif
@@ -2616,7 +2693,8 @@ Arguments:
failed by one of them.
host host to deliver to
host_af AF_INET or AF_INET6
- port default TCP/IP port to use, in host byte order
+ defport default TCP/IP port to use if host does not specify, in host
+ byte order
interface interface to bind to, or NULL
tblock transport instance block
message_defer set TRUE if yield is OK, but all addresses were deferred
@@ -2638,7 +2716,7 @@ Returns: OK - the connection was made and the delivery attempted;
*/
static int
-smtp_deliver(address_item *addrlist, host_item *host, int host_af, int port,
+smtp_deliver(address_item *addrlist, host_item *host, int host_af, int defport,
uschar *interface, transport_instance *tblock,
BOOL *message_defer, BOOL suppress_tls)
{
@@ -2646,22 +2724,22 @@ address_item *addr;
int yield = OK;
int save_errno;
int rc;
-time_t start_delivery_time = time(NULL);
+struct timeval start_delivery_time;
BOOL pass_message = FALSE;
uschar *message = NULL;
uschar new_message_id[MESSAGE_ID_LENGTH + 1];
-uschar *p;
smtp_context sx;
+gettimeofday(&start_delivery_time, NULL);
suppress_tls = suppress_tls; /* stop compiler warning when no TLS support */
*message_defer = FALSE;
sx.addrlist = addrlist;
sx.host = host;
sx.host_af = host_af,
-sx.port = port;
+sx.port = defport;
sx.interface = interface;
sx.helo_data = NULL;
sx.tblock = tblock;
@@ -2678,17 +2756,14 @@ set it up. This cannot be done until the identify of the host is known. */
if (tblock->filter_command)
{
- BOOL rc;
- uschar fbuf[64];
- sprintf(CS fbuf, "%.50s transport", tblock->name);
- rc = transport_set_up_command(&transport_filter_argv, tblock->filter_command,
- TRUE, DEFER, addrlist, fbuf, NULL);
transport_filter_timeout = tblock->filter_timeout;
/* On failure, copy the error to all addresses, abandon the SMTP call, and
yield ERROR. */
- if (!rc)
+ if (!transport_set_up_command(&transport_filter_argv,
+ tblock->filter_command, TRUE, DEFER, addrlist,
+ string_sprintf("%.50s transport", tblock->name), NULL))
{
set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
FALSE);
@@ -2699,14 +2774,15 @@ if (tblock->filter_command)
if ( transport_filter_argv
&& *transport_filter_argv
&& **transport_filter_argv
- && sx.peer_offered & PEER_OFFERED_CHUNKING
+ && sx.peer_offered & OPTION_CHUNKING
)
{
- sx.peer_offered &= ~PEER_OFFERED_CHUNKING;
+ sx.peer_offered &= ~OPTION_CHUNKING;
DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n");
}
}
+sx.first_addr = addrlist;
/* For messages that have more than the maximum number of envelope recipients,
we want to send several transactions down the same SMTP connection. (See
@@ -2718,39 +2794,61 @@ transaction to handle. */
SEND_MESSAGE:
sx.from_addr = return_path;
-sx.first_addr = sx.sync_addr = addrlist;
+sx.sync_addr = sx.first_addr;
sx.ok = FALSE;
sx.send_rset = TRUE;
sx.completed_addr = FALSE;
-/* Initiate a message transfer. */
+/* If we are a continued-connection-after-verify the MAIL and RCPT
+commands were already sent; do not re-send but do mark the addrs as
+having been accepted up to RCPT stage. A traditional cont-conn
+always has a sequence number greater than one. */
-switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield))
+if (continue_hostname && continue_sequence == 1)
{
- case 0: break;
- case -1: case -2: goto RESPONSE_FAILED;
- case -3: goto END_OFF;
- case -4: goto SEND_QUIT;
- default: goto SEND_FAILED;
- }
+ address_item * addr;
-/* If we are an MUA wrapper, abort if any RCPTs were rejected, either
-permanently or temporarily. We should have flushed and synced after the last
-RCPT. */
+ sx.peer_offered = smtp_peer_options;
+ sx.pending_MAIL = FALSE;
+ sx.ok = TRUE;
+ sx.next_addr = NULL;
-if (mua_wrapper)
+ for (addr = addrlist; addr; addr = addr->next)
+ addr->transport_return = PENDING_OK;
+ }
+else
{
- address_item *badaddr;
- for (badaddr = sx.first_addr; badaddr; badaddr = badaddr->next)
- if (badaddr->transport_return != PENDING_OK)
- {
- /*XXX could we find a better errno than 0 here? */
- set_errno_nohost(addrlist, 0, badaddr->message, FAIL,
- testflag(badaddr, af_pass_message));
- sx.ok = FALSE;
- break;
- }
+ /* Initiate a message transfer. */
+
+ switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield))
+ {
+ case 0: break;
+ case -1: case -2: goto RESPONSE_FAILED;
+ case -3: goto END_OFF;
+ case -4: goto SEND_QUIT;
+ default: goto SEND_FAILED;
+ }
+
+ /* If we are an MUA wrapper, abort if any RCPTs were rejected, either
+ permanently or temporarily. We should have flushed and synced after the last
+ RCPT. */
+
+ if (mua_wrapper)
+ {
+ address_item * a;
+ unsigned cnt;
+
+ for (a = sx.first_addr, cnt = 0; a && cnt < sx.max_rcpt; a = a->next, cnt++)
+ if (a->transport_return != PENDING_OK)
+ {
+ /*XXX could we find a better errno than 0 here? */
+ set_errno_nohost(addrlist, 0, a->message, FAIL,
+ testflag(a, af_pass_message));
+ sx.ok = FALSE;
+ break;
+ }
+ }
}
/* If ok is TRUE, we know we have got at least one good recipient, and must now
@@ -2761,10 +2859,10 @@ are pipelining. The responses are all handled by sync_responses().
If using CHUNKING, do not send a BDAT until we know how big a chunk we want
to send is. */
-if ( !(sx.peer_offered & PEER_OFFERED_CHUNKING)
+if ( !(sx.peer_offered & OPTION_CHUNKING)
&& (sx.ok || (pipelining_active && !mua_wrapper)))
{
- int count = smtp_write_command(&sx.outblock, FALSE, "DATA\r\n");
+ int count = smtp_write_command(&sx.outblock, SCMD_FLUSH, "DATA\r\n");
if (count < 0) goto SEND_FAILED;
switch(sync_responses(&sx, count, sx.ok ? +1 : -1))
@@ -2791,7 +2889,7 @@ for handling the SMTP dot-handling protocol, flagging to apply to headers as
well as body. Set the appropriate timeout value to be used for each chunk.
(Haven't been able to make it work using select() for writing yet.) */
-if (!(sx.peer_offered & PEER_OFFERED_CHUNKING) && !sx.ok)
+if (!(sx.peer_offered & OPTION_CHUNKING) && !sx.ok)
{
/* Save the first address of the next batch. */
sx.first_addr = sx.next_addr;
@@ -2801,6 +2899,7 @@ if (!(sx.peer_offered & PEER_OFFERED_CHUNKING) && !sx.ok)
else
{
transport_ctx tctx = {
+ {sx.inblock.sock},
tblock,
addrlist,
US".", US"..", /* Escaping strings */
@@ -2817,7 +2916,7 @@ else
of responses. The callback needs a whole bunch of state so set up
a transport-context structure to be passed around. */
- if (sx.peer_offered & PEER_OFFERED_CHUNKING)
+ if (sx.peer_offered & OPTION_CHUNKING)
{
tctx.check_string = tctx.escape_string = NULL;
tctx.options |= topt_use_bdat;
@@ -2842,17 +2941,16 @@ else
transport_write_timeout = sx.ob->data_timeout;
smtp_command = US"sending data block"; /* For error messages */
DEBUG(D_transport|D_v)
- if (sx.peer_offered & PEER_OFFERED_CHUNKING)
+ if (sx.peer_offered & OPTION_CHUNKING)
debug_printf(" will write message using CHUNKING\n");
else
debug_printf(" SMTP>> writing message and terminating \".\"\n");
transport_count = 0;
#ifndef DISABLE_DKIM
- sx.ok = dkim_transport_write_message(sx.inblock.sock, &tctx, &sx.ob->dkim,
- CUSS &message);
+ sx.ok = dkim_transport_write_message(&tctx, &sx.ob->dkim, CUSS &message);
#else
- sx.ok = transport_write_message(sx.inblock.sock, &tctx, 0);
+ sx.ok = transport_write_message(&tctx, 0);
#endif
/* transport_write_message() uses write() because it is called from other
@@ -2878,7 +2976,7 @@ else
smtp_command = US"end of data";
- if (sx.peer_offered & PEER_OFFERED_CHUNKING && sx.cmd_count > 1)
+ if (sx.peer_offered & OPTION_CHUNKING && sx.cmd_count > 1)
{
/* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */
switch(sync_responses(&sx, sx.cmd_count-1, 0))
@@ -2948,10 +3046,11 @@ else
if (sx.ok)
{
int flag = '=';
- int delivery_time = (int)(time(NULL) - start_delivery_time);
+ struct timeval delivery_time;
int len;
- uschar *conf = NULL;
+ uschar * conf = NULL;
+ timesince(&delivery_time, &start_delivery_time);
sx.send_rset = FALSE;
pipelining_active = FALSE;
@@ -2966,7 +3065,7 @@ else
{
const uschar *s = string_printing(sx.buffer);
/* deconst cast ok here as string_printing was checked to have alloc'n'copied */
- conf = (s == sx.buffer)? (uschar *)string_copy(s) : US s;
+ conf = (s == sx.buffer)? US string_copy(s) : US s;
}
/* Process all transported addresses - for LMTP or PRDR, read a status for
@@ -3026,14 +3125,15 @@ else
actual host that was used. */
addr->transport_return = OK;
- addr->more_errno = delivery_time;
+ addr->more_errno = delivery_time.tv_sec;
+ addr->delivery_usec = delivery_time.tv_usec;
addr->host_used = host;
addr->special_action = flag;
addr->message = conf;
#ifndef DISABLE_PRDR
- if (sx.prdr_active) addr->flags |= af_prdr_used;
+ if (sx.prdr_active) setflag(addr, af_prdr_used);
#endif
- if (sx.peer_offered & PEER_OFFERED_CHUNKING) addr->flags |= af_chunking_used;
+ if (sx.peer_offered & OPTION_CHUNKING) setflag(addr, af_chunking_used);
flag = '-';
#ifndef DISABLE_PRDR
@@ -3050,7 +3150,7 @@ else
else
sprintf(CS sx.buffer, "%.500s\n", addr->unique);
- DEBUG(D_deliver) debug_printf("journalling %s\n", sx.buffer);
+ DEBUG(D_deliver) debug_printf("S:journalling %s", sx.buffer);
len = Ustrlen(CS sx.buffer);
if (write(journal_fd, sx.buffer, len) != len)
log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
@@ -3277,7 +3377,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
|| continue_more
|| (
#ifdef SUPPORT_TLS
- ( tls_out.active < 0 && !continue_proxy
+ ( tls_out.active < 0 && !continue_proxy_cipher
|| verify_check_given_host(&sx.ob->hosts_nopass_tls, host) != OK
)
&&
@@ -3291,7 +3391,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
BOOL pass_message;
if (sx.send_rset)
- if (! (sx.ok = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0))
+ if (! (sx.ok = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0))
{
msg = US string_sprintf("send() to %s [%s] failed: %s", host->name,
host->address, strerror(errno));
@@ -3323,32 +3423,39 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
continue_sequence++; /* Causes * in logging */
goto SEND_MESSAGE;
}
- if (continue_more) return yield; /* More addresses for another run */
- /* Pass the connection on to a new Exim process. */
+ /* Unless caller said it already has more messages listed for this host,
+ pass the connection on to a new Exim process (below, the call to
+ transport_pass_socket). If the caller has more ready, just return with
+ the connection still open. */
+
#ifdef SUPPORT_TLS
if (tls_out.active >= 0)
- if (verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK)
+ if ( continue_more
+ || verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK)
{
- /* Pass the socket, for direct use, to a new Exim process. Before
- doing so, we must shut down TLS. Not all MTAs allow for the
- continuation of the SMTP session when TLS is shut down. We test for
- this by sending a new EHLO. If we don't get a good response, we don't
- attempt to pass the socket on. */
+ /* Before passing the socket on, or returning to caller with it still
+ open, we must shut down TLS. Not all MTAs allow for the continuation
+ of the SMTP session when TLS is shut down. We test for this by sending
+ a new EHLO. If we don't get a good response, we don't attempt to pass
+ the socket on. */
tls_close(FALSE, TRUE);
smtp_peer_options = smtp_peer_options_wrap;
sx.ok = !sx.smtps
- && smtp_write_command(&sx.outblock, FALSE,
+ && smtp_write_command(&sx.outblock, SCMD_FLUSH,
"EHLO %s\r\n", sx.helo_data) >= 0
&& smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
'2', sx.ob->command_timeout);
+
+ if (sx.ok && continue_more)
+ return yield; /* More addresses for another run */
}
else
{
/* Set up a pipe for proxying TLS for the new transport process */
- smtp_peer_options |= PEER_OFFERED_TLS;
+ smtp_peer_options |= OPTION_TLS;
if (sx.ok = (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0))
socket_fd = pfd[1];
else
@@ -3359,7 +3466,10 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
# endif
);
}
+ else
#endif
+ if (continue_more)
+ return yield; /* More addresses for another run */
/* If the socket is successfully passed, we mustn't send QUIT (or
indeed anything!) from here. */
@@ -3376,24 +3486,34 @@ propagate it from the initial
just passed the baton to. Fork a child to to do it, and return to
get logging done asap. Which way to place the work makes assumptions
about post-fork prioritisation which may not hold on all platforms. */
-
+#ifdef SUPPORT_TLS
if (tls_out.active >= 0)
{
int pid = fork();
if (pid > 0) /* parent */
{
+ DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid);
+ close(pfd[0]);
+ waitpid(pid, NULL, 0);
tls_close(FALSE, FALSE);
(void)close(sx.inblock.sock);
continue_transport = NULL;
continue_hostname = NULL;
return yield;
}
- else if (pid == 0) /* child */
+ else if (pid == 0) /* child; fork again to disconnect totally */
{
- smtp_proxy_tls(&sx, pfd[0], sx.ob->command_timeout);
+ close(pfd[1]);
+ if ((pid = fork()))
+ {
+ DEBUG(D_transport) debug_printf("proxy-prox final-pid %d\n", pid);
+ _exit(pid ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+ smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd[0], sx.ob->command_timeout);
exim_exit(0);
}
}
+#endif
}
}
@@ -3426,7 +3546,7 @@ This change is being made on 31-Jul-98. After over a year of trouble-free
operation, the old commented-out code was removed on 17-Sep-99. */
SEND_QUIT:
-if (sx.send_quit) (void)smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n");
+if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n");
END_OFF:
@@ -3507,7 +3627,7 @@ outblock.ptr = outbuffer;
outblock.cmd_count = 0;
outblock.authenticating = FALSE;
-(void)smtp_write_command(&outblock, FALSE, "QUIT\r\n");
+(void)smtp_write_command(&outblock, SCMD_FLUSH, "QUIT\r\n");
(void)smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
ob->command_timeout);
(void)close(inblock.sock);
@@ -3579,7 +3699,7 @@ smtp_transport_entry(
address_item *addrlist) /* addresses we are working on */
{
int cutoff_retry;
-int port;
+int defport;
int hosts_defer = 0;
int hosts_fail = 0;
int hosts_looked_up = 0;
@@ -3608,8 +3728,10 @@ DEBUG(D_transport)
for (host = hostlist; host; host = host->next)
debug_printf(" %s:%d\n", host->name, host->port);
}
- if (continue_hostname) debug_printf("already connected to %s [%s]\n",
- continue_hostname, continue_host_address);
+ if (continue_hostname)
+ debug_printf("already connected to %s [%s] (on fd %d)\n",
+ continue_hostname, continue_host_address,
+ cutthrough.fd >= 0 ? cutthrough.fd : 0);
}
/* Set the flag requesting that these hosts be added to the waiting
@@ -3732,7 +3854,7 @@ else if (ob->hosts_randomize && hostlist->mx == MX_NONE && !continue_hostname)
/* Sort out the default port. */
-if (!smtp_get_port(ob->port, addrlist, &port, tid)) return FALSE;
+if (!smtp_get_port(ob->port, addrlist, &defport, tid)) return FALSE;
/* For each host-plus-IP-address on the list:
@@ -3971,7 +4093,7 @@ for (cutoff_retry = 0;
the default. */
pistring = string_sprintf(":%d", host->port == PORT_NONE
- ? port : host->port);
+ ? defport : host->port);
if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
@@ -4050,7 +4172,7 @@ for (cutoff_retry = 0;
{
if ( !host->address
|| host->status != hstatus_unusable_expired
- || host->last_try > received_time)
+ || host->last_try > received_time.tv_sec)
continue;
DEBUG(D_transport) debug_printf("trying expired host %s [%s]%s\n",
host->name, host->address, pistring);
@@ -4171,7 +4293,7 @@ for (cutoff_retry = 0;
/* Attempt the delivery. */
total_hosts_tried++;
- rc = smtp_deliver(addrlist, thost, host_af, port, interface, tblock,
+ rc = smtp_deliver(addrlist, thost, host_af, defport, interface, tblock,
&message_defer, FALSE);
/* Yield is one of:
@@ -4218,7 +4340,7 @@ for (cutoff_retry = 0;
"%s: delivering unencrypted to H=%s [%s] (not in hosts_require_tls)",
first_addr->message, host->name, host->address);
first_addr = prepare_addresses(addrlist, host);
- rc = smtp_deliver(addrlist, thost, host_af, port, interface, tblock,
+ rc = smtp_deliver(addrlist, thost, host_af, defport, interface, tblock,
&message_defer, TRUE);
if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
write_logs(first_addr, host);
@@ -4370,7 +4492,7 @@ for (cutoff_retry = 0;
for (last_rule = retry->rules;
last_rule->next;
last_rule = last_rule->next);
- timedout = time(NULL) - received_time > last_rule->timeout;
+ timedout = time(NULL) - received_time.tv_sec > last_rule->timeout;
}
else timedout = TRUE; /* No rule => timed out */
@@ -4513,6 +4635,7 @@ DEBUG(D_transport) debug_printf("Leaving %s transport\n", tblock->name);
return TRUE; /* Each address has its status */
}
+#endif /*!MACRO_PREDEF*/
/* vi: aw ai sw=2
*/
/* End of transport/smtp.c */
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index 88b608bcc..c965a72a7 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -130,6 +130,7 @@ typedef struct {
int cmd_count;
uschar peer_offered;
+ uschar avoid_option;
uschar * igquotstr;
uschar * helo_data;
#ifdef EXPERIMENTAL_DSN_INFO
diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c
index 555843068..1368849d6 100644
--- a/src/src/transports/smtp_socks.c
+++ b/src/src/transports/smtp_socks.c
@@ -233,6 +233,7 @@ socks_opts proxies[32]; /* max #proxies handled */
unsigned nproxies;
socks_opts * sob;
unsigned size;
+blob early_data;
if (!timeout) timeout = 24*60*60; /* use 1 day for "indefinite" */
tmo = time(NULL) + timeout;
@@ -268,6 +269,14 @@ for (nproxies = 0;
socks_option(sob, option);
}
+/* Set up the socks protocol method-selection message,
+for sending on connection */
+
+state = US"method select";
+buf[0] = 5; buf[1] = 1; buf[2] = sob->auth_type;
+early_data.data = buf;
+early_data.len = 3;
+
/* Try proxies until a connection succeeds */
for(;;)
@@ -285,11 +294,11 @@ for(;;)
sob = &proxies[idx];
/* bodge up a host struct for the proxy */
- proxy.address = sob->proxy_host;
+ proxy.address = proxy.name = sob->proxy_host;
proxy_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
if ((fd = smtp_sock_connect(&proxy, proxy_af, sob->port,
- interface, tb, sob->timeout)) >= 0)
+ interface, tb, sob->timeout, &early_data)) >= 0)
{
proxy_local_address = string_copy(proxy.address);
proxy_local_port = sob->port;
@@ -301,13 +310,8 @@ for(;;)
}
/* Do the socks protocol stuff */
-/* Send method-selection */
-state = US"method select";
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SOCKS>> 05 01 %02x\n", sob->auth_type);
-buf[0] = 5; buf[1] = 1; buf[2] = sob->auth_type;
-if (send(fd, buf, 3, 0) < 0)
- goto snd_err;
/* expect method response */
diff --git a/src/src/transports/tf_maildir.c b/src/src/transports/tf_maildir.c
index 7be72896a..9e18a804b 100644
--- a/src/src/transports/tf_maildir.c
+++ b/src/src/transports/tf_maildir.c
@@ -211,10 +211,12 @@ int len;
uschar buffer[256];
sprintf(CS buffer, "%d 1\n", size);
len = Ustrlen(buffer);
-(void)lseek(fd, 0, SEEK_END);
-len = write(fd, buffer, len);
-DEBUG(D_transport)
- debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer);
+if (lseek(fd, 0, SEEK_END) >= 0)
+ {
+ len = write(fd, buffer, len);
+ DEBUG(D_transport)
+ debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer);
+ }
}
diff --git a/src/src/utf8.c b/src/src/utf8.c
index 7b7b88f66..4647785b9 100644
--- a/src/src/utf8.c
+++ b/src/src/utf8.c
@@ -68,7 +68,7 @@ any mixed-case annotation. This does not really matter for a domain. */
break;
}
}
-if ((rc = idn2_lookup_u8(CCS s, &s1, IDN2_NFC_INPUT)) != IDN2_OK)
+if ((rc = idn2_lookup_u8((const uint8_t *) s, &s1, IDN2_NFC_INPUT)) != IDN2_OK)
{
if (err) *err = US idn2_strerror(rc);
return NULL;
@@ -98,6 +98,7 @@ string_domain_alabel_to_utf8(const uschar * alabel, uschar ** err)
const uschar * label;
int sep = '.';
uschar * s = NULL;
+int size = 0, len = 0;
while (label = string_nextinlist(&alabel, &sep, NULL, 0))
if ( string_is_alabel(label)
@@ -105,7 +106,7 @@ while (label = string_nextinlist(&alabel, &sep, NULL, 0))
)
return NULL;
else
- s = string_append_listele(s, '.', label);
+ s = string_append_listele(s, &size, &len, '.', label);
return s;
#else
diff --git a/src/src/verify.c b/src/src/verify.c
index 9ff1807d4..ac5eb667b 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -39,7 +39,7 @@ static tree_node *dnsbl_cache = NULL;
#define MT_NOT 1
#define MT_ALL 2
-static uschar cutthrough_response(char, uschar **, int);
+static uschar cutthrough_response(int, char, uschar **, int);
@@ -68,9 +68,7 @@ int length, expire;
time_t now;
dbdata_callout_cache *cache_record;
-cache_record = dbfn_read_with_length(dbm_file, key, &length);
-
-if (cache_record == NULL)
+if (!(cache_record = dbfn_read_with_length(dbm_file, key, &length)))
{
HDEBUG(D_verify) debug_printf("callout cache: no %s record found for %s\n", type, key);
return NULL;
@@ -388,7 +386,7 @@ if (addr->transport == cutthrough.addr.transport)
deliver_domain = addr->domain;
transport_name = addr->transport->name;
- host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
+ host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET;
if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
US"callout") ||
@@ -408,10 +406,10 @@ if (addr->transport == cutthrough.addr.transport)
/* Match! Send the RCPT TO, set done from the response */
done =
- smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n",
+ smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
transport_rcpt_address(addr,
addr->transport->rcpt_include_affixes)) >= 0 &&
- cutthrough_response('2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2';
+ cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2';
/* This would go horribly wrong if a callout fail was ignored by ACL.
We punt by abandoning cutthrough on a reject, like the
@@ -429,7 +427,7 @@ if (addr->transport == cutthrough.addr.transport)
}
else
{
- cancel_cutthrough_connection("recipient rejected");
+ cancel_cutthrough_connection(TRUE, US"recipient rejected");
if (!resp || errno == ETIMEDOUT)
{
HDEBUG(D_verify) debug_printf("SMTP timeout\n");
@@ -459,7 +457,7 @@ if (addr->transport == cutthrough.addr.transport)
break; /* host_list */
}
if (!done)
- cancel_cutthrough_connection("incompatible connection");
+ cancel_cutthrough_connection(TRUE, US"incompatible connection");
return done;
}
@@ -490,6 +488,7 @@ Arguments:
vopt_callout_random => do the "random" thing
vopt_callout_recipsender => use real sender for recipient
vopt_callout_recippmaster => use postmaster for recipient
+ vopt_callout_hold => lazy close connection
se_mailfrom MAIL FROM address for sender verify; NULL => ""
pm_mailfrom if non-NULL, do the postmaster check with this sender
@@ -556,7 +555,10 @@ else
if (cached_callout_lookup(addr, address_key, from_address,
&options, &pm_mailfrom, &yield, failure_ptr,
&new_domain_record, &old_domain_cache_result))
+ {
+ cancel_cutthrough_connection(TRUE, US"cache-hit");
goto END_CALLOUT;
+ }
if (!addr->transport)
{
@@ -756,9 +758,12 @@ tls_retry_connection:
}
#endif
- /* This would be ok for 1st rcpt of a cutthrough (XXX do we have a count?) , but no way to
- handle a subsequent because of the RSET. So refuse to support any. */
- cancel_cutthrough_connection("random-recipient");
+ /* This would be ok for 1st rcpt of a cutthrough (the case handled here;
+ subsequents are done in cutthrough_multi()), but no way to
+ handle a subsequent because of the RSET vaporising the MAIL FROM.
+ So refuse to support any. Most cutthrough use will not involve
+ random_local_part, so no loss. */
+ cancel_cutthrough_connection(TRUE, US"random-recipient");
addr->address = string_sprintf("%s@%.1000s",
random_local_part, rcpt_domain);
@@ -778,26 +783,33 @@ tls_retry_connection:
postmaster-verify.
The sync_responses() would need to be taught about it and we'd
need another return code filtering out to here.
+
+ Avoid using a SIZE option on the MAIL for all randon-rcpt checks.
*/
+ sx.avoid_option = OPTION_SIZE;
+
/* Remember when we last did a random test */
new_domain_record.random_stamp = time(NULL);
if (smtp_write_mail_and_rcpt_cmds(&sx, &yield) == 0)
switch(addr->transport_return)
{
- case PENDING_OK:
+ case PENDING_OK: /* random was accepted, unfortunately */
new_domain_record.random_result = ccache_accept;
- break;
- case FAIL:
+ yield = OK; /* Only usable verify result we can return */
+ done = TRUE;
+ goto no_conn;
+ case FAIL: /* rejected: the preferred result */
new_domain_record.random_result = ccache_reject;
+ sx.avoid_option = 0;
/* Between each check, issue RSET, because some servers accept only
one recipient after MAIL FROM:<>.
XXX We don't care about that for postmaster_full. Should we? */
if ((done =
- smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 &&
+ smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 &&
smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
'2', callout)))
break;
@@ -822,6 +834,8 @@ tls_retry_connection:
sx.send_rset = TRUE;
sx.completed_addr = FALSE;
goto tls_retry_connection;
+ case DEFER: /* 4xx response to random */
+ break; /* Just to be clear. ccache_unknown, !done. */
}
/* Re-setup for main verify, or for the error message when failing */
@@ -835,12 +849,14 @@ tls_retry_connection:
else
done = TRUE;
- /* Main verify. If the host is accepting all local parts, as determined
- by the "random" check, we don't need to waste time doing any further
- checking. */
+ /* Main verify. For rcpt-verify use SIZE if we know it and we're not cacheing;
+ for sndr-verify never use it. */
if (done)
{
+ if (!(options & vopt_is_recipient && options & vopt_callout_no_cache))
+ sx.avoid_option = OPTION_SIZE;
+
done = FALSE;
switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield))
{
@@ -849,12 +865,12 @@ tls_retry_connection:
case PENDING_OK: done = TRUE;
new_address_record.result = ccache_accept;
break;
- case FAIL: done = TRUE;
+ case FAIL: done = TRUE;
yield = FAIL;
*failure_ptr = US"recipient";
new_address_record.result = ccache_reject;
break;
- default: break;
+ default: break;
}
break;
@@ -887,10 +903,10 @@ tls_retry_connection:
/* Could possibly shift before main verify, just above, and be ok
for cutthrough. But no way to handle a subsequent rcpt, so just
refuse any */
- cancel_cutthrough_connection("postmaster verify");
+ cancel_cutthrough_connection(TRUE, US"postmaster verify");
HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n");
- done = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0
+ done = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0
&& smtp_read_response(&sx.inblock, sx.buffer,
sizeof(sx.buffer), '2', callout);
@@ -907,6 +923,7 @@ tls_retry_connection:
sx.ok = FALSE;
sx.send_rset = TRUE;
sx.completed_addr = FALSE;
+ sx.avoid_option = OPTION_SIZE;
if( smtp_write_mail_and_rcpt_cmds(&sx, &yield) == 0
&& addr->transport_return == PENDING_OK
@@ -914,7 +931,7 @@ tls_retry_connection:
done = TRUE;
else
done = (options & vopt_callout_fullpm) != 0
- && smtp_write_command(&sx.outblock, FALSE,
+ && smtp_write_command(&sx.outblock, SCMD_FLUSH,
"RCPT TO:<postmaster>\r\n") >= 0
&& smtp_read_response(&sx.inblock, sx.buffer,
sizeof(sx.buffer), '2', callout);
@@ -976,7 +993,7 @@ no_conn:
if (*sx.buffer == 0) Ustrcpy(sx.buffer, US"connection dropped");
/*XXX test here is ugly; seem to have a split of responsibility for
- building this message. Need to reationalise. Where is it done
+ building this message. Need to rationalise. Where is it done
before here, and when not?
Not == 5xx resp to MAIL on main-verify
*/
@@ -1003,8 +1020,10 @@ no_conn:
/* Cutthrough - on a successful connect and recipient-verify with
use-sender and we are 1st rcpt and have no cutthrough conn so far
- here is where we want to leave the conn open */
- if ( cutthrough.delivery
+ here is where we want to leave the conn open. Ditto for a lazy-close
+ verify. */
+
+ if ( (cutthrough.delivery || options & vopt_callout_hold)
&& rcpt_count == 1
&& done
&& yield == OK
@@ -1016,14 +1035,29 @@ no_conn:
&& !sx.lmtp
)
{
- HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for cutthrough delivery\n");
-
- cutthrough.fd = sx.outblock.sock; /* We assume no buffer in use in the outblock */
- cutthrough.nrcpt = 1;
- cutthrough.interface = interface;
- cutthrough.host = *host;
- cutthrough.addr = *addr; /* Save the address_item for later logging */
- cutthrough.addr.next = NULL;
+ HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for %s\n",
+ cutthrough.delivery
+ ? "cutthrough delivery" : "potential further verifies and delivery");
+
+ cutthrough.callout_hold_only = !cutthrough.delivery;
+ cutthrough.is_tls = tls_out.active >= 0;
+ cutthrough.fd = sx.outblock.sock; /* We assume no buffer in use in the outblock */
+ cutthrough.nrcpt = 1;
+ cutthrough.transport = addr->transport->name;
+ cutthrough.interface = interface;
+ cutthrough.snd_port = sending_port;
+ cutthrough.peer_options = smtp_peer_options;
+ cutthrough.host = *host;
+ {
+ int oldpool = store_pool;
+ store_pool = POOL_PERM;
+ cutthrough.snd_ip = string_copy(sending_ip_address);
+ cutthrough.host.name = string_copy(host->name);
+ cutthrough.host.address = string_copy(host->address);
+ store_pool = oldpool;
+ }
+ cutthrough.addr = *addr; /* Save the address_item for later logging */
+ cutthrough.addr.next = NULL;
cutthrough.addr.host_used = &cutthrough.host;
if (addr->parent)
*(cutthrough.addr.parent = store_get(sizeof(address_item))) =
@@ -1036,12 +1070,12 @@ no_conn:
}
else
{
- /* Ensure no cutthrough on multiple address verifies */
+ /* Ensure no cutthrough on multiple verifies that were incompatible */
if (options & vopt_callout_recipsender)
- cancel_cutthrough_connection("not usable for cutthrough");
+ cancel_cutthrough_connection(TRUE, US"not usable for cutthrough");
if (sx.send_quit)
{
- (void) smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n");
+ (void) smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n");
/* Wait a short time for response, and discard it */
smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
@@ -1153,7 +1187,7 @@ if(cutthrough.fd < 0)
if(
#ifdef SUPPORT_TLS
- (tls_out.active == cutthrough.fd) ? tls_write(FALSE, ctblock.buffer, n) :
+ tls_out.active == cutthrough.fd ? tls_write(FALSE, ctblock.buffer, n, FALSE) :
#endif
send(cutthrough.fd, ctblock.buffer, n, 0) > 0
)
@@ -1184,20 +1218,27 @@ return TRUE;
}
/* Buffered output of counted data block. Return boolean success */
-BOOL
+static BOOL
cutthrough_puts(uschar * cp, int n)
{
if (cutthrough.fd < 0) return TRUE;
if (_cutthrough_puts(cp, n)) return TRUE;
-cancel_cutthrough_connection("transmit failed");
+cancel_cutthrough_connection(TRUE, US"transmit failed");
return FALSE;
}
+void
+cutthrough_data_puts(uschar * cp, int n)
+{
+if (cutthrough.delivery) (void) cutthrough_puts(cp, n);
+return;
+}
+
static BOOL
_cutthrough_flush_send(void)
{
-int n= ctblock.ptr-ctblock.buffer;
+int n = ctblock.ptr - ctblock.buffer;
if(n>0)
if(!cutthrough_send(n))
@@ -1211,21 +1252,28 @@ BOOL
cutthrough_flush_send(void)
{
if (_cutthrough_flush_send()) return TRUE;
-cancel_cutthrough_connection("transmit failed");
+cancel_cutthrough_connection(TRUE, US"transmit failed");
return FALSE;
}
-BOOL
+static BOOL
cutthrough_put_nl(void)
{
return cutthrough_puts(US"\r\n", 2);
}
+void
+cutthrough_data_put_nl(void)
+{
+cutthrough_data_puts(US"\r\n", 2);
+}
+
+
/* Get and check response from cutthrough target */
static uschar
-cutthrough_response(char expect, uschar ** copy, int timeout)
+cutthrough_response(int fd, char expect, uschar ** copy, int timeout)
{
smtp_inblock inblock;
uschar inbuffer[4096];
@@ -1235,12 +1283,12 @@ inblock.buffer = inbuffer;
inblock.buffersize = sizeof(inbuffer);
inblock.ptr = inbuffer;
inblock.ptrend = inbuffer;
-inblock.sock = cutthrough.fd;
+inblock.sock = fd;
/* this relies on (inblock.sock == tls_out.active) */
if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, timeout))
- cancel_cutthrough_connection("target timeout on read");
+ cancel_cutthrough_connection(TRUE, US"target timeout on read");
-if(copy != NULL)
+if(copy)
{
uschar * cp;
*copy = cp = string_copy(responsebuffer);
@@ -1258,7 +1306,7 @@ return responsebuffer[0];
BOOL
cutthrough_predata(void)
{
-if(cutthrough.fd < 0)
+if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
return FALSE;
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> DATA\n");
@@ -1266,13 +1314,13 @@ cutthrough_puts(US"DATA\r\n", 6);
cutthrough_flush_send();
/* Assume nothing buffered. If it was it gets ignored. */
-return cutthrough_response('3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
+return cutthrough_response(cutthrough.fd, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
}
-/* fd and tctx args only to match write_chunk() */
+/* tctx arg only to match write_chunk() */
static BOOL
-cutthrough_write_chunk(int fd, transport_ctx * tctx, uschar * s, int len)
+cutthrough_write_chunk(transport_ctx * tctx, uschar * s, int len)
{
uschar * s2;
while(s && (s2 = Ustrchr(s, '\n')))
@@ -1293,7 +1341,7 @@ cutthrough_headers_send(void)
{
transport_ctx tctx;
-if(cutthrough.fd < 0)
+if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
return FALSE;
/* We share a routine with the mainline transport to handle header add/remove/rewrites,
@@ -1301,13 +1349,15 @@ if(cutthrough.fd < 0)
*/
HDEBUG(D_acl) debug_printf_indent("----------- start cutthrough headers send -----------\n");
+tctx.u.fd = cutthrough.fd;
tctx.tblock = cutthrough.addr.transport;
tctx.addr = &cutthrough.addr;
tctx.check_string = US".";
tctx.escape_string = US"..";
+/*XXX check under spool_files_wireformat. Might be irrelevant */
tctx.options = topt_use_crlf;
-if (!transport_headers_send(cutthrough.fd, &tctx, &cutthrough_write_chunk))
+if (!transport_headers_send(&tctx, &cutthrough_write_chunk))
return FALSE;
HDEBUG(D_acl) debug_printf_indent("----------- done cutthrough headers send ------------\n");
@@ -1316,9 +1366,10 @@ return TRUE;
static void
-close_cutthrough_connection(const char * why)
+close_cutthrough_connection(const uschar * why)
{
-if(cutthrough.fd >= 0)
+int fd = cutthrough.fd;
+if(fd >= 0)
{
/* We could be sending this after a bunch of data, but that is ok as
the only way to cancel the transfer in dataphase is to drop the tcp
@@ -1328,26 +1379,37 @@ if(cutthrough.fd >= 0)
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> QUIT\n");
_cutthrough_puts(US"QUIT\r\n", 6); /* avoid recursion */
_cutthrough_flush_send();
+ cutthrough.fd = -1; /* avoid recursion via read timeout */
/* Wait a short time for response, and discard it */
- cutthrough_response('2', NULL, 1);
+ cutthrough_response(fd, '2', NULL, 1);
- #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
tls_close(FALSE, TRUE);
- #endif
+#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
- (void)close(cutthrough.fd);
- cutthrough.fd = -1;
+ (void)close(fd);
HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why);
}
ctblock.ptr = ctbuffer;
}
void
-cancel_cutthrough_connection(const char * why)
+cancel_cutthrough_connection(BOOL close_noncutthrough_verifies, const uschar * why)
{
-close_cutthrough_connection(why);
-cutthrough.delivery = FALSE;
+if (cutthrough.delivery || close_noncutthrough_verifies)
+ close_cutthrough_connection(why);
+cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
+}
+
+
+void
+release_cutthrough_connection(const uschar * why)
+{
+if (cutthrough.fd < 0) return;
+HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why);
+cutthrough.fd = -1;
+cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
}
@@ -1372,7 +1434,7 @@ if( !cutthrough_puts(US".", 1)
)
return cutthrough.addr.message;
-res = cutthrough_response('2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT);
+res = cutthrough_response(cutthrough.fd, '2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT);
for (addr = &cutthrough.addr; addr; addr = addr->next)
{
addr->message = cutthrough.addr.message;
@@ -1380,7 +1442,7 @@ for (addr = &cutthrough.addr; addr; addr = addr->next)
{
case '2':
delivery_log(LOG_MAIN, addr, (int)'>', NULL);
- close_cutthrough_connection("delivered");
+ close_cutthrough_connection(US"delivered");
break;
case '4':
@@ -1465,7 +1527,7 @@ va_list ap;
va_start(ap, format);
if (smtp_out && (f == smtp_out))
- smtp_vprintf(format, ap);
+ smtp_vprintf(format, FALSE, ap);
else
vfprintf(f, format, ap);
va_end(ap);
@@ -1727,16 +1789,16 @@ while (addr_new)
transport. */
transport_feedback tf = {
- NULL, /* interface (=> any) */
- US"smtp", /* port */
- US"smtp", /* protocol */
- NULL, /* hosts */
- US"$smtp_active_hostname", /* helo_data */
- FALSE, /* hosts_override */
- FALSE, /* hosts_randomize */
- FALSE, /* gethostbyname */
- TRUE, /* qualify_single */
- FALSE /* search_parents */
+ .interface = NULL, /* interface (=> any) */
+ .port = US"smtp",
+ .protocol = US"smtp",
+ .hosts = NULL,
+ .helo_data = US"$smtp_active_hostname",
+ .hosts_override = FALSE,
+ .hosts_randomize = FALSE,
+ .gethostbyname = FALSE,
+ .qualify_single = TRUE,
+ .search_parents = FALSE
};
/* If verification yielded a remote transport, we want to use that
@@ -1879,7 +1941,7 @@ while (addr_new)
}
respond_printf(f, "%s\n", cr);
}
- cancel_cutthrough_connection("routing hard fail");
+ cancel_cutthrough_connection(TRUE, US"routing hard fail");
if (!full_info)
{
@@ -1918,7 +1980,7 @@ while (addr_new)
}
respond_printf(f, "%s\n", cr);
}
- cancel_cutthrough_connection("routing soft fail");
+ cancel_cutthrough_connection(TRUE, US"routing soft fail");
if (!full_info)
{
@@ -1991,7 +2053,7 @@ while (addr_new)
/* If stopped because more than one new address, cannot cutthrough */
if (addr_new && addr_new->next)
- cancel_cutthrough_connection("multiple addresses from routing");
+ cancel_cutthrough_connection(TRUE, US"multiple addresses from routing");
yield = OK;
goto out;
@@ -2241,18 +2303,16 @@ verify_check_header_names_ascii(uschar **msgptr)
header_line *h;
uschar *colon, *s;
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
{
- colon = Ustrchr(h->text, ':');
- for(s = h->text; s < colon; s++)
- {
- if ((*s < 33) || (*s > 126))
- {
- *msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
- colon - h->text, h->text);
- return FAIL;
- }
- }
+ colon = Ustrchr(h->text, ':');
+ for(s = h->text; s < colon; s++)
+ if ((*s < 33) || (*s > 126))
+ {
+ *msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
+ colon - h->text, h->text);
+ return FAIL;
+ }
}
return OK;
}
@@ -2622,8 +2682,11 @@ if (ip_bind(sock, host_af, interface_address, 0) < 0)
goto END_OFF;
}
+/*XXX could take advantage of TFO early-data. Hmm, what are the
+error returns; can we differentiate connect from data fails?
+Do we need to? */
if (ip_connect(sock, host_af, sender_host_address, port,
- rfc1413_query_timeout, TRUE) < 0)
+ rfc1413_query_timeout, &tcp_fastopen_nodata) < 0)
{
if (errno == ETIMEDOUT && LOGGING(ident_timeout))
log_write(0, LOG_MAIN, "ident connection to %s timed out",
@@ -3094,18 +3157,16 @@ verify_check_this_host(const uschar **listptr, unsigned int *cache_bits,
int rc;
unsigned int *local_cache_bits = cache_bits;
const uschar *save_host_address = deliver_host_address;
-check_host_block cb;
-cb.host_name = host_name;
-cb.host_address = host_address;
+check_host_block cb = { .host_name = host_name, .host_address = host_address };
-if (valueptr != NULL) *valueptr = NULL;
+if (valueptr) *valueptr = NULL;
/* If the host address starts off ::ffff: it is an IPv6 address in
IPv4-compatible mode. Find the IPv4 part for checking against IPv4
addresses. */
-cb.host_ipv4 = (Ustrncmp(host_address, "::ffff:", 7) == 0)?
- host_address + 7 : host_address;
+cb.host_ipv4 = Ustrncmp(host_address, "::ffff:", 7) == 0
+ ? host_address + 7 : host_address;
/* During the running of the check, put the IP address into $host_address. In
the case of calls from the smtp transport, it will already be there. However,
diff --git a/src/src/version.c b/src/src/version.c
index 04a2d0733..f27cc3cde 100644
--- a/src/src/version.c
+++ b/src/src/version.c
@@ -40,6 +40,16 @@ version_cnumber_format = US"%d\0<<eximcnumber>>";
sprintf(CS version_cnumber, CS version_cnumber_format, cnumber);
version_string = US EXIM_VERSION_STR "\0<<eximversion>>";
+#ifdef EXIM_BUILD_DATE_OVERRIDE
+/* Reproducible build support; build tooling should have given us something looking like
+ * "25-Feb-2017 20:15:40" in EXIM_BUILD_DATE_OVERRIDE based on $SOURCE_DATE_EPOCH in environ
+ * per <https://reproducible-builds.org/specs/source-date-epoch/>
+ */
+version_date = date_buffer;
+version_date[0] = 0;
+Ustrncat(version_date, EXIM_BUILD_DATE_OVERRIDE, sizeof(date_buffer));
+
+#else
Ustrcpy(today, __DATE__);
if (today[4] == ' ') today[4] = '0';
today[3] = today[6] = '-';
@@ -51,6 +61,7 @@ Ustrncat(version_date, today, 4);
Ustrncat(version_date, today+7, 4);
Ustrcat(version_date, " ");
Ustrcat(version_date, __TIME__);
+#endif
}
/* End of version.c */
diff --git a/test/confs/0021 b/test/confs/0021
index ae5a309b9..cb057386e 100644
--- a/test/confs/0021
+++ b/test/confs/0021
@@ -67,7 +67,7 @@ mail:
rcpt:
accept senders = +ok_senders
sender_domains = +ok_sender_domains
- logwrite = :panic: rcpt accepted
+ logwrite = :panic: rcpt accepted C=$smtp_command_history
# ----- Routers -----
diff --git a/test/confs/0211 b/test/confs/0211
index 96f3beac1..7856481df 100644
--- a/test/confs/0211
+++ b/test/confs/0211
@@ -30,7 +30,11 @@ begin routers
others:
driver = manualroute
domains = ! +local_domains
- route_list = * localhost4.test.ex byname
+.ifdef LIST
+ route_data = 127.0.0.1:HOSTIPV4
+.else
+ route_data = localhost4.test.ex byname
+.endif
self = send
transport = smtp
no_more
@@ -48,6 +52,7 @@ begin transports
smtp:
driver = smtp
port = PORT_S
+ command_timeout = 1s
local_delivery:
driver = appendfile
diff --git a/test/confs/0227 b/test/confs/0227
index ed988ac85..fea66e16f 100644
--- a/test/confs/0227
+++ b/test/confs/0227
@@ -24,6 +24,8 @@ check_recipient:
!verify = sender/callout=no_cache
deny hosts = V4NET.0.0.3
!verify = recipient/callout=no_cache
+ deny hosts = V4NET.0.0.7
+ !verify = recipient/callout=no_cache,use_sender,random
deny hosts = V4NET.0.0.5
!verify = sender/callout=no_cache/check_postmaster
deny hosts = V4NET.0.0.6
diff --git a/test/confs/0547 b/test/confs/0547
index 5d172447e..f3442b25b 100644
--- a/test/confs/0547
+++ b/test/confs/0547
@@ -1,6 +1,7 @@
# Exim test configuration 0547
MAXNM = 100
+LOG_SELECTOR =
.include DIR/aux-var/std_conf_prefix
@@ -10,7 +11,7 @@ primary_hostname = myhost.test.ex
acl_smtp_rcpt = accept
-log_selector = +smtp_no_mail
+log_selector = +smtp_no_mail LOG_SELECTOR
smtp_accept_max_nonmail = MAXNM
diff --git a/test/confs/0580 b/test/confs/0580
new file mode 100644
index 000000000..54ef7ae70
--- /dev/null
+++ b/test/confs/0580
@@ -0,0 +1,46 @@
+# Exim test configuration 0580
+
+OPT =
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = check_rcpt
+
+log_selector = +received_recipients
+OPT
+
+# ----- ACLs -----
+
+begin acl
+
+check_rcpt:
+ accept verify = recipient/callout=use_sender,hold
+
+
+# ----- Routers -----
+
+begin routers
+
+r1:
+ driver = manualroute
+ route_list = * 127.0.0.1
+ self = send
+ transport = t1
+
+
+begin transports
+
+t1:
+ driver = smtp
+ port = PORT_S
+
+
+# ----- Retry -----
+begin retry
+
+* * F,5d,10s
+# End
diff --git a/test/confs/0581 b/test/confs/0581
new file mode 120000
index 000000000..35e8a25bd
--- /dev/null
+++ b/test/confs/0581
@@ -0,0 +1 @@
+0580 \ No newline at end of file
diff --git a/test/confs/0582 b/test/confs/0582
new file mode 120000
index 000000000..35e8a25bd
--- /dev/null
+++ b/test/confs/0582
@@ -0,0 +1 @@
+0580 \ No newline at end of file
diff --git a/test/confs/0906 b/test/confs/0906
new file mode 100644
index 000000000..0c7b83d5e
--- /dev/null
+++ b/test/confs/0906
@@ -0,0 +1,97 @@
+# Exim test configuration 0906
+SERVER=
+
+exim_path = EXIM_PATH
+keep_environment =
+host_lookup_order = bydns
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/SERVER%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+chunking_advertise_hosts = *
+tls_advertise_hosts = ${if eq {SRV}{tls} {*}}
+
+# ----- Main settings -----
+
+spool_wireformat = true
+
+primary_hostname = testhost.test.ex
+domainlist local_domains = @ : test.ex
+
+acl_smtp_rcpt = acl_r
+log_selector = +received_recipients
+
+.ifdef _OPT_MAIN_TLS_CERTIFICATE
+tls_certificate = DIR/aux-fixed/cert1
+tls_privatekey = DIR/aux-fixed/cert1
+.endif
+
+queue_run_in_order = true
+
+# ----- ACL -----
+
+begin acl
+acl_r:
+ accept condition = ${if != {$received_port}{PORT_S}}
+ control = queue_only
+ accept
+
+# ----- Routers -----
+
+begin routers
+
+to_server:
+ driver = accept
+ condition = ${if = {$received_port}{PORT_S}}
+ transport = remote_smtp${if eq {OPT}{dkim} {_dkim}}
+ errors_to = ""
+
+fail_remote_domains:
+ driver = redirect
+ domains = ! +local_domains
+ data = :fail: unrouteable mail domain "$domain"
+
+localuser:
+ driver = accept
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ file = DIR/test-mail/$local_part
+ headers_add = "X-body-linecount: $body_linecount\n\
+ X-message-linecount: $message_linecount\n\
+ X-received-count: $received_count"
+ return_path_add
+ user = CALLER
+
+remote_smtp:
+ driver = smtp
+ hosts = 127.0.0.1
+ port = PORT_D
+ allow_localhost
+
+remote_smtp_dkim:
+ driver = smtp
+ hosts = 127.0.0.1
+ port = PORT_D
+ allow_localhost
+
+.ifdef OPT
+ dkim_domain = test.ex
+ dkim_selector = sel
+ dkim_private_key = DIR/aux-fixed/dkim/dkim.private
+.ifndef HEADERS_MAXSIZE
+ dkim_sign_headers = LIST
+.endif
+.endif
+
+# ----- Retry -----
+
+begin retry
+* * F,30m,5m;
+# End
diff --git a/test/confs/0907 b/test/confs/0907
new file mode 100644
index 000000000..8cb2b1b6d
--- /dev/null
+++ b/test/confs/0907
@@ -0,0 +1,3 @@
+# This file contains a BOM at the very beginning
+tls_advertise_hosts =
+keep_environment =
diff --git a/test/confs/0908 b/test/confs/0908
new file mode 100644
index 000000000..27af1d5f2
--- /dev/null
+++ b/test/confs/0908
@@ -0,0 +1 @@
+.include DIR/confs/0907
diff --git a/test/confs/1990 b/test/confs/1990
new file mode 100644
index 000000000..4c2bdc29d
--- /dev/null
+++ b/test/confs/1990
@@ -0,0 +1,48 @@
+# Exim test configuration 1990
+# TCP Fast Open
+
+SERVER=
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+log_selector = +received_recipients +millisec
+
+# ----- Routers -----
+
+begin routers
+
+server:
+ driver = redirect
+ condition = ${if eq {SERVER}{server} {yes}{no}}
+ data = :blackhole:
+
+client:
+ driver = accept
+ condition = ${if eq {SERVER}{server}{no}{yes}}
+ transport = send_to_server
+
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server:
+ driver = smtp
+ allow_localhost
+ hosts = 127.0.0.1
+ port = PORT_D
+ hosts_try_fastopen = *
+
+# ----- Retry -----
+
+begin retry
+
+* * F,5d,10s
+
+
+# End
diff --git a/test/confs/2007 b/test/confs/2007
index 7b58b73ee..a16b9a57e 100644
--- a/test/confs/2007
+++ b/test/confs/2007
@@ -16,6 +16,7 @@ queue_only
queue_run_in_order
tls_advertise_hosts = *
+tls_require_ciphers = NORMAL:!DHE-RSA:!DHE-DSS:!ECDHE-RSA:!ECDHE-ECDSA:!ECDHE-PSK
# Set certificate only if server
diff --git a/test/confs/2013 b/test/confs/2013
index 45d683cb4..208e17c41 100644
--- a/test/confs/2013
+++ b/test/confs/2013
@@ -29,6 +29,15 @@ tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
begin routers
+.ifdef REQUIRE
+cl_override:
+ driver = manualroute
+ route_data = HOSTIPV4
+ retry_use_local_part
+ transport = send_to_server
+ self = send
+.endif
+
client:
driver = accept
condition = ${if eq {SERVER}{server}{no}{yes}}
@@ -54,8 +63,10 @@ local_delivery:
send_to_server:
driver = smtp
allow_localhost
+ hosts_override
hosts = 127.0.0.1
hosts_noproxy_tls = :
port = PORT_D
+ tls_try_verify_hosts = :
# End
diff --git a/test/confs/2035 b/test/confs/2035
new file mode 100644
index 000000000..f7f225746
--- /dev/null
+++ b/test/confs/2035
@@ -0,0 +1,77 @@
+# Exim test configuration 2135
+
+.include DIR/aux-var/tls_conf_prefix
+
+.ifdef SERVER
+tls_certificate = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.chain.pem
+tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.unlocked.key
+.else
+tls_advertise_hosts =
+.endif
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+.ifdef SERVER
+acl_smtp_rcpt = srvr_rcpt
+acl_smtp_data = srvr_data
+.else
+acl_smtp_rcpt = client_rcpt
+acl_smtp_data = client_data
+.endif
+
+log_selector = +received_recipients +outgoing_port
+
+.ifdef SERVER
+queue_only
+queue_run_in_order = true
+.endif
+
+# ----- ACLs -----
+
+begin acl
+
+client_rcpt:
+ accept
+ verify = recipient/callout=use_sender,hold
+
+client_data:
+ accept
+
+srvr_rcpt:
+ defer local_parts = rcpt_defer
+ accept
+
+srvr_data:
+ defer condition = ${if eq {data_defer}{${local_part:$recipients}}}
+ accept
+
+# ----- Routers -----
+
+begin routers
+
+target:
+ driver = redirect
+ condition = ${if or {{eq {SERVER}{server}} {queue_running}}}
+ data = :blackhole:
+
+client:
+ driver = manualroute
+ route_list= * 127.0.0.1::PORT_D
+ self = send
+ transport = t1
+ errors_to = ""
+
+begin transports
+
+t1:
+ driver = smtp
+ tls_verify_certificates = DIR/aux-fixed/exim-ca/example.com/CA/CA.pem
+ tls_verify_cert_hostnames = :
+
+# ----- Retry -----
+begin retry
+
+* * F,5d,10s
+# End
diff --git a/test/confs/2036 b/test/confs/2036
new file mode 120000
index 000000000..3f3e22d7e
--- /dev/null
+++ b/test/confs/2036
@@ -0,0 +1 @@
+2035 \ No newline at end of file
diff --git a/test/confs/2037 b/test/confs/2037
new file mode 120000
index 000000000..3f3e22d7e
--- /dev/null
+++ b/test/confs/2037
@@ -0,0 +1 @@
+2035 \ No newline at end of file
diff --git a/test/confs/2038 b/test/confs/2038
new file mode 100644
index 000000000..140819433
--- /dev/null
+++ b/test/confs/2038
@@ -0,0 +1,63 @@
+# Exim test configuration 2035
+
+SERVER =
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector = +tls_peerdn+smtp_connection+incoming_port+received_recipients
+
+queue_only
+queue_run_in_order
+
+smtp_accept_max_nonmail = 0
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+ driver = manualroute
+ condition = ${if eq {SERVER}{server}{no}{yes}}
+ route_data = 127.0.0.1
+ self = send
+ retry_use_local_part
+ transport = send_to_server
+
+server:
+ driver = accept
+ retry_use_local_part
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ file = DIR/test-mail/$local_part
+ headers_add = TLS: cipher=$tls_cipher peerdn=$tls_peerdn
+ user = CALLER
+
+send_to_server:
+ driver = smtp
+ allow_localhost
+ hosts_noproxy_tls = :
+ port = PORT_D
+ max_rcpt = 1
+
+# End
diff --git a/test/confs/2052 b/test/confs/2052
deleted file mode 100644
index fd1f4d1c0..000000000
--- a/test/confs/2052
+++ /dev/null
@@ -1,67 +0,0 @@
-# Exim test configuration 2052
-# as per 2000 but with TCP Fast Open
-
-SERVER=
-
-.include DIR/aux-var/tls_conf_prefix
-
-primary_hostname = myhost.test.ex
-
-# ----- Main settings -----
-
-acl_smtp_rcpt = accept
-
-log_selector = +tls_peerdn
-
-queue_only
-queue_run_in_order
-
-tls_advertise_hosts = *
-# needed to force generation
-tls_dhparam = historic
-
-# Set certificate only if server
-
-tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-
-tls_verify_hosts = *
-tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
-
-
-# ----- Routers -----
-
-begin routers
-
-client:
- driver = accept
- condition = ${if eq {SERVER}{server}{no}{yes}}
- retry_use_local_part
- transport = send_to_server
-
-
-# ----- Transports -----
-
-begin transports
-
-send_to_server:
- driver = smtp
- allow_localhost
- hosts = 127.0.0.1
- port = PORT_D
- hosts_try_fastopen = *
- tls_certificate = DIR/aux-fixed/cert2
- tls_privatekey = DIR/aux-fixed/cert2
- tls_verify_certificates = DIR/aux-fixed/cert2
- tls_try_verify_hosts =
-
-
-# ----- Retry -----
-
-
-begin retry
-
-* * F,5d,10s
-
-
-# End
diff --git a/test/confs/2107 b/test/confs/2107
index 9487445cc..679367315 100644
--- a/test/confs/2107
+++ b/test/confs/2107
@@ -16,6 +16,7 @@ queue_only
queue_run_in_order
tls_advertise_hosts = *
+tls_require_ciphers = AES256-SHA
# Set certificate only if server
diff --git a/test/confs/2113 b/test/confs/2113
index bb64867a9..95b6842a9 100644
--- a/test/confs/2113
+++ b/test/confs/2113
@@ -29,6 +29,15 @@ tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
begin routers
+.ifdef REQUIRE
+cl_override:
+ driver = manualroute
+ route_data = HOSTIPV4
+ retry_use_local_part
+ transport = send_to_server
+ self = send
+.endif
+
client:
driver = accept
condition = ${if eq {SERVER}{server}{no}{yes}}
@@ -54,6 +63,7 @@ local_delivery:
send_to_server:
driver = smtp
allow_localhost
+ hosts_override
hosts = 127.0.0.1
hosts_noproxy_tls = :
port = PORT_D
diff --git a/test/confs/2135 b/test/confs/2135
new file mode 100644
index 000000000..f7f225746
--- /dev/null
+++ b/test/confs/2135
@@ -0,0 +1,77 @@
+# Exim test configuration 2135
+
+.include DIR/aux-var/tls_conf_prefix
+
+.ifdef SERVER
+tls_certificate = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.chain.pem
+tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.unlocked.key
+.else
+tls_advertise_hosts =
+.endif
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+.ifdef SERVER
+acl_smtp_rcpt = srvr_rcpt
+acl_smtp_data = srvr_data
+.else
+acl_smtp_rcpt = client_rcpt
+acl_smtp_data = client_data
+.endif
+
+log_selector = +received_recipients +outgoing_port
+
+.ifdef SERVER
+queue_only
+queue_run_in_order = true
+.endif
+
+# ----- ACLs -----
+
+begin acl
+
+client_rcpt:
+ accept
+ verify = recipient/callout=use_sender,hold
+
+client_data:
+ accept
+
+srvr_rcpt:
+ defer local_parts = rcpt_defer
+ accept
+
+srvr_data:
+ defer condition = ${if eq {data_defer}{${local_part:$recipients}}}
+ accept
+
+# ----- Routers -----
+
+begin routers
+
+target:
+ driver = redirect
+ condition = ${if or {{eq {SERVER}{server}} {queue_running}}}
+ data = :blackhole:
+
+client:
+ driver = manualroute
+ route_list= * 127.0.0.1::PORT_D
+ self = send
+ transport = t1
+ errors_to = ""
+
+begin transports
+
+t1:
+ driver = smtp
+ tls_verify_certificates = DIR/aux-fixed/exim-ca/example.com/CA/CA.pem
+ tls_verify_cert_hostnames = :
+
+# ----- Retry -----
+begin retry
+
+* * F,5d,10s
+# End
diff --git a/test/confs/2136 b/test/confs/2136
new file mode 120000
index 000000000..b9dc6e979
--- /dev/null
+++ b/test/confs/2136
@@ -0,0 +1 @@
+2135 \ No newline at end of file
diff --git a/test/confs/2137 b/test/confs/2137
new file mode 120000
index 000000000..b9dc6e979
--- /dev/null
+++ b/test/confs/2137
@@ -0,0 +1 @@
+2135 \ No newline at end of file
diff --git a/test/confs/2138 b/test/confs/2138
new file mode 100644
index 000000000..d6d7604d8
--- /dev/null
+++ b/test/confs/2138
@@ -0,0 +1,64 @@
+# Exim test configuration 2135
+
+SERVER =
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector = +tls_peerdn+smtp_connection+incoming_port+received_recipients
+
+queue_only
+queue_run_in_order
+
+smtp_accept_max_nonmail = 0
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+ driver = manualroute
+ condition = ${if eq {SERVER}{server}{no}{yes}}
+ route_data = 127.0.0.1
+ self = send
+ retry_use_local_part
+ transport = send_to_server
+
+server:
+ driver = accept
+ retry_use_local_part
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ file = DIR/test-mail/$local_part
+ headers_add = TLS: cipher=$tls_cipher peerdn=$tls_peerdn
+ user = CALLER
+
+send_to_server:
+ driver = smtp
+ allow_localhost
+ hosts_noproxy_tls = :
+ port = PORT_D
+ tls_try_verify_hosts = :
+ max_rcpt = 1
+
+# End
diff --git a/test/confs/2152 b/test/confs/2152
deleted file mode 100644
index a8b6c15f1..000000000
--- a/test/confs/2152
+++ /dev/null
@@ -1,68 +0,0 @@
-# Exim test configuration 2152
-# as per 2100 but with TCP Fast Open
-
-SERVER=
-
-.include DIR/aux-var/tls_conf_prefix
-
-primary_hostname = myhost.test.ex
-
-.ifdef _HAVE_TLS
-# that was purely to trigger the lazy-create of builtin macros
-.endif
-# ----- Main settings -----
-
-acl_smtp_rcpt = accept
-
-log_selector = +tls_peerdn
-
-queue_only
-queue_run_in_order
-
-tls_advertise_hosts = *
-
-# Set certificate only if server
-
-tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-
-tls_verify_hosts = *
-tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
-
-
-# ----- Routers -----
-
-begin routers
-
-client:
- driver = accept
- condition = ${if eq {SERVER}{server}{no}{yes}}
- retry_use_local_part
- transport = send_to_server
-
-
-# ----- Transports -----
-
-begin transports
-
-send_to_server:
- driver = smtp
- allow_localhost
- hosts = 127.0.0.1
- port = PORT_D
- hosts_try_fastopen = *
- tls_certificate = DIR/aux-fixed/cert2
- tls_privatekey = DIR/aux-fixed/cert2
- tls_verify_certificates = DIR/aux-fixed/cert2
- tls_try_verify_hosts = :
-
-
-# ----- Retry -----
-
-
-begin retry
-
-* * F,5d,10s
-
-
-# End
diff --git a/test/confs/4012 b/test/confs/4012
new file mode 100644
index 000000000..9afd4a07c
--- /dev/null
+++ b/test/confs/4012
@@ -0,0 +1,29 @@
+# Exim test configuration 4012
+# Content-scan: sock interface
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+av_scanner = sock : 127.0.0.1 PORT_S : : BAD : NAME:: (\w+)
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+acl_smtp_data = c_data
+
+begin acl
+
+c_data:
+ accept !malware = * OPT
+ deny logwrite = $callout_address malware_name $malware_name
+
+# ----- Routers -----
+
+begin routers
+
+r:
+ driver = redirect
+ data = :blackhole:
+
+# End
diff --git a/test/confs/4020 b/test/confs/4020
index 8dfd46888..05c95a571 100644
--- a/test/confs/4020
+++ b/test/confs/4020
@@ -32,11 +32,12 @@ my_main_router:
begin transports
my_smtp:
- driver = smtp
- interface = HOSTIPV4
- port = PORT_S
- hide socks_proxy = 127.0.0.1 port=PORT_D OPT
- debug_print = transport_name <$transport_name>
+ driver = smtp
+ interface = HOSTIPV4
+ port = PORT_S
+ hide socks_proxy = 127.0.0.1 port=PORT_D OPT
+ hosts_try_fastopen = ${if eq {$local_part}{user_tfo} {*}}
+ debug_print = transport_name <$transport_name>
# End
diff --git a/test/confs/4027 b/test/confs/4027
new file mode 120000
index 000000000..4af051ca9
--- /dev/null
+++ b/test/confs/4027
@@ -0,0 +1 @@
+4020 \ No newline at end of file
diff --git a/test/confs/4503 b/test/confs/4503
new file mode 120000
index 000000000..c4f73bacd
--- /dev/null
+++ b/test/confs/4503
@@ -0,0 +1 @@
+4500 \ No newline at end of file
diff --git a/test/confs/4520 b/test/confs/4520
index 70454c33c..897c1a675 100644
--- a/test/confs/4520
+++ b/test/confs/4520
@@ -12,6 +12,7 @@ primary_hostname = myhost.test.ex
acl_smtp_rcpt = accept
acl_smtp_dkim = accept logwrite = signer: $dkim_cur_signer bits: $dkim_key_length h=$dkim_headernames
+DDIR=DIR/aux-fixed/dkim
# ----- Routers
@@ -42,9 +43,18 @@ send_to_server:
.else
dkim_selector = sel
.endif
- dkim_private_key = DIR/aux-fixed/dkim/dkim.private
+
+ dkim_private_key = ${if match {$dkim_selector}{^ses} {DDIR/dkim512.private} \
+ {${if match {$dkim_selector}{^sel} {DDIR/dkim.private} \
+ {}}}}
+
.ifndef HEADERS_MAXSIZE
dkim_sign_headers = OPT
+.else
+ dkim_identity = allheaders@$dkim_domain
+.endif
+.ifdef VALUE
+ dkim_hash = VALUE
.endif
# End
diff --git a/test/confs/4523 b/test/confs/4523
new file mode 120000
index 000000000..072f5faf2
--- /dev/null
+++ b/test/confs/4523
@@ -0,0 +1 @@
+4520 \ No newline at end of file
diff --git a/test/confs/4524 b/test/confs/4524
new file mode 120000
index 000000000..072f5faf2
--- /dev/null
+++ b/test/confs/4524
@@ -0,0 +1 @@
+4520 \ No newline at end of file
diff --git a/test/confs/4530 b/test/confs/4530
new file mode 120000
index 000000000..a8ce02c97
--- /dev/null
+++ b/test/confs/4530
@@ -0,0 +1 @@
+0906 \ No newline at end of file
diff --git a/test/confs/5010 b/test/confs/5010
new file mode 100644
index 000000000..927f4a442
--- /dev/null
+++ b/test/confs/5010
@@ -0,0 +1,35 @@
+# Exim test configuration 5010
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+all:
+ driver = accept
+ retry_use_local_part
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ directory = DIR/test-mail
+ maildir_format
+ quota = 30/no_check
+ quota_filecount = 1
+ user = CALLER
+ maildir_use_size_file
+
+# End
diff --git a/test/confs/5011 b/test/confs/5011
new file mode 100644
index 000000000..f1a19a85d
--- /dev/null
+++ b/test/confs/5011
@@ -0,0 +1,35 @@
+# Exim test configuration 5011
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+all:
+ driver = accept
+ retry_use_local_part
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ directory = DIR/test-mail
+ maildir_format
+ quota = 30
+ quota_filecount = 1/no_check
+ user = CALLER
+ maildir_use_size_file
+
+# End
diff --git a/test/confs/5012 b/test/confs/5012
new file mode 100644
index 000000000..f4715bfab
--- /dev/null
+++ b/test/confs/5012
@@ -0,0 +1,35 @@
+# Exim test configuration 5011
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+all:
+ driver = accept
+ retry_use_local_part
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ directory = DIR/test-mail
+ maildir_format
+ quota = 30/no_check
+ quota_filecount = 1/no_check
+ user = CALLER
+ maildir_use_size_file
+
+# End
diff --git a/test/confs/5601 b/test/confs/5601
index 3309870a3..6e667b429 100644
--- a/test/confs/5601
+++ b/test/confs/5601
@@ -21,7 +21,7 @@ domainlist local_domains = test.ex : *.test.ex
acl_smtp_rcpt = check_recipient
acl_smtp_data = check_data
-log_selector = +tls_peerdn
+log_selector = +tls_peerdn +received_recipients
remote_max_parallel = 1
tls_advertise_hosts = *
diff --git a/test/confs/5740 b/test/confs/5740
index ccc907c82..4d41e820b 100644
--- a/test/confs/5740
+++ b/test/confs/5740
@@ -21,7 +21,7 @@ domainlist local_domains = test.ex : *.test.ex
acl_smtp_rcpt = check_recipient
acl_smtp_data = check_data
-log_selector = +tls_peerdn
+log_selector = +tls_peerdn +received_recipients
remote_max_parallel = 1
tls_advertise_hosts = *
@@ -71,7 +71,7 @@ client:
condition = ${if eq {SERVER}{server}{no}{yes}}
retry_use_local_part
transport = send_to_server${if eq{$local_part}{nostaple}{1} \
- {${if eq{$local_part}{norequire} {2} \
+ {${if match{$local_part}{norequire} {2} \
{${if eq{$local_part}{smtps} {4}{3}}} \
}}}
diff --git a/test/confs/5840 b/test/confs/5840
index ac3578dc9..01c114252 100644
--- a/test/confs/5840
+++ b/test/confs/5840
@@ -61,10 +61,10 @@ begin transports
send_to_server:
driver = smtp
allow_localhost
- port = PORT_D
+ port = ${if match {$host}{\Ntest.ex$\N} {PORT_D}{25}}
hosts_try_dane = *
- hosts_require_dane = !thishost.test.ex
+ hosts_require_dane = HOSTIPV4
tls_verify_cert_hostnames = ${if eq {OPT}{no_certname} {}{*}}
tls_try_verify_hosts = thishost.test.ex
tls_verify_certificates = CDIR2/ca_chain.pem
diff --git a/test/dnszones-src/db.test.ex b/test/dnszones-src/db.test.ex
index 349fbd4d3..73db57f9c 100644
--- a/test/dnszones-src/db.test.ex
+++ b/test/dnszones-src/db.test.ex
@@ -461,10 +461,24 @@ DNSSEC danelazy2 A 127.0.0.1
DNSSEC _1225._tcp.danelazy CNAME test.again.dns.
DNSSEC _1225._tcp.danelazy2 CNAME test.again.dns.
-; hosts with no TLSA
+; hosts with no TLSA (just missing here, hence the TLSA NXDMAIN is _insecure_; a broken dane config)
+; 1 for dane-required, 2 for merely requested
DNSSEC dane.no.1 A HOSTIPV4
DNSSEC dane.no.2 A 127.0.0.1
+; a broken dane config (or under attack) where the TLSA lookup fails (as opposed to there not being one)
+DNSSEC danebroken1 A 127.0.0.1
+_1225._tcp.danebroken1 CNAME test.fail.dns.
+
+; a good dns config saying there is no dane support, by securely returning NOXDOMAIN for TLSA lookups
+; 3 for dane-required, 4 for merely requested
+; the TLSA data here is dummy; ignored
+DNSSEC dane.no.3 A HOSTIPV4
+DNSSEC dane.no.4 A 127.0.0.1
+
+DNSSEC NXDOMAIN _1225._tcp.dane.no.3 TLSA 2 0 1 eec923139018c540a344c5191660ecba1ac3708525a98bfc338e17f31d3fa741
+DNSSEC NXDOMAIN _1225._tcp.dane.no.4 TLSA 2 0 1 eec923139018c540a344c5191660ecba1ac3708525a98bfc338e17f31d3fa741
+
; ------- Testing delays ------------
DELAY=500 delay500 A HOSTIPV4
@@ -477,13 +491,19 @@ DELAY=1500 delay1500 A HOSTIPV4
; openssl rsa -in aux-fixed/dkim/dkim.private -out /dev/stdout -pubout -outform PEM
;
; Deliberate bad version, having extra backslashes
+; sha256-hash-only version.... appears to be too long, gets truncated
;
; Another, 512-bit (with a Notes field)
+; 512 requiring sha1 hash
+; 512 requiring sha256 hash
;
sel._domainkey TXT "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
sel_bad._domainkey TXT "v=DKIM1\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
+sel_sha256._domainkey TXT "v=DKIM1; h=sha256; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
ses._domainkey TXT "v=DKIM1; n=halfkilo; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
+ses_sha1._domainkey TXT "v=DKIM1; h=sha1; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
+ses_sha256._domainkey TXT "v=DKIM1; h=sha256; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
; End
diff --git a/test/lib/Exim/Runtest.pm b/test/lib/Exim/Runtest.pm
index 537cea1e9..e41a29c8c 100644
--- a/test/lib/Exim/Runtest.pm
+++ b/test/lib/Exim/Runtest.pm
@@ -137,7 +137,7 @@ sub flavour {
sub flavours {
my %h = map { /\.(\S+)$/, 1 }
- glob('stdout/*.*'), glob('stderr/*.*');
+ grep { !/\.orig$/ } glob('stdout/*.*'), glob('stderr/*.*');
return sort keys %h;
}
diff --git a/test/log/0211 b/test/log/0211
index 74acec3a3..ac647a67b 100644
--- a/test/log/0211
+++ b/test/log/0211
@@ -14,6 +14,7 @@
1999-03-02 09:44:33 End queue run: pid=pppp -qf
1999-03-02 09:44:33 Test: reject connect
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away (A)
1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away (A)
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> F=<> R=all T=local_delivery
@@ -22,6 +23,7 @@
1999-03-02 09:44:33 End queue run: pid=pppp -qf
1999-03-02 09:44:33 Test: reject helo
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away (C)
1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away (C)
1999-03-02 09:44:33 10HmaZ-0005vi-00 ** usery@domain2 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away (C)
1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
@@ -32,3 +34,9 @@
1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmbB-0005vi-00 H=localhost4.test.ex [127.0.0.1]: Remote host closed connection in response to HELO the.local.host.name (EHLO response was: 550 You are banned)
1999-03-02 09:44:33 10HmbB-0005vi-00 == userx@domain1 R=others T=smtp defer (-18) H=localhost4.test.ex [127.0.0.1]: Remote host closed connection in response to HELO the.local.host.name (EHLO response was: 550 You are banned)
+1999-03-02 09:44:33 Test: smtp-reject conn on 1MX, timeout TCP conn on 2MX
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbB-0005vi-00 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 554 no smtp service here
+1999-03-02 09:44:33 10HmbB-0005vi-00 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4]: SMTP timeout after initial connection: Connection timed out
+1999-03-02 09:44:33 10HmbB-0005vi-00 == userx@domain1 R=others T=smtp defer (dd): Connection timed out H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4]: SMTP timeout after initial connection
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/0227 b/test/log/0227
index f1e64701c..d91075fb6 100644
--- a/test/log/0227
+++ b/test/log/0227
@@ -14,6 +14,9 @@
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify fail for <ok@localhost1>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<postmaster@localhost1>: 550 Don't like postmaster
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: Sender verify failed
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.7] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<uncheckable@localhost1> rejected RCPT <z@remote.lmtp>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<z@remote.lmtp>: 550 Recipient not liked
1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root sender verify defer for <bad@localhost1>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : Remote host closed connection in response to initial connection
1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root F=<bad@localhost1> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
diff --git a/test/log/0376 b/test/log/0376
index 0e2f661ac..fa191bcd5 100644
--- a/test/log/0376
+++ b/test/log/0376
@@ -12,10 +12,6 @@
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
1999-03-02 09:44:33 10HmaX-0005vi-00 <= ok7@otherhost53 H=[V4NET.0.0.7] U=root P=smtp S=sss
diff --git a/test/log/0429 b/test/log/0429
index cb75f6cf4..d477a6b9b 100644
--- a/test/log/0429
+++ b/test/log/0429
@@ -1,5 +1,6 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after HELO myhost.test.ex: 550 No
1999-03-02 09:44:33 10HmaX-0005vi-00 ** x@y R=r1 T=t1 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after HELO myhost.test.ex: 550 No
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
diff --git a/test/log/0506 b/test/log/0506
index d74b21dab..e0140f58b 100644
--- a/test/log/0506
+++ b/test/log/0506
@@ -1,7 +1,7 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmaX-0005vi-00 => discarded <exim-filter@test.ex> R=r1
1999-03-02 09:44:33 10HmaX-0005vi-00 => discarded <sieve-filter@test.ex> R=r1
-1999-03-02 09:44:33 10HmaX-0005vi-00 Completed QT=0s
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed QT=qqs
1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmaY-0005vi-00 => discarded <exim-filter@test.ex> R=r1
1999-03-02 09:44:33 10HmaY-0005vi-00 == sieve-filter@test.ex R=r1 defer (-17): error in filter file: Sieve filtering not enabled
diff --git a/test/log/0547 b/test/log/0547
index 34defc347..79b4ace5b 100644
--- a/test/log/0547
+++ b/test/log/0547
@@ -1,9 +1,10 @@
1999-03-02 09:44:33 U=CALLER rejected EXPN x@y
-1999-03-02 09:44:33 no MAIL in SMTP connection from CALLER D=0s C=EXPN,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from CALLER D=qqs C=EXPN,QUIT
******** SERVER ********
+2017-07-30 18:51:05.712 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+2017-07-30 18:51:05.712 no MAIL in SMTP connection from [127.0.0.1] D=q.qqqs
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s C=QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=qqs C=QUIT
1999-03-02 09:44:33 H=(x.y.z) [127.0.0.1] rejected VRFY a@b.c
-1999-03-02 09:44:33 no MAIL in SMTP connection from (x.y.z) [127.0.0.1] D=0s C=EHLO,VRFY,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from (x.y.z) [127.0.0.1] D=qqs C=EHLO,VRFY,QUIT
diff --git a/test/log/0551 b/test/log/0551
index 831e11a89..5baae67cb 100644
--- a/test/log/0551
+++ b/test/log/0551
@@ -3,9 +3,9 @@
1999-03-02 09:44:33 [1235] 10HmaX-0005vi-00 => usery <usery@test.ex> R=r1 T=t1
1999-03-02 09:44:33 [1235] 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 [1236] 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=qqs
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1 QT=qqs
1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=q.qqqs DT=q.qqqs
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed QT=q.qqqs
diff --git a/test/log/0578 b/test/log/0578
index 7c38e638c..60ddf3c13 100644
--- a/test/log/0578
+++ b/test/log/0578
@@ -12,10 +12,6 @@
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK accepting that random recipient
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
1999-03-02 09:44:33 10HmaX-0005vi-00 <= ok7@otherhost53 H=[V4NET.0.0.7] U=root P=smtp S=sss
diff --git a/test/log/0580 b/test/log/0580
new file mode 100644
index 000000000..f006778e5
--- /dev/null
+++ b/test/log/0580
@@ -0,0 +1,15 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery@test.ex usery2@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaY-0005vi-00 -> usery2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery3@test.ex usery@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery3@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 -> usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery4@test.ex usery5@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => usery4@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 -> usery5@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
diff --git a/test/log/0581 b/test/log/0581
new file mode 100644
index 000000000..f554e0057
--- /dev/null
+++ b/test/log/0581
@@ -0,0 +1,23 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userd@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userf@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex userd2@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userd@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 -> userd2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd3@test.ex userd2@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userd3@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 -> userd2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd4@test.ex userd5@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userd4@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbB-0005vi-00 -> userd5@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
diff --git a/test/log/0582 b/test/log/0582
new file mode 100644
index 000000000..8953064ef
--- /dev/null
+++ b/test/log/0582
@@ -0,0 +1,3 @@
+1999-03-02 09:44:33 U=CALLER F=<userg@ok.example> temporarily rejected RCPT <userg@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<userg@test.ex>: 451 not right now
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userh@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 == userh@test.ex R=r1 T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after end of data: 451 not right now
diff --git a/test/log/0609 b/test/log/0609
index a19051aa1..b395954a4 100644
--- a/test/log/0609
+++ b/test/log/0609
@@ -4,4 +4,4 @@
1999-03-02 09:44:33 SMTP connection from [127.0.0.1] (TCP/IP connection count = 1)
1999-03-02 09:44:33 SMTP connection from [127.0.0.1] closed by QUIT
1999-03-02 09:44:33 SMTP connection from [127.0.0.1] (TCP/IP connection count = 1)
-1999-03-02 09:44:33 unexpected disconnection while reading SMTP command from [127.0.0.1]
+1999-03-02 09:44:33 unexpected disconnection while reading SMTP command from [127.0.0.1] D=qqs
diff --git a/test/log/0901 b/test/log/0901
index cd8c52e75..0297a8915 100644
--- a/test/log/0901
+++ b/test/log/0901
@@ -10,6 +10,6 @@
1999-03-02 09:44:33 SMTP connection from (tester) [127.0.0.1] lost while reading message data
1999-03-02 09:44:33 SMTP connection from (tester) [127.0.0.1] lost while reading message data
1999-03-02 09:44:33 10HmbD-0005vi-00 <= someone8@some.domain H=(tester) [127.0.0.1] P=esmtp K S=sss for CALLER@test.ex
-1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "bdat 1" H=(tester) [127.0.0.1] next input="bdat 87 last\r\n"
+1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "BDAT 1" H=(tester) [127.0.0.1] next input="BDAT 87 last\r\n"
1999-03-02 09:44:33 SMTP call from (tester) [127.0.0.1] dropped: too many syntax or protocol errors (last command was "From: Sam@random.com")
1999-03-02 09:44:33 SMTP connection from (tester) [127.0.0.1] lost while reading message data (header)
diff --git a/test/log/0906 b/test/log/0906
new file mode 100644
index 000000000..12e227677
--- /dev/null
+++ b/test/log/0906
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a <a@test.ex> R=localuser T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= sender@dom H=(test.com) [127.0.0.1] P=esmtp K S=sss for a@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= <> H=localhost (testhost.test.ex) [127.0.0.1] P=esmtp K S=sss for a@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmaY-0005vi-00 => a@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] K C="250- 8nn byte chunk, total 8nn\\n250 OK id=10HmaX-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/1990 b/test/log/1990
new file mode 100644
index 000000000..36a7a56b6
--- /dev/null
+++ b/test/log/1990
@@ -0,0 +1,15 @@
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for a@test.ex
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 => a@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaY-0005vi-00"
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for b@test.ex
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => b@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] TFO C="250 OK id=10HmbA-0005vi-00"
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed
+
+******** SERVER ********
+2017-07-30 18:51:05.712 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex for a@test.ex
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] TFO P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for b@test.ex
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 => :blackhole: <b@test.ex> R=server
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 Completed
diff --git a/test/log/2013 b/test/log/2013
index 79bc3f612..fc71b5f24 100644
--- a/test/log/2013
+++ b/test/log/2013
@@ -4,11 +4,22 @@
1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbB-0005vi-00"
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbC-0005vi-00"
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usera@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userc@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbI-0005vi-00"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
@@ -25,3 +36,17 @@
1999-03-02 09:44:33 10HmbC-0005vi-00 => usery <usery@test.ex> R=server T=local_delivery
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbD-0005vi-00@myhost.test.ex for usera@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbF-0005vi-00@myhost.test.ex for userc@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbE-0005vi-00@myhost.test.ex for userb@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbG-0005vi-00 => usera <usera@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbH-0005vi-00 => userc <userc@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbI-0005vi-00 => userb <userb@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2035 b/test/log/2035
new file mode 100644
index 000000000..ea335213a
--- /dev/null
+++ b/test/log/2035
@@ -0,0 +1,11 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userb@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usera@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userb@test.ex
diff --git a/test/log/2036 b/test/log/2036
new file mode 100644
index 000000000..33b6423ef
--- /dev/null
+++ b/test/log/2036
@@ -0,0 +1,14 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userd@test.ex> R=target
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userf@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex
diff --git a/test/log/2037 b/test/log/2037
new file mode 100644
index 000000000..ac307f28d
--- /dev/null
+++ b/test/log/2037
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for data_defer@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 == data_defer@test.ex R=client T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]:1111: SMTP error from remote mail server after end of data: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected after DATA
diff --git a/test/log/2038 b/test/log/2038
new file mode 100644
index 000000000..b3dfed849
--- /dev/null
+++ b/test/log/2038
@@ -0,0 +1,42 @@
+**NOTE: The delivery lines in this file have been sorted.
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userx0@test.ex userx1@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usery0@test.ex usery1@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userz0@test.ex userz1@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbD-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbF-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1111 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx0@test.ex
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 2)
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx1@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz0@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1111 closed by QUIT
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery0@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userx0 <userx0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userx1 <userx1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 => userz0 <userz0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userz1 <userz1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => usery0 <usery0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => usery1 <usery1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2052 b/test/log/2052
deleted file mode 100644
index 04c72f5eb..000000000
--- a/test/log/2052
+++ /dev/null
@@ -1,12 +0,0 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 Start queue run: pid=pppp -qf
-1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session: (certificate verification failed): certificate invalid: delivering unencrypted to H=127.0.0.1 [127.0.0.1] (not in hosts_require_tls)
-1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaY-0005vi-00"
-1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qf
-
-******** SERVER ********
-1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (recv): A TLS fatal alert has been received.: Certificate is bad
-1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (send): The specified session has been invalidated for some reason.
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
diff --git a/test/log/2091 b/test/log/2091
index 78638261b..1e8f6bb19 100644
--- a/test/log/2091
+++ b/test/log/2091
@@ -1,5 +1,5 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= this-user@testhost.test.ex U=this-user P=local S=sss for other-user@test.ex
-1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no K C="250- 351 byte chunk, total 351\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no K C="250- 3nn byte chunk, total 3nn\\n250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
******** SERVER ********
diff --git a/test/log/2113 b/test/log/2113
index 08b08cc84..1d3ca3332 100644
--- a/test/log/2113
+++ b/test/log/2113
@@ -4,11 +4,22 @@
1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbB-0005vi-00"
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbC-0005vi-00"
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usera@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userc@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbI-0005vi-00"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
@@ -25,3 +36,17 @@
1999-03-02 09:44:33 10HmbC-0005vi-00 => usery <usery@test.ex> R=server T=local_delivery
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@myhost.test.ex for usera@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbF-0005vi-00@myhost.test.ex for userc@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbE-0005vi-00@myhost.test.ex for userb@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbG-0005vi-00 => usera <usera@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbH-0005vi-00 => userc <userc@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbI-0005vi-00 => userb <userb@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2135 b/test/log/2135
new file mode 100644
index 000000000..50a8dbc19
--- /dev/null
+++ b/test/log/2135
@@ -0,0 +1,11 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userb@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usera@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userb@test.ex
diff --git a/test/log/2136 b/test/log/2136
new file mode 100644
index 000000000..33b6423ef
--- /dev/null
+++ b/test/log/2136
@@ -0,0 +1,14 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userd@test.ex> R=target
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userf@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex
diff --git a/test/log/2137 b/test/log/2137
new file mode 100644
index 000000000..360f31ed6
--- /dev/null
+++ b/test/log/2137
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for data_defer@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 == data_defer@test.ex R=client T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]:1111: SMTP error from remote mail server after end of data: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected after DATA
diff --git a/test/log/2138 b/test/log/2138
new file mode 100644
index 000000000..6bc8e0284
--- /dev/null
+++ b/test/log/2138
@@ -0,0 +1,42 @@
+**NOTE: The delivery lines in this file have been sorted.
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userx0@test.ex userx1@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usery0@test.ex usery1@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userz0@test.ex userz1@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbD-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbF-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1111 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx0@test.ex
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 2)
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx1@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz0@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1111 closed by QUIT
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery0@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userx0 <userx0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userx1 <userx1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 => userz0 <userz0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userz1 <userz1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => usery0 <usery0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => usery1 <usery1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2152 b/test/log/2152
deleted file mode 100644
index 1ed6351ff..000000000
--- a/test/log/2152
+++ /dev/null
@@ -1,9 +0,0 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 Start queue run: pid=pppp -qf
-1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmaY-0005vi-00"
-1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qf
-
-******** SERVER ********
-1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=yes DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
diff --git a/test/log/2191 b/test/log/2191
index 4b8b84f4b..c2c1f8742 100644
--- a/test/log/2191
+++ b/test/log/2191
@@ -1,7 +1,7 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= this-user@testhost.test.ex U=this-user P=local S=sss for other-user@test.ex
1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
-1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no K C="250- 351 byte chunk, total 351\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no K C="250- 3nn byte chunk, total 3nn\\n250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
******** SERVER ********
diff --git a/test/log/3454 b/test/log/3454
index d047667e7..7578fc090 100644
--- a/test/log/3454
+++ b/test/log/3454
@@ -3,5 +3,5 @@
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
1999-03-02 09:44:33 TLS error on connection from [127.0.0.1] (recv): The TLS connection was non-properly terminated.
1999-03-02 09:44:33 TLS error on connection from [127.0.0.1] (send): The specified session has been invalidated for some reason.
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,AUTH
-1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=0s A=plain:userx X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=qqs X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,AUTH
+1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=qqs A=plain:userx X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
diff --git a/test/log/3464 b/test/log/3464
index 2063b33ba..842c13ade 100644
--- a/test/log/3464
+++ b/test/log/3464
@@ -1,5 +1,5 @@
******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,AUTH
-1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=0s A=plain:userx X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=qqs X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,AUTH
+1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=qqs A=plain:userx X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
diff --git a/test/log/4027 b/test/log/4027
new file mode 100644
index 000000000..3af3f325b
--- /dev/null
+++ b/test/log/4027
@@ -0,0 +1,6 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 TFO C="250 accepted OK"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 TFO C="250 accepted OK"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/4203 b/test/log/4203
index a1acf570e..1c2d52830 100644
--- a/test/log/4203
+++ b/test/log/4203
@@ -1,4 +1,5 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
1999-03-02 09:44:33 10HmaX-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
diff --git a/test/log/4213 b/test/log/4213
index e0c0a43d9..1a9aa5eae 100644
--- a/test/log/4213
+++ b/test/log/4213
@@ -1,4 +1,5 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
1999-03-02 09:44:33 10HmaX-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no: utf8 support required but not offered for forwarding
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
diff --git a/test/log/4223 b/test/log/4223
index fb5a1defe..f4d4efa3a 100644
--- a/test/log/4223
+++ b/test/log/4223
@@ -1,4 +1,5 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
1999-03-02 09:44:33 10HmaX-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no: utf8 support required but not offered for forwarding
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
diff --git a/test/log/4500 b/test/log/4500
index 0e0f8400d..ec8ef088e 100644
--- a/test/log/4500
+++ b/test/log/4500
@@ -10,3 +10,6 @@
1999-03-02 09:44:33 10HmaZ-0005vi-00 DKIM: d=test.ex s=sel c=simple/simple a=rsa-sha256 b=1024 [verification succeeded]
1999-03-02 09:44:33 10HmaZ-0005vi-00 signer: test.ex bits: 1024
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
+1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=ses_sha1 c=simple/simple a=rsa-sha1 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmbA-0005vi-00 signer: test.ex bits: 512
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
diff --git a/test/log/4503 b/test/log/4503
new file mode 100644
index 000000000..7ec93a1f5
--- /dev/null
+++ b/test/log/4503
@@ -0,0 +1,6 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 DKIM: d=test.ex s=sel c=simple/simple a=rsa-sha512 b=1024 [verification failed - signature did not verify (headers probably modified in transit)]
+1999-03-02 09:44:33 10HmaX-0005vi-00 signer: test.ex bits: 1024
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
diff --git a/test/log/4506 b/test/log/4506
index fb0f22567..027169df0 100644
--- a/test/log/4506
+++ b/test/log/4506
@@ -13,3 +13,6 @@
1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: validation error: RSA_LONG_LINE
1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: Error during validation, disabling signature verification: RSA_LONG_LINE
1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
+1999-03-02 09:44:33 10HmbB-0005vi-00 DKIM: d=test.ex s=ses_sha256 c=simple/simple a=rsa-sha1 b=512 [verification failed - unspecified reason]
+1999-03-02 09:44:33 10HmbB-0005vi-00 signer: test.ex bits: 512
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
diff --git a/test/log/4520 b/test/log/4520
index e9736fd6f..8daa636c0 100644
--- a/test/log/4520
+++ b/test/log/4520
@@ -23,13 +23,14 @@
1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex
1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <b@test.ex> R=server_dump
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 i=allheaders@test.ex [verification succeeded]
1999-03-02 09:44:33 10HmbC-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmbC-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbB-0005vi-00@myhost.test.ex
1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <c@test.ex> R=server_dump
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
1999-03-02 09:44:33 10HmbE-0005vi-00 DKIM: d=test.ex s=sel_bad c=relaxed/relaxed a=rsa-sha256 b=1024 [invalid - syntax error in public key record]
-1999-03-02 09:44:33 10HmbE-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmbE-0005vi-00 signer: test.ex bits: 1024 h=From
1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbD-0005vi-00@myhost.test.ex
1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <d@test.ex> R=server_dump
1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
diff --git a/test/log/4521 b/test/log/4521
index 052569fa9..3eaa19eb0 100644
--- a/test/log/4521
+++ b/test/log/4521
@@ -1,8 +1,8 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= sender@testhost.test.ex U=sender P=local S=sss for a@test.ex
-1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 661 byte chunk, total 661\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 6nn byte chunk, total 6nn\\n250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= sender@testhost.test.ex U=sender P=local S=sss for b@test.ex
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => b@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 8520 byte chunk, total 8848\\n250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => b@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 8nn byte chunk, total 8nn\\n250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
******** SERVER ********
diff --git a/test/log/4523 b/test/log/4523
new file mode 100644
index 000000000..d1e5ebba3
--- /dev/null
+++ b/test/log/4523
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 i=allheaders@test.ex [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server_dump
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/4524 b/test/log/4524
new file mode 100644
index 000000000..a6d687c83
--- /dev/null
+++ b/test/log/4524
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => c@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=ses c=relaxed/relaxed a=rsa-sha256 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 512 h=From:To:Subject
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <c@test.ex> R=server_dump
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/4530 b/test/log/4530
new file mode 100644
index 000000000..f4ff0117c
--- /dev/null
+++ b/test/log/4530
@@ -0,0 +1,21 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => z <z@test.ex> R=localuser T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => y <y@test.ex> R=localuser T=local_delivery
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1224 port 1225
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=esmtp S=sss for z@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= <> H=localhost (testhost.test.ex) [127.0.0.1] P=esmtp K S=sss for z@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => z@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 6nn byte chunk, total 6nn\\n250 OK id=10HmaX-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=esmtp K S=sss for y@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> H=localhost (testhost.test.ex) [127.0.0.1] P=esmtp K S=sss for y@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmbA-0005vi-00 => y@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 6nn byte chunk, total 6nn\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
diff --git a/test/log/4700 b/test/log/4700
index 35da72e04..8a1a7a4f4 100644
--- a/test/log/4700
+++ b/test/log/4700
@@ -6,6 +6,7 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 == userx@domain1 R=others T=smtp defer (0) H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 450 I'm busy
1999-03-02 09:44:33 End queue run: pid=pppp -qf
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away
1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away
1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> F=<> R=all T=local_delivery
@@ -13,6 +14,7 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qf
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
1999-03-02 09:44:33 10HmaZ-0005vi-00 ** usery@domain2 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
diff --git a/test/log/5002 b/test/log/5002
index 6c45cd787..f4ba74f72 100644
--- a/test/log/5002
+++ b/test/log/5002
@@ -2,7 +2,7 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaY-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaY-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 10HmaZ-0005vi-00 == qqq@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
diff --git a/test/log/5010 b/test/log/5010
new file mode 100644
index 000000000..deaedc617
--- /dev/null
+++ b/test/log/5010
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaY-0005vi-00 ** userx@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= <> R=10HmaY-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 == CALLER@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** CALLER@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaZ-0005vi-00 CALLER@test.ex: error ignored
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/5011 b/test/log/5011
new file mode 100644
index 000000000..e0c7efe99
--- /dev/null
+++ b/test/log/5011
@@ -0,0 +1,18 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 == CALLER@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaY-0005vi-00 ** CALLER@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaY-0005vi-00 CALLER@test.ex: error ignored
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmbA-0005vi-00 == CALLER@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmbA-0005vi-00 ** CALLER@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmbA-0005vi-00 CALLER@test.ex: error ignored
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
diff --git a/test/log/5012 b/test/log/5012
new file mode 100644
index 000000000..e2d436abc
--- /dev/null
+++ b/test/log/5012
@@ -0,0 +1,6 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/5601 b/test/log/5601
index 2ddf7e2cd..564369845 100644
--- a/test/log/5601
+++ b/test/log/5601
@@ -1,35 +1,35 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for norequire@test.ex
1999-03-02 09:44:33 10HmaX-0005vi-00 => norequire@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for nostaple@test.ex
1999-03-02 09:44:33 10HmaZ-0005vi-00 => nostaple@test.ex R=client T=send_to_server1 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmbB-0005vi-00 => CALLER@test.ex R=client T=send_to_server3 H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmbD-0005vi-00 Received TLS status callback, null content
1999-03-02 09:44:33 10HmbD-0005vi-00 == CALLER@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmbE-0005vi-00 Server certificate revoked; reason: superseded
1999-03-02 09:44:33 10HmbE-0005vi-00 == CALLER@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
1999-03-02 09:44:33 10HmbF-0005vi-00 Server OSCP dates invalid
1999-03-02 09:44:33 10HmbF-0005vi-00 == CALLER@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
1999-03-02 09:44:33 10HmaY-0005vi-00 client claims: ocsp status 1 (notresp)
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com for norequire@test.ex
1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <norequire@test.ex> R=server
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
1999-03-02 09:44:33 10HmbA-0005vi-00 client claims: ocsp status 0 (notreq)
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com for nostaple@test.ex
1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <nostaple@test.ex> R=server
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
1999-03-02 09:44:33 10HmbC-0005vi-00 client claims: ocsp status 4 (verified)
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com for CALLER@test.ex
1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <CALLER@test.ex> R=server
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
diff --git a/test/log/5740 b/test/log/5740
index 3fc357b76..2b82395f9 100644
--- a/test/log/5740
+++ b/test/log/5740
@@ -1,28 +1,28 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaX-0005vi-00 => norequire@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for norequire_1@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => norequire_1@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
1999-03-02 09:44:33 10HmaX-0005vi-00 client ocsp status: 1 (notresp)
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => norequire@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for norequire_2@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => norequire_2@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
1999-03-02 09:44:33 10HmaZ-0005vi-00 client ocsp status: 4 (verified)
1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for nostaple@test.ex
1999-03-02 09:44:33 10HmbB-0005vi-00 => nostaple@test.ex R=client T=send_to_server1 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
1999-03-02 09:44:33 10HmbB-0005vi-00 client ocsp status: 0 (notreq)
1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for good@test.ex
1999-03-02 09:44:33 10HmbD-0005vi-00 => good@test.ex R=client T=send_to_server3 H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbE-0005vi-00"
1999-03-02 09:44:33 10HmbD-0005vi-00 client ocsp status: 4 (verified)
1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for failrequire@test.ex
1999-03-02 09:44:33 10HmbF-0005vi-00 Received TLS status callback, null content
1999-03-02 09:44:33 10HmbF-0005vi-00 client ocsp status: 1 (notresp)
1999-03-02 09:44:33 10HmbF-0005vi-00 == failrequire@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for failrevoked@test.ex
1999-03-02 09:44:33 10HmbG-0005vi-00 Server certificate revoked; reason: superseded
1999-03-02 09:44:33 10HmbG-0005vi-00 client ocsp status: 3 (failed)
1999-03-02 09:44:33 10HmbG-0005vi-00 == failrevoked@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for failexpired@test.ex
1999-03-02 09:44:33 10HmbH-0005vi-00 Server OSCP dates invalid
1999-03-02 09:44:33 10HmbH-0005vi-00 client ocsp status: 3 (failed)
1999-03-02 09:44:33 10HmbH-0005vi-00 == failexpired@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
@@ -30,20 +30,20 @@
******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
1999-03-02 09:44:33 10HmaY-0005vi-00 client claims: ocsp status 1
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com
-1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <norequire@test.ex> R=server
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com for norequire_1@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <norequire_1@test.ex> R=server
1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
1999-03-02 09:44:33 10HmbA-0005vi-00 client claims: ocsp status 4
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com
-1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <norequire@test.ex> R=server
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com for norequire_2@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <norequire_2@test.ex> R=server
1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
1999-03-02 09:44:33 10HmbC-0005vi-00 client claims: ocsp status 0
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com for nostaple@test.ex
1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <nostaple@test.ex> R=server
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
1999-03-02 09:44:33 10HmbE-0005vi-00 client claims: ocsp status 4
-1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@server1.example.com for good@test.ex
1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <good@test.ex> R=server
1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
diff --git a/test/log/5840 b/test/log/5840
index 6d65bf25e..9d134ca6d 100644
--- a/test/log/5840
+++ b/test/log/5840
@@ -26,6 +26,9 @@
1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@mxdanelazy.test.ex
1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.1.test.ex
1999-03-02 09:44:33 10HmbJ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.2.test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@danebroken1.test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.3.test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.4.test.ex
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
1999-03-02 09:44:33 10HmbH-0005vi-00 H=danelazy.test.ex [ip4.ip4.ip4.ip4]: DANE error: tlsa lookup DEFER
1999-03-02 09:44:33 10HmbH-0005vi-00 H=danelazy2.test.ex [127.0.0.1]: DANE error: tlsa lookup DEFER
@@ -35,8 +38,17 @@
1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
1999-03-02 09:44:33 10HmbJ-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
1999-03-02 09:44:33 10HmbJ-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="dane.no.2.test.ex"
-1999-03-02 09:44:33 10HmbJ-0005vi-00 => CALLER@dane.no.2.test.ex R=client T=send_to_server H=dane.no.2.test.ex [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbK-0005vi-00"
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => CALLER@dane.no.2.test.ex R=client T=send_to_server H=dane.no.2.test.ex [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbN-0005vi-00"
1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbK-0005vi-00 H=danebroken1.test.ex [127.0.0.1]: DANE error: tlsa lookup DEFER
+1999-03-02 09:44:33 10HmbK-0005vi-00 == CALLER@danebroken1.test.ex R=client T=send_to_server defer (-36): DANE error: tlsa lookup DEFER
+1999-03-02 09:44:33 10HmbL-0005vi-00 ** CALLER@dane.no.3.test.ex R=client T=send_to_server: DANE error: tlsa lookup FAIL
+1999-03-02 09:44:33 10HmbL-0005vi-00 CALLER@dane.no.3.test.ex: error ignored
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbM-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="dane.no.4.test.ex"
+1999-03-02 09:44:33 10HmbM-0005vi-00 => CALLER@dane.no.4.test.ex R=client T=send_to_server H=dane.no.4.test.ex [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbO-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qf
******** SERVER ********
@@ -60,6 +72,9 @@
1999-03-02 09:44:33 10HmbG-0005vi-00 => :blackhole: <CALLER@thishost.test.ex> R=server
1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 10HmbK-0005vi-00 <= <> H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbJ-0005vi-00@myhost.test.ex for CALLER@dane.no.2.test.ex
-1999-03-02 09:44:33 10HmbK-0005vi-00 => :blackhole: <CALLER@dane.no.2.test.ex> R=server
-1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbN-0005vi-00 <= <> H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbJ-0005vi-00@myhost.test.ex for CALLER@dane.no.2.test.ex
+1999-03-02 09:44:33 10HmbN-0005vi-00 => :blackhole: <CALLER@dane.no.2.test.ex> R=server
+1999-03-02 09:44:33 10HmbN-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbO-0005vi-00 <= <> H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbM-0005vi-00@myhost.test.ex for CALLER@dane.no.4.test.ex
+1999-03-02 09:44:33 10HmbO-0005vi-00 => :blackhole: <CALLER@dane.no.4.test.ex> R=server
+1999-03-02 09:44:33 10HmbO-0005vi-00 Completed
diff --git a/test/mail/0906.a b/test/mail/0906.a
new file mode 100644
index 000000000..a55f68d7f
--- /dev/null
+++ b/test/mail/0906.a
@@ -0,0 +1,109 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from localhost ([127.0.0.1] helo=testhost.test.ex)
+ by testhost.test.ex with esmtp (Exim x.yz)
+ id 10HmaX-0005vi-00
+ for a@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from [127.0.0.1] (helo=test.com)
+ by testhost.test.ex with esmtp (Exim x.yz)
+ (envelope-from <sender@dom>)
+ id 10HmaY-0005vi-00
+ for a@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: foo
+X-body-linecount: 0
+X-message-linecount: 10
+X-received-count: 2
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+.dot
+tail
+
diff --git a/test/mail/2013.usera b/test/mail/2013.usera
new file mode 100644
index 000000000..8e17aeefc
--- /dev/null
+++ b/test/mail/2013.usera
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbG-0005vi-00
+ for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbD-0005vi-00
+ for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2013.userb b/test/mail/2013.userb
new file mode 100644
index 000000000..556fb35e8
--- /dev/null
+++ b/test/mail/2013.userb
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbI-0005vi-00
+ for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbE-0005vi-00
+ for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbE-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2013.userc b/test/mail/2013.userc
new file mode 100644
index 000000000..818aafb5e
--- /dev/null
+++ b/test/mail/2013.userc
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbH-0005vi-00
+ for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbF-0005vi-00
+ for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbF-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2038.userx0 b/test/mail/2038.userx0
new file mode 100644
index 000000000..4acc59105
--- /dev/null
+++ b/test/mail/2038.userx0
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbA-0005vi-00
+ for userx0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2038.userx1 b/test/mail/2038.userx1
new file mode 100644
index 000000000..2d4691e52
--- /dev/null
+++ b/test/mail/2038.userx1
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbB-0005vi-00
+ for userx1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2038.usery0 b/test/mail/2038.usery0
new file mode 100644
index 000000000..0959b777b
--- /dev/null
+++ b/test/mail/2038.usery0
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbE-0005vi-00
+ for usery0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2038.usery1 b/test/mail/2038.usery1
new file mode 100644
index 000000000..0aaf2a5ff
--- /dev/null
+++ b/test/mail/2038.usery1
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbF-0005vi-00
+ for usery1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2038.userz0 b/test/mail/2038.userz0
new file mode 100644
index 000000000..dac74adae
--- /dev/null
+++ b/test/mail/2038.userz0
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbC-0005vi-00
+ for userz0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2038.userz1 b/test/mail/2038.userz1
new file mode 100644
index 000000000..4797ffdf8
--- /dev/null
+++ b/test/mail/2038.userz1
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbD-0005vi-00
+ for userz1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2113.usera b/test/mail/2113.usera
new file mode 100644
index 000000000..43e950776
--- /dev/null
+++ b/test/mail/2113.usera
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbG-0005vi-00
+ for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbD-0005vi-00
+ for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2113.userb b/test/mail/2113.userb
new file mode 100644
index 000000000..d93f45f7c
--- /dev/null
+++ b/test/mail/2113.userb
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbI-0005vi-00
+ for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbE-0005vi-00
+ for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbE-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2113.userc b/test/mail/2113.userc
new file mode 100644
index 000000000..5bc9043fb
--- /dev/null
+++ b/test/mail/2113.userc
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbH-0005vi-00
+ for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbF-0005vi-00
+ for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbF-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2138.userx0 b/test/mail/2138.userx0
new file mode 100644
index 000000000..952a4546f
--- /dev/null
+++ b/test/mail/2138.userx0
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbA-0005vi-00
+ for userx0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2138.userx1 b/test/mail/2138.userx1
new file mode 100644
index 000000000..a6f4b9762
--- /dev/null
+++ b/test/mail/2138.userx1
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbB-0005vi-00
+ for userx1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2138.usery0 b/test/mail/2138.usery0
new file mode 100644
index 000000000..d0c8c270f
--- /dev/null
+++ b/test/mail/2138.usery0
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbE-0005vi-00
+ for usery0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2138.usery1 b/test/mail/2138.usery1
new file mode 100644
index 000000000..b7d4c665e
--- /dev/null
+++ b/test/mail/2138.usery1
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbF-0005vi-00
+ for usery1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2138.userz0 b/test/mail/2138.userz0
new file mode 100644
index 000000000..4a0f92398
--- /dev/null
+++ b/test/mail/2138.userz0
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbC-0005vi-00
+ for userz0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2138.userz1 b/test/mail/2138.userz1
new file mode 100644
index 000000000..5aca0f53a
--- /dev/null
+++ b/test/mail/2138.userz1
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbD-0005vi-00
+ for userz1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/4530.y b/test/mail/4530.y
new file mode 100644
index 000000000..445e41a95
--- /dev/null
+++ b/test/mail/4530.y
@@ -0,0 +1,26 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from localhost ([127.0.0.1] helo=testhost.test.ex)
+ by testhost.test.ex with esmtp (Exim x.yz)
+ id 10HmaY-0005vi-00
+ for y@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
+ s=sel; h=LIST; bh=CVpkzY75tV/NCKk5pPx4GnM3NX83xwCiT0xVwo0G1Rs=; b=TIqPqpKM5qf
+ ZFlv2H8yio5RybWA3sLCtVmE6HmBhBKqW+uqLKG2grqJhVMJ3qXnvQQ3ixnMjMlJqfCpEBtxfsSR9
+ MGLPP9ZMdlrBNEL6XKlgE+X8bAra5zkuLZs8gy8H3/mtEfoKPs4ltB/ZK/j2FHG2+CEx+TDTIkh9E
+ wkAMrA=;
+Received: from [127.0.0.1] (helo=xxx)
+ by testhost.test.ex with esmtp (Exim x.yz)
+ (envelope-from <CALLER@bloggs.com>)
+ id 10HmbA-0005vi-00
+ for y@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: simple test
+X-body-linecount: 0
+X-message-linecount: 15
+X-received-count: 2
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+.Line 3 has a leading dot
+last line: 4
+
diff --git a/test/mail/4530.z b/test/mail/4530.z
new file mode 100644
index 000000000..1b4735507
--- /dev/null
+++ b/test/mail/4530.z
@@ -0,0 +1,26 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from localhost ([127.0.0.1] helo=testhost.test.ex)
+ by testhost.test.ex with esmtp (Exim x.yz)
+ id 10HmaX-0005vi-00
+ for z@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
+ s=sel; h=LIST; bh=CVpkzY75tV/NCKk5pPx4GnM3NX83xwCiT0xVwo0G1Rs=; b=TIqPqpKM5qf
+ ZFlv2H8yio5RybWA3sLCtVmE6HmBhBKqW+uqLKG2grqJhVMJ3qXnvQQ3ixnMjMlJqfCpEBtxfsSR9
+ MGLPP9ZMdlrBNEL6XKlgE+X8bAra5zkuLZs8gy8H3/mtEfoKPs4ltB/ZK/j2FHG2+CEx+TDTIkh9E
+ wkAMrA=;
+Received: from [127.0.0.1] (helo=xxx)
+ by testhost.test.ex with esmtp (Exim x.yz)
+ (envelope-from <CALLER@bloggs.com>)
+ id 10HmaZ-0005vi-00
+ for z@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: simple test
+X-body-linecount: 0
+X-message-linecount: 15
+X-received-count: 2
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+.Line 3 has a leading dot
+last line: 4
+
diff --git a/test/mail/5010.maildirsize b/test/mail/5010.maildirsize
new file mode 100644
index 000000000..f6a87c4bb
--- /dev/null
+++ b/test/mail/5010.maildirsize
@@ -0,0 +1,2 @@
+30S,1C
+ddd d
diff --git a/test/mail/5010.new/1.myhost.test.ex b/test/mail/5010.new/1.myhost.test.ex
new file mode 100644
index 000000000..4b8954864
--- /dev/null
+++ b/test/mail/5010.new/1.myhost.test.ex
@@ -0,0 +1,17 @@
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaX-0005vi-00
+ for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
diff --git a/test/mail/5011.maildirsize b/test/mail/5011.maildirsize
new file mode 100644
index 000000000..f6a87c4bb
--- /dev/null
+++ b/test/mail/5011.maildirsize
@@ -0,0 +1,2 @@
+30S,1C
+ddd d
diff --git a/test/mail/5012.maildirsize b/test/mail/5012.maildirsize
new file mode 100644
index 000000000..69ef86707
--- /dev/null
+++ b/test/mail/5012.maildirsize
@@ -0,0 +1,3 @@
+30S,1C
+ddd d
+ddd d
diff --git a/test/mail/5012.new/1.myhost.test.ex b/test/mail/5012.new/1.myhost.test.ex
new file mode 100644
index 000000000..4b8954864
--- /dev/null
+++ b/test/mail/5012.new/1.myhost.test.ex
@@ -0,0 +1,17 @@
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaX-0005vi-00
+ for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
diff --git a/test/mail/5012.new/2.myhost.test.ex b/test/mail/5012.new/2.myhost.test.ex
new file mode 100644
index 000000000..ffc6a3bf8
--- /dev/null
+++ b/test/mail/5012.new/2.myhost.test.ex
@@ -0,0 +1,28 @@
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaY-0005vi-00
+ for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
diff --git a/test/paniclog/0021 b/test/paniclog/0021
index dae415203..d6e91d346 100644
--- a/test/paniclog/0021
+++ b/test/paniclog/0021
@@ -1,6 +1,6 @@
-1999-03-02 09:44:33 rcpt accepted
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=MAIL,MAIL,RCPT
+1999-03-02 09:44:33 rcpt accepted C=MAIL,MAIL,RCPT,RCPT
1999-03-02 09:44:33 ACL "warn" with "message" setting found in a non-message (EHLO or HELO) ACL: cannot specify header lines here: message ignored
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=MAIL,RCPT
1999-03-02 09:44:33 ACL "warn" with "message" setting found in a non-message (EHLO or HELO) ACL: cannot specify header lines here: message ignored
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=EHLO,MAIL,RCPT
diff --git a/test/rejectlog/0227 b/test/rejectlog/0227
index 8f5c0ad15..e44ddafbc 100644
--- a/test/rejectlog/0227
+++ b/test/rejectlog/0227
@@ -30,6 +30,9 @@ F From: abcd@x.y.z
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify fail for <ok@localhost1>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<postmaster@localhost1>: 550 Don't like postmaster
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: Sender verify failed
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.7] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<uncheckable@localhost1> rejected RCPT <z@remote.lmtp>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<z@remote.lmtp>: 550 Recipient not liked
1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root sender verify defer for <bad@localhost1>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : Remote host closed connection in response to initial connection
1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root F=<bad@localhost1> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
diff --git a/test/rejectlog/0376 b/test/rejectlog/0376
index 47ad1638d..1702cec04 100644
--- a/test/rejectlog/0376
+++ b/test/rejectlog/0376
@@ -12,9 +12,5 @@
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
diff --git a/test/rejectlog/0578 b/test/rejectlog/0578
index db94a4d6e..bf20a240d 100644
--- a/test/rejectlog/0578
+++ b/test/rejectlog/0578
@@ -12,9 +12,5 @@
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK accepting that random recipient
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
diff --git a/test/rejectlog/0582 b/test/rejectlog/0582
new file mode 100644
index 000000000..614c29400
--- /dev/null
+++ b/test/rejectlog/0582
@@ -0,0 +1 @@
+1999-03-02 09:44:33 U=CALLER F=<userg@ok.example> temporarily rejected RCPT <userg@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<userg@test.ex>: 451 not right now
diff --git a/test/rejectlog/0901 b/test/rejectlog/0901
index a7f8f0692..f75d9d270 100644
--- a/test/rejectlog/0901
+++ b/test/rejectlog/0901
@@ -1,6 +1,6 @@
******** SERVER ********
-1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "bdat 1" H=(tester) [127.0.0.1] next input="bdat 87 last\r\n"
+1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "BDAT 1" H=(tester) [127.0.0.1] next input="BDAT 87 last\r\n"
Envelope-from: <someone9@some.domain>
Envelope-to: <CALLER@test.ex>
1999-03-02 09:44:33 SMTP call from (tester) [127.0.0.1] dropped: too many syntax or protocol errors (last command was "From: Sam@random.com")
diff --git a/test/rejectlog/2037 b/test/rejectlog/2037
new file mode 100644
index 000000000..210641393
--- /dev/null
+++ b/test/rejectlog/2037
@@ -0,0 +1,20 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected after DATA
+Envelope-from: <>
+Envelope-to: <data_defer@test.ex>
+P Received: from localhost ([127.0.0.1] helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+ (Exim x.yz)
+ id 10HmaX-0005vi-00
+ for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+P Received: from CALLER by myhost.test.ex with local-smtp (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00
+ for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+ Subject: test
+I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
+ Date: Tue, 2 Mar 1999 09:44:33 +0000
diff --git a/test/rejectlog/2137 b/test/rejectlog/2137
new file mode 100644
index 000000000..6ec734584
--- /dev/null
+++ b/test/rejectlog/2137
@@ -0,0 +1,20 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected after DATA
+Envelope-from: <>
+Envelope-to: <data_defer@test.ex>
+P Received: from localhost ([127.0.0.1] helo=myhost.test.ex)
+ by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+ (Exim x.yz)
+ id 10HmaX-0005vi-00
+ for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+P Received: from CALLER by myhost.test.ex with local-smtp (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaY-0005vi-00
+ for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+ Subject: test
+I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
+ Date: Tue, 2 Mar 1999 09:44:33 +0000
diff --git a/test/runtest b/test/runtest
index ec385f294..3bd6c77bd 100755
--- a/test/runtest
+++ b/test/runtest
@@ -487,9 +487,13 @@ RESET_AFTER_EXTRA_LINE_READ:
/Tue, 2 Mar 1999 09:44:33 +0000/gx;
# Date/time in logs and in one instance of a filter test
- s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(\s[+-]\d\d\d\d)?/1999-03-02 09:44:33/gx;
+ s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(\s[+-]\d\d\d\d)?\s/1999-03-02 09:44:33 /gx;
+ s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d\.\d{3}(\s[+-]\d\d\d\d)?\s/2017-07-30 18:51:05.712 /gx;
s/^Logwrite\s"\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d/Logwrite "1999-03-02 09:44:33/gx;
+ s/((D|[QD]T)=)\d+s/$1qqs/g;
+ s/((D|[QD]T)=)\d\.\d{3}s/$1q.qqqs/g;
+
# Date/time in message separators
s/(?:[A-Z][a-z]{2}\s){2}\d\d\s\d\d:\d\d:\d\d\s\d\d\d\d
/Tue Mar 02 09:44:33 1999/gx;
@@ -517,9 +521,6 @@ RESET_AFTER_EXTRA_LINE_READ:
# Date/time in exim -bV output
s/\d\d-[A-Z][a-z]{2}-\d{4}\s\d\d:\d\d:\d\d/07-Mar-2000 12:21:52/g;
- # Time on queue tolerance
- s/(QT|D)=1s/$1=0s/;
-
# Eximstats heading
s/Exim\sstatistics\sfrom\s\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d\sto\s
\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d/Exim statistics from <time> to <time>/x;
@@ -910,6 +911,9 @@ RESET_AFTER_EXTRA_LINE_READ:
# optional IDN2 variant conversions. Accept either IDN1 or IDN2
s/conversion strasse.de/conversion xn--strae-oqa.de/;
s/conversion: german.xn--strae-oqa.de/conversion: german.straße.de/;
+
+ # subsecond timstamp info in reported header-files
+ s/^(-received_time_usec \.)\d{6}$/$1uuuuuu/;
}
# ======== stderr ========
@@ -1088,6 +1092,9 @@ RESET_AFTER_EXTRA_LINE_READ:
# Not all platforms build with DKIM enabled
next if /^PDKIM >> Body data for hash, canonicalized/;
+ # Not all platforms have sendfile support
+ next if /^cannot use sendfile for body: no support$/;
+
# Parts of DKIM-specific debug output depend on the time/date
next if /^date:\w+,\{SP\}/;
next if /^PDKIM \[[^[]+\] (Header hash|b) computed:/;
@@ -1103,6 +1110,10 @@ RESET_AFTER_EXTRA_LINE_READ:
next if /^(ppppp )?setsockopt FASTOPEN: Protocol not available$/;
+ # Specific pointer values reported for DB operations change from run to run
+ s/^(returned from EXIM_DBOPEN: 0x)[0-9a-f]+/$1AAAAAAAA/;
+ s/^(EXIM_DBCLOSE.0x)[0-9a-f]+/$1AAAAAAAA/;
+
# When Exim is checking the size of directories for maildir, it uses
# the check_dir_size() function to scan directories. Of course, the order
# of the files that are obtained using readdir() varies from system to
@@ -1154,6 +1165,9 @@ RESET_AFTER_EXTRA_LINE_READ:
{
# Berkeley DB version differences
next if / Berkeley DB error: /;
+
+ # CHUNKING: exact sizes depend on hostnames in headers
+ s/(=>.* K C="250- \d)\d+ (byte chunk, total \d)\d+/$1nn $2nn/;
}
# ======== All files other than stderr ========
@@ -1513,7 +1527,7 @@ $munges =
'optional_config' =>
{ 'stdout' => '/^(
- dkim_(canon|domain|private_key|selector|sign_headers|strict)
+ dkim_(canon|domain|private_key|selector|sign_headers|strict|hash|identity)
|gnutls_require_(kx|mac|protocols)
|hosts_(requ(est|ire)|try)_(dane|ocsp)
|hosts_(avoid|nopass|require|verify_avoid)_tls
@@ -2531,7 +2545,7 @@ GetOptions(
'keep' => \$save_output,
'slow' => \$slow,
'valgrind' => \$valgrind,
- 'range=i{2}' => \my @range_wanted,
+ 'range=s{2}' => \my @range_wanted,
'test=i@' => \my @tests_wanted,
'flavor|flavour=s' => $flavour,
'help' => sub { pod2usage(-exit => 0) },
@@ -2711,7 +2725,7 @@ if (defined $parm_trusted_config_list)
open(TCL, $parm_trusted_config_list) or die "Can't open $parm_trusted_config_list: $!\n";
my $test_config = getcwd() . '/test-config';
die "Can't find '$test_config' in TRUSTED_CONFIG_LIST $parm_trusted_config_list."
- if not grep { /^$test_config$/ } <TCL>;
+ if not grep { /^\Q$test_config\E$/ } <TCL>;
}
else
{
@@ -4067,7 +4081,8 @@ Keep the various output files produced during a test run. (default: don't keep)
=item B<--range> I<n0> I<n1>
-Run tests between (including) I<n0> and I<n1>.
+Run tests between (including) I<n0> and I<n1>. A "+" may be used to specify the "last
+test available".
=item B<--slow>
diff --git a/test/scripts/0000-Basic/0002 b/test/scripts/0000-Basic/0002
index cf8dc36e0..cb0bb188f 100644
--- a/test/scripts/0000-Basic/0002
+++ b/test/scripts/0000-Basic/0002
@@ -417,6 +417,8 @@ gei: ${if gei{ABC}{abc}{y}{n}}
isip: ${if isip {1.2.3.4}{y}{n}} 1.2.3.4
isip4: ${if isip4{1.2.3.4}{y}{n}} 1.2.3.4
isip6: ${if isip6{1.2.3.4}{y}{n}} 1.2.3.4
+isip: ${if isip {::1.2.3.256}{y}{n}} ::1.2.3.256
+isip4: ${if isip4{1.2.3.256}{y}{n}} 1.2.3.256
isip: ${if isip {1:2:3:4}{y}{n}} 1:2:3:4
isip4: ${if isip4{1:2:3:4}{y}{n}} 1:2:3:4
isip6: ${if isip6{1:2:3:4}{y}{n}} 1:2:3:4
@@ -426,6 +428,7 @@ isip6: ${if isip6{::1}{y}{n}} ::1
isip: ${if isip {fe80::a00:20ff:fe86:a061}{y}{n}} fe80::a00:20ff:fe86:a061
isip4: ${if isip4{fe80::a00:20ff:fe86:a061}{y}{n}} fe80::a00:20ff:fe86:a061
isip6: ${if isip6{fe80::a00:20ff:fe86:a061}{y}{n}} fe80::a00:20ff:fe86:a061
+isip: ${if isip {fe80::1.2.3.4}{y}{n}} fe80::1.2.3.4
isip: ${if isip {rhubarb}{y}{n}} rhubarb
isip4: ${if isip4{rhubarb}{y}{n}} rhubarb
isip6: ${if isip6{rhubarb}{y}{n}} rhubarb
diff --git a/test/scripts/0000-Basic/0211 b/test/scripts/0000-Basic/0211
index 655b4dd96..c27a7ebf3 100644
--- a/test/scripts/0000-Basic/0211
+++ b/test/scripts/0000-Basic/0211
@@ -13,6 +13,7 @@ exim -odi userx@domain1
Test message 1
****
#
+sudo rm DIR/spool/db/*
exim -z "Test: temp-rej helo"
****
server PORT_S
@@ -27,6 +28,7 @@ QUIT
exim -qf
****
#
+sudo rm DIR/spool/db/*
exim -z "Test: drop conn after banner"
****
server PORT_S
@@ -35,6 +37,7 @@ server PORT_S
exim -qf
****
#
+sudo rm DIR/spool/db/*
exim -z "Test: reject connect"
****
server PORT_S
@@ -45,6 +48,7 @@ QUIT
exim -qf
****
#
+sudo rm DIR/spool/db/*
exim -z "Test: reject helo"
****
server PORT_S
@@ -74,4 +78,19 @@ Test message 4
****
#
#
+#
+sudo rm DIR/spool/db/*
+exim -z "Test: smtp-reject conn on 1MX, timeout TCP conn on 2MX"
+****
+server PORT_S 2
+554 no smtp service here
+QUIT
+220 bye
+*eof
+*sleep 2
+****
+exim -DLIST -qf
+****
+#
+#
no_msglog_check
diff --git a/test/scripts/0000-Basic/0227 b/test/scripts/0000-Basic/0227
index a67dab2eb..e53c1da7f 100644
--- a/test/scripts/0000-Basic/0227
+++ b/test/scripts/0000-Basic/0227
@@ -12,11 +12,13 @@ RCPT TO
QUIT
250 OK
****
+# sender
sudo exim -v -bs -oMa V4NET.0.0.1
MAIL FROM:<ok@localhost>
RCPT TO:<z@test.ex>
QUIT
****
+# sender, no callout
sudo exim -v -bs -oMa V4NET.0.0.2
MAIL FROM:<unchecked@localhost>
RCPT TO:<z@test.ex>
@@ -33,6 +35,7 @@ RCPT TO
QUIT
250 OK
****
+# sender, refused
sudo exim -v -bs -oMa V4NET.0.0.1
MAIL FROM:<bad@localhost>
RCPT TO:<z@test.ex>
@@ -49,6 +52,7 @@ RCPT TO
QUIT
250 OK
****
+# sender, tmperr
sudo exim -v -bs -oMa V4NET.0.0.1
MAIL FROM:<uncheckable@localhost1>
RCPT TO:<z@test.ex>
@@ -63,6 +67,7 @@ MAIL FROM
QUIT
250 OK
****
+# sender, err on mailfrom
sudo exim -v -bs -oMa V4NET.0.0.1
MAIL FROM:<uncheckable2@localhost1>
RCPT TO:<z@test.ex>
@@ -78,6 +83,7 @@ MAIL FROM
QUIT
250 OK
****
+# sender, err on mailfrom
sudo exim -v -bs -oMa V4NET.0.0.1
MAIL FROM:<uncheckable@localhost1>
RCPT TO:<z@test.ex>
@@ -94,6 +100,7 @@ RCPT TO
QUIT
250 OK
****
+# recipient, refused
sudo exim -v -bs -oMa V4NET.0.0.3
MAIL FROM:<uncheckable@localhost1>
RCPT TO:<z@remote.domain>
@@ -111,11 +118,13 @@ RCPT TO
QUIT
250 OK
****
+# recipient, refused
sudo exim -v -bs -oMa V4NET.0.0.3
MAIL FROM:<uncheckable@localhost1>
RCPT TO:<z@remote.domain>
QUIT
****
+# recipient, no conneect
sudo exim -v -bs -oMa V4NET.0.0.3
MAIL FROM:<uncheckable@localhost1>
RCPT TO:<z@remote.domain>
@@ -207,16 +216,17 @@ QUIT
server PORT_S
220 Server ready
EHLO
-250- wotcher
+250- wotcher sverifier
250-SIZE
250 OK
-MAIL FROM
+MAIL FROM:<>
250 OK
RCPT TO
250 OK
QUIT
250 OK
****
+# sender, size known, tgt supports sixe
sudo exim -v -bs -oMa V4NET.0.0.6
EHLO me
MAIL FROM:<ok@localhost1> SIZE=420000
@@ -226,6 +236,76 @@ QUIT
#
server PORT_S
220 Server ready
+EHLO
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<> SIZE=
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+# receipient, size known, tgt supports size
+sudo exim -v -bs -oMa V4NET.0.0.3
+EHLO me
+MAIL FROM:<ok@localhost1> SIZE=420000
+RCPT TO:<z@remote.domain>
+QUIT
+****
+#
+server PORT_S
+220 Server ready
+EHLO
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<>
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+# receipient, size unknown, tgt supports size
+sudo exim -v -bs -oMa V4NET.0.0.3
+EHLO me
+MAIL FROM:<ok@localhost1>
+RCPT TO:<z@remote.domain>
+QUIT
+****
+#
+server PORT_S
+220 Server ready
+EHLO
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<ok@localhost1>
+250 OK
+RCPT TO:<myhost.test.ex-
+550 RANDOM NOT OK
+RSET
+250 OK
+MAIL FROM:<ok@localhost1> SIZE=
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+****
+# receipient, size known, tgt supports size, use_sender, w/random
+# stdout should see SIZE on the main but not on the random receipient's MAIL FROM
+sudo exim -v -bs -oMa V4NET.0.0.7
+EHLO me
+MAIL FROM:<ok@localhost1> SIZE=420000
+RCPT TO:<z@remote.domain>
+QUIT
+****
+#
+server PORT_S
+220 Server ready
LHLO
250 OK
MAIL FROM
diff --git a/test/scripts/0000-Basic/0547 b/test/scripts/0000-Basic/0547
index 2595eff48..a645802a1 100644
--- a/test/scripts/0000-Basic/0547
+++ b/test/scripts/0000-Basic/0547
@@ -1,11 +1,14 @@
# log_selector = +smtp_no_mail
need_ipv4
#
-exim -DSERVER=server -bd -oX PORT_D
+exim -DSERVER=server -DLOG_SELECTOR=+millisec -bd -oX PORT_D
****
client 127.0.0.1 PORT_D
??? 220
****
+killdaemon
+exim -DSERVER=server -bd -oX PORT_D
+****
client 127.0.0.1 PORT_D
??? 220
quit
diff --git a/test/scripts/0000-Basic/0551 b/test/scripts/0000-Basic/0551
index d11064c00..1565275ea 100644
--- a/test/scripts/0000-Basic/0551
+++ b/test/scripts/0000-Basic/0551
@@ -1,14 +1,15 @@
-# log_selector = +pid
+# log_selector = +pid , +millisec
#
exim -odi userx@test.ex usery@test.ex
Message 1
****
-exim -odi userx@test.ex userz@test.ex
+exim -DLOG_SELECTOR=+pid+queue_time -odi userx@test.ex userz@test.ex
Message 2
****
-exim -DLOG_SELECTOR= -odi userx@test.ex
+exim -d+all -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -odi userx@test.ex
Message 3
****
exigrep userx
eximstats -ne -nr -nt -tnl -q0 -h0 -t0
no_msglog_check
+no_stderr_check
diff --git a/test/scripts/0000-Basic/0580 b/test/scripts/0000-Basic/0580
new file mode 100644
index 000000000..8d8a11751
--- /dev/null
+++ b/test/scripts/0000-Basic/0580
@@ -0,0 +1,156 @@
+# callout lazy-close, -bs send
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# cmdline -bs send
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+# multiple recipients
+# 1st callout result is cached (above); should not activate LCC
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery@test.ex>
+rcpt to:<usery2@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+# 2nd callout result is cached (above); should not activate LCC
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery3@test.ex>
+rcpt to:<usery@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+# no cache hits; should do LCC
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery4@test.ex>
+rcpt to:<usery5@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0581 b/test/scripts/0000-Basic/0581
new file mode 100644
index 000000000..f0ce3bcd7
--- /dev/null
+++ b/test/scripts/0000-Basic/0581
@@ -0,0 +1,264 @@
+# callout lazy-close, smtp send
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# smtp send
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+killdaemon
+#
+#
+# smtp send, deliver_drop_priv
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -DSERVER=server -DOPT=deliver_drop_privilege -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<usere@ok.example>
+??? 250
+RCPT TO:<userf@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+killdaemon
+#
+#
+# multiple recipients
+# 1st callout result is cached (above); should not activate LCC
+# smtp send
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd2@test.ex>
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd@test.ex>
+250 OK
+RCPT TO:<userd2@test.ex>
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+RCPT TO:<userd2@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+#
+# 2nd callout result is cached (above); should not activate LCC
+# smtp send
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd3@test.ex>
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd3@test.ex>
+250 OK
+RCPT TO:<userd2@test.ex>
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd3@test.ex>
+??? 250
+RCPT TO:<userd2@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+#
+# no cache hits; should do LCC
+# smtp send
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd4@test.ex>
+250 OK
+RCPT TO:<userd5@test.ex>
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd4@test.ex>
+??? 250
+RCPT TO:<userd5@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+killdaemon
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0582 b/test/scripts/0000-Basic/0582
new file mode 100644
index 000000000..3eefcc979
--- /dev/null
+++ b/test/scripts/0000-Basic/0582
@@ -0,0 +1,56 @@
+# callout lazy-close, defers
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# cmdline -bs send, rcpt-time defer
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+451 not right now
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userg@ok.example>
+rcpt to:<userg@test.ex>
+quit
+****
+sleep 1
+#
+# cmdline -bs send, data-time defer
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+451 not right now
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userh@ok.example>
+rcpt to:<userh@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0901 b/test/scripts/0000-Basic/0901
index 9908d5ecd..5e88c5ae9 100644
--- a/test/scripts/0000-Basic/0901
+++ b/test/scripts/0000-Basic/0901
@@ -243,12 +243,12 @@ ehlo tester
??? 250-8BITMIME
??? 250-CHUNKING
??? 250 HELP
-mail from:someone9@some.domain
+MAIL FROM:someone9@some.domain
??? 250
-rcpt to:CALLER@test.ex
+RCPT TO:CALLER@test.ex
??? 250
-bdat 1\r\nTbdat 87 last
-To: Susan@random.com
+BDAT 1\r\nTBDAT 87 last
+o: Susan@random.com
From: Sam@random.com
Subject: This is a bodyless test message
diff --git a/test/scripts/0000-Basic/0906 b/test/scripts/0000-Basic/0906
new file mode 100644
index 000000000..18ab5bb54
--- /dev/null
+++ b/test/scripts/0000-Basic/0906
@@ -0,0 +1,124 @@
+# CHUNKING, spool_wireformat
+#
+exim -bd -DSERVER=server -oX PORT_D:PORT_S
+****
+#
+# Basic long message
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.com
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<sender@dom>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+BDAT 8408 LAST
+Subject: foo
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+.dot
+tail
+??? 250-
+??? 250
+QUIT
+****
+#
+sleep 1
+killdaemon
+exim -q
+****
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0907 b/test/scripts/0000-Basic/0907
new file mode 100644
index 000000000..341a63f48
--- /dev/null
+++ b/test/scripts/0000-Basic/0907
@@ -0,0 +1,4 @@
+# check for BOM in an included config file (0908)
+#
+1
+exim -bP config
diff --git a/test/scripts/0000-Basic/0908 b/test/scripts/0000-Basic/0908
new file mode 120000
index 000000000..8cc1a8c6e
--- /dev/null
+++ b/test/scripts/0000-Basic/0908
@@ -0,0 +1 @@
+0907 \ No newline at end of file
diff --git a/test/scripts/1990-TCP-Fast-Open/1990 b/test/scripts/1990-TCP-Fast-Open/1990
new file mode 100644
index 000000000..cbedd3622
--- /dev/null
+++ b/test/scripts/1990-TCP-Fast-Open/1990
@@ -0,0 +1,45 @@
+# TCP Fast Open
+#
+# Linux:
+# Both server and client-side TFO support must be enabled in the
+# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
+#
+# A packet capture on the loopback interface will show the TFO
+# option on the SYN, but the fast-output SMTP banner will not
+# be seen unless you also deliberately emulate a long path:
+# 'sudo tc qdisc add dev lo root netem delay 100ms'
+#
+# First time runs will see a TFO request option only; subsequent
+# ones should see the TFO cookie and fast-output SMTP banner
+# (currently on a separate packet after the server SYN,ACK but before
+# the client ACK).
+#
+# The client log => lint.ex should have a "TFO" element.
+# Assuming this is the first run since boot, the a@test recipient will not.
+#
+# The server log <= line for b@test.ex should have a "TFO" element, but
+# this will only be obtained when the above delay is inserted into the
+# loopback net path.
+#
+#
+#
+# FreeBSD: it looks like you have to compile a custom kernel, with
+# 'options TCP_RFC7413' in the config. Also set
+# 'net.inet.tcp.fastopen.enabled=1' in /etc/sysctl.conf
+# Untested.
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+exim a@test.ex
+Testing
+****
+sleep 3
+#
+exim b@test.ex
+Testing
+****
+sleep 3
+#
+killdaemon
+no_msglog_check
diff --git a/test/scripts/1990-TCP-Fast-Open/REQUIRES b/test/scripts/1990-TCP-Fast-Open/REQUIRES
new file mode 100644
index 000000000..48cd58b67
--- /dev/null
+++ b/test/scripts/1990-TCP-Fast-Open/REQUIRES
@@ -0,0 +1 @@
+support TCP_Fast_Open
diff --git a/test/scripts/2000-GnuTLS/2013 b/test/scripts/2000-GnuTLS/2013
index 0c2ccba35..cf29efecd 100644
--- a/test/scripts/2000-GnuTLS/2013
+++ b/test/scripts/2000-GnuTLS/2013
@@ -11,7 +11,24 @@ Test message 2
exim userz@test.ex
Test message 3
****
-exim -qqf -d-all+acl
+exim -d-all+acl -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim usera@test.ex
+Test message 1
+****
+exim userb@test.ex
+Test message 2
+****
+exim userc@test.ex
+Test message 3
+****
+exim -DEQUIRE -d-all+acl -qqf
****
killdaemon
exim -DSERVER=server -DNOTDAEMON -qf
diff --git a/test/scripts/2000-GnuTLS/2031 b/test/scripts/2000-GnuTLS/2031
index 65b529093..76186b5e4 100644
--- a/test/scripts/2000-GnuTLS/2031
+++ b/test/scripts/2000-GnuTLS/2031
@@ -6,14 +6,14 @@ exim -DSERVER=server -bd -oX PORT_D
exim CALLER@test.ex
Test message.
****
-millisleep 500
+millisleep 700
#
#
# Extended: server uses SNI to choose certificate
exim abcd@test.ex
Test message.
****
-millisleep 500
+millisleep 700
#
#
killdaemon
diff --git a/test/scripts/2000-GnuTLS/2035 b/test/scripts/2000-GnuTLS/2035
new file mode 100644
index 000000000..94923aa60
--- /dev/null
+++ b/test/scripts/2000-GnuTLS/2035
@@ -0,0 +1,29 @@
+# client: callout lazy-close, -bs send
+gnutls
+need_ipv4
+#
+# a tls-capable target for the verify/delivery connection
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# A recipient verify and continued-delivery. The debug output should show "already connected to",
+# "proxied TLS", and the DATA smtp command only done by the transport process.
+# cmdline -bs send
+exim -d-all+transport -bs
+mail from:<usera@ok.example>
+rcpt to:<userb@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+killdaemon
+exim -q
+****
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2036 b/test/scripts/2000-GnuTLS/2036
new file mode 100644
index 000000000..cd6e9a121
--- /dev/null
+++ b/test/scripts/2000-GnuTLS/2036
@@ -0,0 +1,76 @@
+# client: callout lazy-close, smtp send
+gnutls
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# smtp send
+# a tls-capable target for the verify/delivery connection on PORT_D
+# plus a daemon under test on PORT_S
+exim -bd -DSERVER=server -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+# smtp send, deliver_drop_priv
+exim -bd -DSERVER=server -DOPT=deliver_drop_privilege -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<usere@ok.example>
+??? 250
+RCPT TO:<userf@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2037 b/test/scripts/2000-GnuTLS/2037
new file mode 100644
index 000000000..ad13a3f94
--- /dev/null
+++ b/test/scripts/2000-GnuTLS/2037
@@ -0,0 +1,31 @@
+# client: callout lazy-close, defers
+gnutls
+need_ipv4
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+# cmdline -bs send, rcpt-time defer
+exim -bs
+mail from:<>
+rcpt to:<rcpt_defer@test.ex>
+quit
+****
+sleep 3
+#
+# cmdline -bs send, data-time defer
+exim -bs
+mail from:<>
+rcpt to:<data_defer@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 3
+killdaemon
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2038 b/test/scripts/2000-GnuTLS/2038
new file mode 100644
index 000000000..83259d998
--- /dev/null
+++ b/test/scripts/2000-GnuTLS/2038
@@ -0,0 +1,19 @@
+# TLS client: multiple messages over one connection (continue_more)
+gnutls
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim userx0@test.ex userx1@test.ex
+Test message 1
+****
+exim usery0@test.ex usery1@test.ex
+Test message 2
+****
+exim userz0@test.ex userz1@test.ex
+Test message 3
+****
+exim -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+sortlog
diff --git a/test/scripts/2000-GnuTLS/2052 b/test/scripts/2000-GnuTLS/2052
deleted file mode 100644
index fa76b4849..000000000
--- a/test/scripts/2000-GnuTLS/2052
+++ /dev/null
@@ -1,22 +0,0 @@
-# TLS client: TLS setup fails - retry in clear (with fastopen)
-#
-# If all works you'll not see any difference. To enable in the
-# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
-# A packet capture on the loopback interface will show the TFU
-# option on the SYN, but the fast-output SMTP banner will not
-# be seen unless you also deliberately emulate a long path:
-# 'sudo tc qdisc add dev lo root netem delay 100ms'
-#
-# If the client-side is disabled in the kernel, Exim logs
-# will become noisy.
-#
-gnutls
-exim -DSERVER=server -bd -oX PORT_D
-****
-exim CALLER@test.ex
-Testing
-****
-exim -qf
-****
-killdaemon
-no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2090 b/test/scripts/2000-GnuTLS/2090
index 278f03429..91227e8ca 100644
--- a/test/scripts/2000-GnuTLS/2090
+++ b/test/scripts/2000-GnuTLS/2090
@@ -58,13 +58,7 @@ EHLO rhu.barb
??? 250-PIPELINING
??? 250-CHUNKING
??? 250 HELP
-MAIL FROM:<someone@some.domain>
-RCPT TO:<CALLER@test.ex>
-BDAT 88 LAST
-To: Susan@random.com
-From: Sam@random.com
-Subject: This is a bodyless test message
-
+MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
??? 250
??? 250
??? 250-
diff --git a/test/scripts/2100-OpenSSL/2113 b/test/scripts/2100-OpenSSL/2113
index e483763a3..3265b460d 100644
--- a/test/scripts/2100-OpenSSL/2113
+++ b/test/scripts/2100-OpenSSL/2113
@@ -10,7 +10,24 @@ Test message 2
exim userz@test.ex
Test message 3
****
-exim -qqf -d-all+acl
+exim -d-all+acl -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim usera@test.ex
+Test message 1
+****
+exim userb@test.ex
+Test message 2
+****
+exim userc@test.ex
+Test message 3
+****
+exim -DEQUIRE -d-all+acl -qqf
****
killdaemon
exim -DSERVER=server -DNOTDAEMON -qf
diff --git a/test/scripts/2100-OpenSSL/2135 b/test/scripts/2100-OpenSSL/2135
new file mode 100644
index 000000000..ff460c671
--- /dev/null
+++ b/test/scripts/2100-OpenSSL/2135
@@ -0,0 +1,28 @@
+# client: callout lazy-close, -bs send
+need_ipv4
+#
+# a tls-capable target for the verify/delivery connection
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# A recipient verify and continued-delivery. The debug output should show "already connected to",
+# "proxied TLS", and the DATA smtp command only done by the transport process.
+# cmdline -bs send
+exim -d-all+transport -bs
+mail from:<usera@ok.example>
+rcpt to:<userb@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+killdaemon
+exim -q
+****
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2136 b/test/scripts/2100-OpenSSL/2136
new file mode 100644
index 000000000..396075cc1
--- /dev/null
+++ b/test/scripts/2100-OpenSSL/2136
@@ -0,0 +1,75 @@
+# client: callout lazy-close, smtp send
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# smtp send
+# a tls-capable target for the verify/delivery connection on PORT_D
+# plus a daemon under test on PORT_S
+exim -bd -DSERVER=server -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+# smtp send, deliver_drop_priv
+exim -bd -DSERVER=server -DOPT=deliver_drop_privilege -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<usere@ok.example>
+??? 250
+RCPT TO:<userf@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2137 b/test/scripts/2100-OpenSSL/2137
new file mode 100644
index 000000000..36c36fe11
--- /dev/null
+++ b/test/scripts/2100-OpenSSL/2137
@@ -0,0 +1,30 @@
+# client: callout lazy-close, defers
+need_ipv4
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+# cmdline -bs send, rcpt-time defer
+exim -bs
+mail from:<>
+rcpt to:<rcpt_defer@test.ex>
+quit
+****
+sleep 3
+#
+# cmdline -bs send, data-time defer
+exim -bs
+mail from:<>
+rcpt to:<data_defer@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 3
+killdaemon
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2138 b/test/scripts/2100-OpenSSL/2138
new file mode 100644
index 000000000..3a94a1f2e
--- /dev/null
+++ b/test/scripts/2100-OpenSSL/2138
@@ -0,0 +1,18 @@
+# TLS client: multiple messages over one connection (continue_more)
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim userx0@test.ex userx1@test.ex
+Test message 1
+****
+exim usery0@test.ex usery1@test.ex
+Test message 2
+****
+exim userz0@test.ex userz1@test.ex
+Test message 3
+****
+exim -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+sortlog
diff --git a/test/scripts/2100-OpenSSL/2152 b/test/scripts/2100-OpenSSL/2152
deleted file mode 100644
index 12a482a93..000000000
--- a/test/scripts/2100-OpenSSL/2152
+++ /dev/null
@@ -1,21 +0,0 @@
-# TLS client: TLS setup fails - retry in clear (with fastopen)
-#
-# If all works you'll not see any difference. To enable in the
-# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
-# A packet capture on the loopback interface will show the TFO
-# option on the SYN, but the fast-output SMTP banner will not
-# be seen unless you also deliberately emulate a long path:
-# 'sudo tc qdisc add dev lo root netem delay 100ms'
-#
-# If the client-side is disabled in the kernel, Exim logs
-# will become noisy.
-#
-exim -DSERVER=server -bd -oX PORT_D
-****
-exim CALLER@test.ex
-Testing
-****
-exim -qf
-****
-killdaemon
-no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2190 b/test/scripts/2100-OpenSSL/2190
index 54095d49a..e004e5e02 100644
--- a/test/scripts/2100-OpenSSL/2190
+++ b/test/scripts/2100-OpenSSL/2190
@@ -57,13 +57,7 @@ EHLO rhu.barb
??? 250-PIPELINING
??? 250-CHUNKING
??? 250 HELP
-MAIL FROM:<someone@some.domain>
-RCPT TO:<CALLER@test.ex>
-BDAT 88 LAST
-To: Susan@random.com
-From: Sam@random.com
-Subject: This is a bodyless test message
-
+MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
??? 250
??? 250
??? 250-
diff --git a/test/scripts/4000-scanning/4012 b/test/scripts/4000-scanning/4012
new file mode 100644
index 000000000..42d108c86
--- /dev/null
+++ b/test/scripts/4000-scanning/4012
@@ -0,0 +1,45 @@
+# content scan interface: sock
+need_ipv4
+munge loopback
+#
+server PORT_S
+/
+>LF>RESULT: OK
+****
+#
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be accepted
+
+.
+quit
+****
+#
+#
+#
+server PORT_S
+/
+>LF>RESULT: BAD
+>LF>NAME: wibble
+****
+#
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be rejected
+
+due to the server response (above)
+.
+quit
+****
diff --git a/test/scripts/4020-socks/4020 b/test/scripts/4020-socks/4020
index 44c885b8d..4a0ac0893 100644
--- a/test/scripts/4020-socks/4020
+++ b/test/scripts/4020-socks/4020
@@ -81,5 +81,4 @@ quit
****
#
#
-#
-
+# Ends
diff --git a/test/scripts/4027-TFO-socks/4027 b/test/scripts/4027-TFO-socks/4027
new file mode 100644
index 000000000..533021cbf
--- /dev/null
+++ b/test/scripts/4027-TFO-socks/4027
@@ -0,0 +1,83 @@
+# socks5 proxy on smtp transport, TCP Fast Open
+#
+munge loopback
+#
+#
+# TFO client, not server
+server PORT_D
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me
+.
+250 accepted OK
+QUIT
+250 bye
+****
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<user_tfo@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be sent
+
+connection trying TFO
+via null-auth proxy
+.
+quit
+****
+#
+#
+#
+# TFO client and server
+server -tfo PORT_D
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me mate
+.
+250 accepted OK
+QUIT
+250 bye
+****
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<user_tfo@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be sent
+
+connection using TFO
+via null-auth proxy
+.
+quit
+****
+#
+#
+# Ends
diff --git a/test/scripts/4027-TFO-socks/REQUIRES b/test/scripts/4027-TFO-socks/REQUIRES
new file mode 100644
index 000000000..f7e42e611
--- /dev/null
+++ b/test/scripts/4027-TFO-socks/REQUIRES
@@ -0,0 +1,2 @@
+support SOCKS
+support TCP_Fast_Open
diff --git a/test/scripts/4500-DKIM/4500 b/test/scripts/4500-DKIM/4500
index 6728b141d..6b3ff5fcf 100644
--- a/test/scripts/4500-DKIM/4500
+++ b/test/scripts/4500-DKIM/4500
@@ -101,6 +101,40 @@ QUIT
****
#
#
+# This should pass. The pubkey dns decord has a additional sha1-only h= field
+#
+# - sha1, 512b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --keyfile=aux-fixed/dkim/dkim512.private \
+# --method=simple/simple --selector=ses_sha1 < aux-fixed/4500.msg1.txt
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+ :date:message-id:subject; s=ses_sha1; bh=OB9dZVu7+5/ufs3TH9leIcE
+ pXSo=; b=hG14R3Eb/f13Pw6J0LmovHAL01KHVmVrTZ7KJrqieYTQemUaseoU2pB
+ 7/g8NUwG/AsYoaw3gaAK8PqxSk2lcIQ==
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
killdaemon
no_stdout_check
no_msglog_check
diff --git a/test/scripts/4500-DKIM/4503 b/test/scripts/4500-DKIM/4503
new file mode 100644
index 000000000..aca19583b
--- /dev/null
+++ b/test/scripts/4500-DKIM/4503
@@ -0,0 +1,45 @@
+# DKIM verify, sha512
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# This should pass, only Mail::DKIM::Signer does not handle rsa-sha512.
+# - sha512, 1024b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --algorithm=rsa-sha512 \
+# --method=simple/simple < aux-fixed/4500.msg1.txt
+#
+# TODO - until we have that we can only test internal consistency,
+# signing vs. verification.
+#
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha512; c=simple/simple; d=test.ex; h=from:to
+ :date:message-id:subject; s=sel; bh=3UbbJTudPxmejzh7U1Zg33U3QT+1
+ 6kfV2eOTvMeiEis=; b=xQSD/JMqz0C+xKf0A1NTkPTbkDuDdJbpBuyjjT9iYvyP
+ Zez+xl0TkoPobFGVa6EN8+ZeYV18zjifhtWYLSsNmPinUtcpKQLG1zxAKmmS0JEh
+ +qihlWbeGJ5+tK588ugUzXHPj+4JBW0H6kxHvdH0l2SlQE5xs/cdggnx5QX5USY=
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+killdaemon
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/4500-DKIM/4506 b/test/scripts/4500-DKIM/4506
index 6eb81cc16..e8d7c41f0 100644
--- a/test/scripts/4500-DKIM/4506
+++ b/test/scripts/4500-DKIM/4506
@@ -134,6 +134,41 @@ QUIT
****
#
#
+# This should fail as the sig on the mail uses sha1 but the dns record requires sha256
+#
+# - sha256, 512b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --keyfile=aux-fixed/dkim/dkim512.private \
+# --method=simple/simple --selector=ses_sha1 < aux-fixed/4500.msg1.txt
+# and then modifying the s= manually
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+ :date:message-id:subject; s=ses_sha256; bh=OB9dZVu7+5/ufs3TH9leIcE
+ pXSo=; b=hG14R3Eb/f13Pw6J0LmovHAL01KHVmVrTZ7KJrqieYTQemUaseoU2pB
+ 7/g8NUwG/AsYoaw3gaAK8PqxSk2lcIQ==
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
killdaemon
no_stdout_check
no_msglog_check
diff --git a/test/scripts/4500-DKIM/4520 b/test/scripts/4500-DKIM/4520
index 6efe3545a..3e5879972 100644
--- a/test/scripts/4500-DKIM/4520
+++ b/test/scripts/4500-DKIM/4520
@@ -26,7 +26,7 @@ content
****
#
# check that on signing we warn in debug mode about verify problems
-exim -d-all+acl -DHEADERS_MAXSIZE=y -DSELECTOR=sel_bad -odf d@test.ex
+exim -d-all+acl -DOPT=From -DSELECTOR=sel_bad -odf d@test.ex
From: nobody@example.com
content
diff --git a/test/scripts/4500-DKIM/4523 b/test/scripts/4500-DKIM/4523
new file mode 100644
index 000000000..b897fc2a5
--- /dev/null
+++ b/test/scripts/4500-DKIM/4523
@@ -0,0 +1,15 @@
+# DKIM signing, sha512
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# default header set
+exim -DHEADERS_MAXSIZE=y -DVALUE=sha512 -odf a@test.ex
+From: nobody@example.com
+
+content
+****
+#
+millisleep 500
+killdaemon
+no_msglog_check
diff --git a/test/scripts/4500-DKIM/4524 b/test/scripts/4500-DKIM/4524
new file mode 100644
index 000000000..9737ad583
--- /dev/null
+++ b/test/scripts/4500-DKIM/4524
@@ -0,0 +1,14 @@
+# DKIM signing, multiple
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+exim -DSELECTOR=ses:sel -DOPT=From:To:Subject -odf c@test.ex
+From: nobody@example.com
+
+content
+****
+#
+millisleep 500
+killdaemon
+no_msglog_check
diff --git a/test/scripts/4500-DKIM/4530 b/test/scripts/4500-DKIM/4530
new file mode 100644
index 000000000..1465d5896
--- /dev/null
+++ b/test/scripts/4500-DKIM/4530
@@ -0,0 +1,68 @@
+# DKIM, CHUNKING, wireformat-spoolfile
+#
+exim -bd -DSERVER=server -DOPT=dkim -oX PORT_S:PORT_D
+****
+#
+# 1: non-CHUNKING injection; will not be stored as wireformat therefore
+# onward-send will not use sendfile. Should still be signed, and verify correctly.
+client 127.0.0.1 PORT_S
+??? 220
+EHLO xxx
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<z@test.ex>
+??? 250
+DATA
+??? 354
+Subject: simple test
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+..Line 3 has a leading dot
+last line: 4
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+# 2: CHUNKING injection; should be stored as wireformat therefore
+# onward-send should not use sendfile. Should still be signed, and verify correctly.
+client 127.0.0.1 PORT_S
+??? 220
+EHLO xxx
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<y@test.ex>
+??? 250
+BDAT 129 LAST
+Subject: simple test
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+.Line 3 has a leading dot
+last line: 4
+??? 250-
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+killdaemon
+exim -q
+****
+no_msglog_check
diff --git a/test/scripts/4700-dsn-info/4700 b/test/scripts/4700-dsn-info/4700
index d0dd4f363..29b2ce8b4 100644
--- a/test/scripts/4700-dsn-info/4700
+++ b/test/scripts/4700-dsn-info/4700
@@ -9,6 +9,8 @@ QUIT
exim -odi userx@domain1
Test message 1
****
+sudo rm DIR/spool/db/*
+#
server PORT_S
220 Connected OK
EHLO
@@ -20,6 +22,8 @@ QUIT
****
exim -qf
****
+sudo rm DIR/spool/db/*
+#
server PORT_S
550 Go away
QUIT
@@ -27,6 +31,8 @@ QUIT
****
exim -qf
****
+sudo rm DIR/spool/db/*
+#
server PORT_S
220 Connected OK
EHLO
diff --git a/test/scripts/5000-maildir/5010 b/test/scripts/5000-maildir/5010
new file mode 100644
index 000000000..9d30c01c3
--- /dev/null
+++ b/test/scripts/5000-maildir/5010
@@ -0,0 +1,35 @@
+# quota and maildir with no_check_support (5010, 5011, 5012)
+exim -odi userx@test.ex
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+****
+exim -odi userx@test.ex
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+****
+no_msglog_check
diff --git a/test/scripts/5000-maildir/5011 b/test/scripts/5000-maildir/5011
new file mode 120000
index 000000000..c95870fcb
--- /dev/null
+++ b/test/scripts/5000-maildir/5011
@@ -0,0 +1 @@
+5010 \ No newline at end of file
diff --git a/test/scripts/5000-maildir/5012 b/test/scripts/5000-maildir/5012
new file mode 120000
index 000000000..c95870fcb
--- /dev/null
+++ b/test/scripts/5000-maildir/5012
@@ -0,0 +1 @@
+5010 \ No newline at end of file
diff --git a/test/scripts/5600-OCSP-OpenSSL/5601 b/test/scripts/5600-OCSP-OpenSSL/5601
index ddcdeed9b..ecc763510 100644
--- a/test/scripts/5600-OCSP-OpenSSL/5601
+++ b/test/scripts/5600-OCSP-OpenSSL/5601
@@ -20,7 +20,7 @@ exim -bd -oX PORT_D -DSERVER=server \
exim nostaple@test.ex
test message.
****
-millisleep 500
+millisleep 700
#
#
#
diff --git a/test/scripts/5730-OCSP-GnuTLS-events/5730 b/test/scripts/5730-OCSP-GnuTLS-events/5730
index d22a1aa1f..11c3a867f 100644
--- a/test/scripts/5730-OCSP-GnuTLS-events/5730
+++ b/test/scripts/5730-OCSP-GnuTLS-events/5730
@@ -21,7 +21,7 @@ exim -bd -oX PORT_D -DSERVER=server \
exim norequire@test.ex
test message.
****
-millisleep 500
+millisleep 700
#
#
#
@@ -30,7 +30,7 @@ millisleep 500
exim nostaple@test.ex
test message.
****
-millisleep 500
+millisleep 700
#
#
#
diff --git a/test/scripts/5740-OCSP-OpenSSL-events/5740 b/test/scripts/5740-OCSP-OpenSSL-events/5740
index 43c545afa..414430630 100644
--- a/test/scripts/5740-OCSP-OpenSSL-events/5740
+++ b/test/scripts/5740-OCSP-OpenSSL-events/5740
@@ -5,7 +5,7 @@
# Client works when we request but don't require OCSP stapling and none comes
exim -bd -oX PORT_D -DSERVER=server -DRETURN=/dev/null
****
-exim norequire@test.ex
+exim norequire_1@test.ex
test message.
****
sleep 1
@@ -18,10 +18,10 @@ killdaemon
exim -bd -oX PORT_D -DSERVER=server \
-DRETURN=DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.ocsp.good.resp
****
-exim norequire@test.ex
+exim norequire_2@test.ex
test message.
****
-millisleep 500
+millisleep 700
#
#
#
@@ -30,7 +30,7 @@ millisleep 500
exim nostaple@test.ex
test message.
****
-millisleep 500
+millisleep 700
#
#
#
diff --git a/test/scripts/5840-DANE-OpenSSL/5840 b/test/scripts/5840-DANE-OpenSSL/5840
index d1da54913..142a25ad4 100644
--- a/test/scripts/5840-DANE-OpenSSL/5840
+++ b/test/scripts/5840-DANE-OpenSSL/5840
@@ -61,14 +61,26 @@ exim -DSERVER=server -DDETAILS=ee -bd -oX PORT_D
exim -odq CALLER@mxdanelazy.test.ex
Testing
****
-### A server lacking a TLSA, required
+### A server lacking a TLSA, dane required (should fail)
exim -odq CALLER@dane.no.1.test.ex
Testing
****
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
exim -odq CALLER@dane.no.2.test.ex
Testing
****
+### A server where the A is dnssec and the TLSA _fails_
+exim -odq CALLER@danebroken1.test.ex
+Testing
+****
+### A server securely saying "no TLSA records here", dane required (should fail)
+exim -odq CALLER@dane.no.3.test.ex
+Testing
+****
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
+exim -odq CALLER@dane.no.4.test.ex
+Testing
+****
exim -qf
****
killdaemon
diff --git a/test/src/fakens.c b/test/src/fakens.c
index 0806136cc..583b01282 100644
--- a/test/src/fakens.c
+++ b/test/src/fakens.c
@@ -53,11 +53,15 @@ HOST_NOT_FOUND.
Any DNS record line in a zone file can be prefixed with "DELAY=" and
a number of milliseconds (followed by one space).
-Any DNS record line in a zone file can be prefixed with "DNSSEC ";
+Any DNS record line can be prefixed with "DNSSEC ";
if all the records found by a lookup are marked
as such then the response will have the "AD" bit set.
-Any DNS record line in a zone file can be prefixed with "AA "
+Any DNS record line can be prefixed with "NXDOMAIN ";
+The record will be ignored (but the prefix set still applied);
+This lets us return a DNSSEC NXDOMAIN.
+
+Any DNS record line can be prefixed with "AA "
if all the records found by a lookup are marked
as such then the response will have the "AA" bit set.
@@ -342,9 +346,6 @@ if (typeptr->name == NULL)
rrdomain[0] = 0; /* No previous domain */
(void)fseek(f, 0, SEEK_SET); /* Start again at the beginning */
-if (dnssec) *dnssec = TRUE; /* cancelled by first nonsecure rec found */
-if (aa) *aa = TRUE; /* cancelled by first non-aa rec found */
-
/* Scan for RRs */
while (fgets(CS buffer, sizeof(buffer), f) != NULL)
@@ -357,6 +358,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
int qtlen = qtypelen;
BOOL rr_sec = FALSE;
BOOL rr_aa = FALSE;
+ BOOL rr_ignore = FALSE;
int delay = 0;
uint ttl = DEFAULT_TTL;
@@ -382,6 +384,11 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
rr_sec = TRUE;
p += 7;
}
+ if (Ustrncmp(p, US"NXDOMAIN ", 9) == 0) /* ignore record content */
+ {
+ rr_ignore = TRUE;
+ p += 9;
+ }
else if (Ustrncmp(p, US"AA ", 3) == 0) /* tagged as authoritative */
{
rr_aa = TRUE;
@@ -438,7 +445,12 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
/* The domain matches */
- if (yield == HOST_NOT_FOUND) yield = NO_DATA;
+ if (yield == HOST_NOT_FOUND)
+ {
+ yield = NO_DATA;
+ if (dnssec) *dnssec = TRUE; /* cancelled by first nonsecure rec found */
+ if (aa) *aa = TRUE; /* cancelled by first non-aa rec found */
+ }
/* Compare RR types; a CNAME record is always returned */
@@ -462,6 +474,8 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
if (aa && !rr_aa)
*aa = FALSE; /* cancel AA return */
+ if (rr_ignore) continue;
+
yield = 0;
*countptr = *countptr + 1;
diff --git a/test/src/server.c b/test/src/server.c
index ce55c5c37..5af86d96f 100644
--- a/test/src/server.c
+++ b/test/src/server.c
@@ -26,6 +26,7 @@ on all interfaces, unless the option -noipv6 is given. */
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <netinet/tcp.h>
#ifdef HAVE_NETINET_IP_VAR_H
# include <netinet/ip_var.h>
@@ -169,7 +170,7 @@ int connection_count = 1;
int count;
int on = 1;
int timeout = 5;
-int initial_pause = 0;
+int initial_pause = 0, tfo = 0;
int use_ipv4 = 1;
int use_ipv6 = 1;
int debug = 0;
@@ -214,6 +215,7 @@ if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
"\n\t-noipv6 disable ipv6"
"\n\t-oP file write PID to file"
"\n\t-t n n seconds timeout"
+ "\n\t-tfo enable TCP Fast Open"
);
exit(0);
}
@@ -221,6 +223,7 @@ if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
while (na < argc && argv[na][0] == '-')
{
if (strcmp(argv[na], "-d") == 0) debug = 1;
+ else if (strcmp(argv[na], "-tfo") == 0) tfo = 1;
else if (strcmp(argv[na], "-t") == 0)
{
if (tmo_noerror = ((timeout = atoi(argv[++na])) < 0)) timeout = -timeout;
@@ -295,7 +298,15 @@ else
printf("IPv6 socket creation failed: %s\n", strerror(errno));
exit(1);
}
-
+#ifdef TCP_FASTOPEN
+ if (tfo)
+ {
+ int backlog = 5;
+ if (setsockopt(listen_socket[v6n], IPPROTO_TCP, TCP_FASTOPEN,
+ &backlog, sizeof(backlog)))
+ if (debug) printf("setsockopt TCP_FASTOPEN: %s\n", strerror(errno));
+ }
+#endif
/* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
available. */
@@ -319,6 +330,15 @@ else
printf("IPv4 socket creation failed: %s\n", strerror(errno));
exit(1);
}
+#ifdef TCP_FASTOPEN
+ if (tfo)
+ {
+ int backlog = 5;
+ if (setsockopt(listen_socket[v4n], IPPROTO_TCP, TCP_FASTOPEN,
+ &backlog, sizeof(backlog)))
+ if (debug) printf("setsockopt TCP_FASTOPEN: %s\n", strerror(errno));
+ }
+#endif
}
}
diff --git a/test/stderr/0004 b/test/stderr/0004
index 310a4ef29..b9e93a910 100644
--- a/test/stderr/0004
+++ b/test/stderr/0004
@@ -479,4 +479,4 @@ LOG: H=[1.1.1.1] F=<BY@aa.bb> rejected RCPT <x@test.ex>
>>> deny: condition test succeeded in ACL "check_recipient"
>>> end of ACL "check_recipient": DENY
LOG: H=[1.1.1.1] F=<BlOcKeD@zz.xy> rejected RCPT <x@test.ex>
-LOG: unexpected disconnection while reading SMTP command from [1.1.1.1]
+LOG: unexpected disconnection while reading SMTP command from [1.1.1.1] D=qqs
diff --git a/test/stderr/0021 b/test/stderr/0021
index 7c5a79ee9..299cc4974 100644
--- a/test/stderr/0021
+++ b/test/stderr/0021
@@ -80,9 +80,10 @@ ok@test1 in "+ok_senders"? yes (matched "+ok_senders")
check sender_domains = +ok_sender_domains
test1 in "somewhere : test1 : test3"? yes (matched "test1")
test1 in "+ok_sender_domains"? yes (matched "+ok_sender_domains")
-check logwrite = :panic: rcpt accepted
+check logwrite = :panic: rcpt accepted C=$smtp_command_history
+ = :panic: rcpt accepted C=MAIL,MAIL,RCPT
LOG: PANIC
- rcpt accepted
+ rcpt accepted C=MAIL,MAIL,RCPT
accept: condition test succeeded in ACL "rcpt"
end of ACL "rcpt": ACCEPT
using ACL "rcpt"
@@ -94,9 +95,10 @@ ok@test1 in "+ok_senders"? yes (matched "+ok_senders" - cached)
check sender_domains = +ok_sender_domains
cached yes match for +ok_sender_domains
test1 in "+ok_sender_domains"? yes (matched "+ok_sender_domains" - cached)
-check logwrite = :panic: rcpt accepted
+check logwrite = :panic: rcpt accepted C=$smtp_command_history
+ = :panic: rcpt accepted C=MAIL,MAIL,RCPT,RCPT
LOG: PANIC
- rcpt accepted
+ rcpt accepted C=MAIL,MAIL,RCPT,RCPT
accept: condition test succeeded in ACL "rcpt"
end of ACL "rcpt": ACCEPT
LOG: smtp_connection MAIN
@@ -173,9 +175,10 @@ ok@test3 in "+ok_senders"? yes (matched "+ok_senders")
check sender_domains = +ok_sender_domains
test3 in "somewhere : test1 : test3"? yes (matched "test3")
test3 in "+ok_sender_domains"? yes (matched "+ok_sender_domains")
-check logwrite = :panic: rcpt accepted
+check logwrite = :panic: rcpt accepted C=$smtp_command_history
+ = :panic: rcpt accepted C=MAIL,RCPT
LOG: PANIC
- rcpt accepted
+ rcpt accepted C=MAIL,RCPT
accept: condition test succeeded in ACL "rcpt"
end of ACL "rcpt": ACCEPT
>>Headers added by MAIL or RCPT ACL:
@@ -197,4 +200,4 @@ LOG: smtp_connection MAIN
SMTP connection from CALLER closed by QUIT
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
1999-03-02 09:44:33 ACL "warn" with "message" setting found in a non-message (EHLO or HELO) ACL: cannot specify header lines here: message ignored
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=EHLO,MAIL,RCPT
diff --git a/test/stderr/0143 b/test/stderr/0143
index 3de426629..b1d0ff9b6 100644
--- a/test/stderr/0143
+++ b/test/stderr/0143
@@ -38,6 +38,7 @@ cmd buf flush ddd bytes
cmd buf flush ddd bytes
SMTP<< 354 Send data
SMTP>> writing message and terminating "."
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=300
SMTP<< 250 OK
ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL
diff --git a/test/stderr/0169 b/test/stderr/0169
index 70f11bf4f..30ed85f8d 100644
--- a/test/stderr/0169
+++ b/test/stderr/0169
@@ -24,6 +24,7 @@ writing to file TESTSUITE/test-mail/userx
Exim quota = 52428800 old size = sssss this message = sss (included)
file count quota = 0 count = 0
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
quota = 52428800 threshold = 21495808 old size = sssss message size = sss
diff --git a/test/stderr/0227 b/test/stderr/0227
index 6a8ee1f7e..e3282cc6f 100644
--- a/test/stderr/0227
+++ b/test/stderr/0227
@@ -222,10 +222,10 @@ LOG: smtp_connection MAIN
Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
SMTP<< 220 Server ready
SMTP>> EHLO myhost.test.ex
- SMTP<< 250- wotcher
+ SMTP<< 250- wotcher sverifier
250-SIZE
250 OK
- SMTP>> MAIL FROM:<> SIZE=ssss
+ SMTP>> MAIL FROM:<>
SMTP<< 250 OK
SMTP>> RCPT TO:<ok@localhost1>
SMTP<< 250 OK
@@ -238,6 +238,69 @@ LOG: smtp_connection MAIN
SMTP connection from root
Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
SMTP<< 220 Server ready
+ SMTP>> EHLO myhost.test.ex
+ SMTP<< 250- wotcher rverifier
+ 250-SIZE
+ 250 OK
+ SMTP>> MAIL FROM:<> SIZE=ssss
+ SMTP<< 250 OK
+ SMTP>> RCPT TO:<z@remote.domain>
+ SMTP<< 250 OK
+ SMTP>> QUIT
+ SMTP<< 250 OK
+ SMTP(close)>>
+LOG: MAIN REJECT
+ H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+LOG: smtp_connection MAIN
+ SMTP connection from root closed by QUIT
+LOG: smtp_connection MAIN
+ SMTP connection from root
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+ SMTP<< 220 Server ready
+ SMTP>> EHLO myhost.test.ex
+ SMTP<< 250- wotcher rverifier
+ 250-SIZE
+ 250 OK
+ SMTP>> MAIL FROM:<>
+ SMTP<< 250 OK
+ SMTP>> RCPT TO:<z@remote.domain>
+ SMTP<< 250 OK
+ SMTP>> QUIT
+ SMTP<< 250 OK
+ SMTP(close)>>
+LOG: MAIN REJECT
+ H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+LOG: smtp_connection MAIN
+ SMTP connection from root closed by QUIT
+LOG: smtp_connection MAIN
+ SMTP connection from root
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+ SMTP<< 220 Server ready
+ SMTP>> EHLO myhost.test.ex
+ SMTP<< 250- wotcher rverifier
+ 250-SIZE
+ 250 OK
+ SMTP>> MAIL FROM:<ok@localhost1>
+ SMTP<< 250 OK
+ SMTP>> RCPT TO:<myhost.test.ex-dddddddd-testing@remote.domain>
+ SMTP<< 550 RANDOM NOT OK
+ SMTP>> RSET
+ SMTP<< 250 OK
+ SMTP>> MAIL FROM:<ok@localhost1> SIZE=ssss
+ SMTP<< 250 OK
+ SMTP>> RCPT TO:<z@remote.domain>
+ SMTP<< 250 OK
+ SMTP>> QUIT
+ SMTP<< 250 OK
+ SMTP(close)>>
+LOG: MAIN REJECT
+ H=(me) [V4NET.0.0.7] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+LOG: smtp_connection MAIN
+ SMTP connection from root closed by QUIT
+LOG: smtp_connection MAIN
+ SMTP connection from root
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+ SMTP<< 220 Server ready
SMTP>> LHLO myhost.test.ex
SMTP<< 250 OK
SMTP>> MAIL FROM:<>
diff --git a/test/stderr/0275 b/test/stderr/0275
index 5f76af09a..089dc2a8b 100644
--- a/test/stderr/0275
+++ b/test/stderr/0275
@@ -198,9 +198,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -307,8 +308,9 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
diff --git a/test/stderr/0278 b/test/stderr/0278
index 2d9967293..b7c7913df 100644
--- a/test/stderr/0278
+++ b/test/stderr/0278
@@ -145,9 +145,10 @@ Delivery address list:
CALLER@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: CALLER@test.ex
@@ -209,8 +210,9 @@ search_tidyup called
--------> CALLER@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to CALLER <CALLER@test.ex> transport=t1
diff --git a/test/stderr/0361 b/test/stderr/0361
index 2506e1cfb..4d3bb363b 100644
--- a/test/stderr/0361
+++ b/test/stderr/0361
@@ -86,8 +86,9 @@ Delivery address list:
kilos@recurse.test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: kilos@recurse.test.ex
@@ -122,8 +123,9 @@ rewrite_one_header: type=F:
re-routed to kilos@recurse.test.ex.test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: kilos@recurse.test.ex.test.ex
@@ -161,8 +163,9 @@ routed by r3 router
transport: <none>
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: kilos@recurse.test.ex.test.ex
@@ -209,8 +212,9 @@ search_tidyup called
--------> kilos@recurse.test.ex.test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to kilos <kilos@recurse.test.ex.test.ex> transport=t2
diff --git a/test/stderr/0376 b/test/stderr/0376
index bcddefdfa..abd462b01 100644
--- a/test/stderr/0376
+++ b/test/stderr/0376
@@ -323,10 +323,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
SMTP(close)>>
wrote callout cache domain record for otherhost3:
result=1 postmaster=0 random=1
-LOG: MAIN REJECT
- H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK
-LOG: MAIN REJECT
- H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
LOG: smtp_connection MAIN
SMTP connection from root closed by QUIT
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -373,10 +369,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
SMTP(close)>>
wrote callout cache domain record for otherhost4:
result=1 postmaster=0 random=1
-LOG: MAIN REJECT
- H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-LOG: MAIN REJECT
- H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
LOG: smtp_connection MAIN
SMTP connection from root closed by QUIT
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/0386 b/test/stderr/0386
index 44e856da2..5573a9964 100644
--- a/test/stderr/0386
+++ b/test/stderr/0386
@@ -252,9 +252,10 @@ Delivery address list:
2@b
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: 2@b
@@ -289,8 +290,9 @@ search_tidyup called
--------> 2@b <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to 2 <2@b> transport=t1
@@ -310,6 +312,7 @@ lock file created
mailbox TESTSUITE/test-mail/2 is locked
writing to file TESTSUITE/test-mail/2
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
@@ -433,8 +436,9 @@ Delivery address list:
2@b
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: 2@b
@@ -469,8 +473,9 @@ search_tidyup called
--------> 2@b <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to 2 <2@b> transport=t1
@@ -490,6 +495,7 @@ lock file created
mailbox TESTSUITE/test-mail/2 is locked
writing to file TESTSUITE/test-mail/2
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
diff --git a/test/stderr/0388 b/test/stderr/0388
index 92b3f23e1..5a21445c9 100644
--- a/test/stderr/0388
+++ b/test/stderr/0388
@@ -9,9 +9,10 @@ set_process_info: pppp delivering specified messages
set_process_info: pppp delivering 10HmaX-0005vi-00
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: x@y
@@ -76,8 +77,9 @@ set_process_info: pppp delivering 10HmaX-0005vi-00 using smtp
checking status of 127.0.0.1
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
127.0.0.1 in serialize_hosts? no (option unset)
set_process_info: pppp delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (x@y)
@@ -107,8 +109,9 @@ address match test: subject=*@127.0.0.1 pattern=*
checking status of V4NET.0.0.0
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
V4NET.0.0.0 in serialize_hosts? no (option unset)
set_process_info: pppp delivering 10HmaX-0005vi-00 to V4NET.0.0.0 [V4NET.0.0.0] (x@y)
@@ -137,8 +140,8 @@ Deferred addresses:
x@y
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR
address match test: subject=x@y pattern=*
y in "*"? yes (matched "*")
@@ -164,6 +167,7 @@ dbfn_write: key=T:V4NET.0.0.0:V4NET.0.0.0:1224
timed out: all retries expired
LOG: MAIN
** x@y: retry timeout exceeded
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
end of retry processing
exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xebb95ced -odi -odi -t -oem -oi -f <> -E10HmaX-0005vi-00
@@ -236,8 +240,8 @@ set_process_info: pppp delivering specified messages
set_process_info: pppp delivering 10HmaY-0005vi-00
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: CALLER@myhost.test.ex
@@ -248,6 +252,7 @@ dbfn_read: key=R:CALLER@myhost.test.ex:<>
no domain retry record
no address retry record
CALLER@myhost.test.ex: queued for routing
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
routing CALLER@myhost.test.ex
diff --git a/test/stderr/0393 b/test/stderr/0393
index dd0887f09..7fb82e35c 100644
--- a/test/stderr/0393
+++ b/test/stderr/0393
@@ -28,6 +28,7 @@ mailbox TESTSUITE/test-mail/userx is locked
writing to file TESTSUITE/test-mail/userx
writing data block fd=dddd size=sss timeout=0
process pppp running as transport filter: fd_write=dddd fd_read=dddd
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
process pppp writing to transport filter
copying from the filter
@@ -70,6 +71,7 @@ lock file created
mailbox TESTSUITE/test-mail/userx is locked
writing to file TESTSUITE/test-mail/userx
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
@@ -108,6 +110,7 @@ lock file created
mailbox TESTSUITE/test-mail/userx is locked
writing to file TESTSUITE/test-mail/userx
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
diff --git a/test/stderr/0398 b/test/stderr/0398
index b975ad05a..f61f37457 100644
--- a/test/stderr/0398
+++ b/test/stderr/0398
@@ -120,13 +120,14 @@ routed by r2 router
Attempting full verification using callout
locking TESTSUITE/spool/db/callout.lockfile
locked TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
dbfn_read: key=remote
callout cache: found domain record for remote
dbfn_read: key=qq@remote
callout cache: no address record found for qq@remote
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
interface=NULL port=1224
Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
@@ -150,14 +151,15 @@ cmd buf flush ddd bytes
SMTP(close)>>
locking TESTSUITE/spool/db/callout.lockfile
locked TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x42
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR|O_CREAT
dbfn_write: key=remote
wrote callout cache domain record for remote:
result=1 postmaster=0 random=0
dbfn_write: key=qq@remote
wrote negative callout cache address record for qq@remote
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
----------- end verify ------------
l_message: $acl_verify_message
@@ -231,14 +233,15 @@ routed by r2 router
Attempting full verification using callout
locking TESTSUITE/spool/db/callout.lockfile
locked TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
dbfn_read: key=remote
callout cache: found domain record for remote
dbfn_read: key=qq@remote
callout cache: found address record for qq@remote
callout cache: address record is negative
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
----------- end verify ------------
l_message: $acl_verify_message
diff --git a/test/stderr/0402 b/test/stderr/0402
index a007de31c..8d62a2ef5 100644
--- a/test/stderr/0402
+++ b/test/stderr/0402
@@ -221,9 +221,10 @@ Delivery address list:
rd+usery@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: CALLER@test.ex
@@ -416,8 +417,9 @@ routed by r1 router
transport: t1
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: TESTSUITE/test-mail/junk
@@ -443,8 +445,9 @@ search_tidyup called
--------> TESTSUITE/test-mail/junk <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
┌considering: /non-exist/$local_part
├──expanding: /non-exist/$local_part
@@ -487,6 +490,7 @@ writing to file TESTSUITE/test-mail/junk
└─────result: From CALLER@test.ex Tue Mar 02 09:44:33 1999
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
@@ -501,8 +505,9 @@ LOG: MAIN
--------> TESTSUITE/test-mail/junk <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to TESTSUITE/test-mail/junk <TESTSUITE/test-mail/junk> transport=ft1
@@ -542,6 +547,7 @@ writing to file TESTSUITE/test-mail/junk
└─────result: From CALLER@test.ex Tue Mar 02 09:44:33 1999
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
@@ -556,8 +562,9 @@ LOG: MAIN
--------> CALLER@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to CALLER <CALLER@test.ex> transport=t1
@@ -581,8 +588,9 @@ LOG: MAIN
--------> usery@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
┌considering: /non-exist/$local_part
├──expanding: /non-exist/$local_part
@@ -609,8 +617,9 @@ LOG: MAIN
--------> userz@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
┌considering: /$local_part
├──expanding: /$local_part
diff --git a/test/stderr/0403 b/test/stderr/0403
index 716cabdf2..a77d8cd98 100644
--- a/test/stderr/0403
+++ b/test/stderr/0403
@@ -74,9 +74,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -137,8 +138,9 @@ routed by r1 router
transport: <none>
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: TESTSUITE/test-mail/junk
@@ -156,8 +158,9 @@ search_tidyup called
--------> TESTSUITE/test-mail/junk <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to TESTSUITE/test-mail/junk <TESTSUITE/test-mail/junk> transport=t1
diff --git a/test/stderr/0404 b/test/stderr/0404
index d3d8f4c64..1718307be 100644
--- a/test/stderr/0404
+++ b/test/stderr/0404
@@ -177,9 +177,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -220,8 +221,9 @@ routed by r2 router
transport: <none>
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ...
@@ -239,8 +241,9 @@ search_tidyup called
--------> >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ... <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ... <>sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ...> transport=t1
@@ -3375,8 +3378,9 @@ Delivery address list:
sender@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: sender@test.ex
@@ -17981,8 +17985,9 @@ sender@test.ex is a duplicate address: discarded
--------> sender@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to sender <sender@test.ex> transport=t2
@@ -18004,6 +18009,7 @@ writing to file TESTSUITE/test-mail/sender
writing data block fd=dddd size=sss timeout=0
flushing headers buffer
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
diff --git a/test/stderr/0408 b/test/stderr/0408
index f3d6d6b1a..fddbe4a46 100644
--- a/test/stderr/0408
+++ b/test/stderr/0408
@@ -74,9 +74,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -138,8 +139,9 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -159,6 +161,7 @@ lock file created
mailbox TESTSUITE/test-mail/userx is locked
writing to file TESTSUITE/test-mail/userx
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
diff --git a/test/stderr/0432 b/test/stderr/0432
index 6ac5a0428..79117e25a 100644
--- a/test/stderr/0432
+++ b/test/stderr/0432
@@ -81,13 +81,14 @@ get[host|ipnode]byname[2] looked up these IP addresses:
Attempting full verification using callout
locking TESTSUITE/spool/db/callout.lockfile
locked TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
dbfn_read: key=y
callout cache: no domain record found for y
dbfn_read: key=x@y
callout cache: no address record found for x@y
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
interface=NULL port=1224
Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
@@ -111,14 +112,15 @@ cmd buf flush ddd bytes
SMTP(close)>>
locking TESTSUITE/spool/db/callout.lockfile
locked TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x42
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR|O_CREAT
dbfn_write: key=y
wrote callout cache domain record for y:
result=1 postmaster=0 random=0
dbfn_write: key=x@y
wrote positive callout cache address record for x@y
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
----------- end verify ------------
sender x@y verified ok
@@ -189,14 +191,15 @@ get[host|ipnode]byname[2] looked up these IP addresses:
Attempting full verification using callout
locking TESTSUITE/spool/db/callout.lockfile
locked TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
dbfn_read: key=y
callout cache: found domain record for y
dbfn_read: key=x@y
callout cache: found address record for x@y
callout cache: address record is positive
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
----------- end verify ------------
sender x@y verified ok
diff --git a/test/stderr/0476 b/test/stderr/0476
index 59ea69f58..675c6239c 100644
--- a/test/stderr/0476
+++ b/test/stderr/0476
@@ -52,6 +52,7 @@ set_process_info: pppp delivering 10HmaX-0005vi-00
LOG: MAIN
** userx@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after RCPT TO:<userx@test.ex>: 550 NO
set_process_info: pppp tidying up after delivering 10HmaX-0005vi-00
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
Exim version x.yz ....
configuration file is TESTSUITE/test-config
diff --git a/test/stderr/0487 b/test/stderr/0487
index 7319b67dd..56e21b60e 100644
--- a/test/stderr/0487
+++ b/test/stderr/0487
@@ -103,9 +103,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -140,8 +141,9 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -163,6 +165,7 @@ writing to file TESTSUITE/test-mail/userx
writing data block fd=dddd size=sss timeout=0
rewrite_one_header: type=F:
From: unqualified
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
diff --git a/test/stderr/0512 b/test/stderr/0512
index 1cdf5f013..07025d5d7 100644
--- a/test/stderr/0512
+++ b/test/stderr/0512
@@ -59,6 +59,7 @@ LOG: MAIN
== userx@myhost.test.ex R=r1 T=t1 defer (dd): Connection refused
LOG: MAIN
** userx@myhost.test.ex: retry timeout exceeded
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
Exim version x.yz ....
configuration file is TESTSUITE/test-config
@@ -122,6 +123,7 @@ LOG: MAIN
== userx@myhost.test.ex R=r1 T=t1 defer (dd): Connection refused
LOG: MAIN
** userx@myhost.test.ex: retry timeout exceeded
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
Exim version x.yz ....
configuration file is TESTSUITE/test-config
diff --git a/test/stderr/0547 b/test/stderr/0547
index 980da7a0b..539328631 100644
--- a/test/stderr/0547
+++ b/test/stderr/0547
@@ -8,7 +8,7 @@
>>> host in helo_accept_junk_hosts? no (option unset)
>>> rhu.barb in helo_lookup_domains? no (end of list)
>>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
-LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=0s C=...HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,QUIT
+LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=qqs C=...HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,QUIT
>>> host in hosts_connection_nolog? no (option unset)
>>> host in host_lookup? no (option unset)
>>> host in host_reject_connection? no (option unset)
@@ -20,6 +20,6 @@ LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=0s C=...HELP,RSET,N
>>> rhu.barb in helo_lookup_domains? no (end of list)
>>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
LOG: SMTP call from (rhu.barb) [10.9.8.7] dropped: too many nonmail commands (last was "HELP")
-LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=0s C=HELO,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP
+LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=qqs C=HELO,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP
******** SERVER ********
diff --git a/test/stderr/0551 b/test/stderr/0551
new file mode 100644
index 000000000..134ebac6b
--- /dev/null
+++ b/test/stderr/0551
@@ -0,0 +1,305 @@
+14:07:56 7857 Exim version x.yz uid=CALLER_UID gid=CALLER_GID pid=pppp D=fffdffff
+14:07:56 7857 Total 20 lookups
+14:07:56 7857 changed uid/gid: forcing real = effective
+14:07:56 7857 uid=uuuu gid=CALLER_GID pid=pppp
+14:07:56.452 7857 configuration file is TESTSUITE/test-config
+14:07:56.452 7857 log selectors = 00000ffc 0c64c60a
+14:07:56.452 7857 cwd=TESTSUITE 8 args: TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d+all -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -odi userx@test.ex
+14:07:56.452 7857 admin user
+14:07:56.453 7857 changed uid/gid: privilege not needed
+14:07:56.453 7857 uid=EXIM_UID gid=EXIM_GID pid=pppp
+14:07:56.453 7857 DSN: r1 propagating DSN
+14:07:56.453 7857 seeking password data for user "CALLER": cache not available
+14:07:56.453 7857 getpwnam() succeeded uid=CALLER_UID gid=CALLER_GID
+14:07:56.453 7857 originator: uid=CALLER_UID gid=CALLER_GID login=CALLER name=CALLER_NAME
+14:07:56.453 7857 sender address = CALLER@myhost.test.ex
+14:07:56.453 7857 set_process_info: pppp accepting a local non-SMTP message from <CALLER@myhost.test.ex>
+14:07:56.453 7857 spool directory space = 157852648K inodes = 26802407 check_space = 10240K inodes = 100 msg_size = 0
+14:07:56.453 7857 log directory space = 157852648K inodes = 26802407 check_space = 10240K inodes = 100
+14:07:56.453 7857 Sender: CALLER@myhost.test.ex
+14:07:56.453 7857 Recipients:
+14:07:56.453 7857 userx@test.ex
+14:07:56.453 7857 search_tidyup called
+14:07:56.453 7857 >>Headers received:
+14:07:56.453 7857
+14:07:56.453 7857 rewrite_one_header: type=F:
+14:07:56.453 7857 From: CALLER_NAME <CALLER@myhost.test.ex>
+14:07:56.453 7857 search_tidyup called
+14:07:56.453 7857 >>Headers after rewriting and local additions:
+14:07:56.453 7857 I Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+14:07:56.453 7857 F From: CALLER_NAME <CALLER@myhost.test.ex>
+14:07:56.453 7857 Date: Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.453 7857
+14:07:56.453 7857 Data file name: TESTSUITE/spool//input//10HmaZ-0005vi-00-D
+14:07:56.455 7857 Data file written for message 10HmaZ-0005vi-00
+14:07:56.455 7857 ┌considering: ${tod_full}
+14:07:56.455 7857 ├──expanding: ${tod_full}
+14:07:56.455 7857 └─────result: Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.455 7857 ┌considering: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+14:07:56.455 7857 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──condition: def:sender_rcvhost
+14:07:56.455 7857 ├─────result: false
+14:07:56.455 7857 ┌───scanning: from $sender_rcvhost
+14:07:56.455 7857 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──expanding: from $sender_rcvhost
+14:07:56.455 7857
+14:07:56.455 7857 ├─────result: from
+14:07:56.455 7857
+14:07:56.455 7857 └───skipping: result is not used
+14:07:56.455 7857 ┌considering: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──condition: def:sender_ident
+14:07:56.455 7857 ├─────result: true
+14:07:56.455 7857 ┌considering: from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ╎┌considering: $sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 ╎ }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857 ╎}} (Exim $version_number)
+14:07:56.455 7857 ╎ ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 ╎ }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 ╎ for $received_for}}
+14:07:56.455 7857 ╎├──expanding: $sender_ident
+14:07:56.455 7857 ╎└─────result: CALLER
+14:07:56.455 7857 ├──expanding: from ${quote_local_part:$sender_ident}
+14:07:56.455 7857 └─────result: from CALLER
+14:07:56.455 7857 ├──condition: def:sender_helo_name
+14:07:56.455 7857 ├─────result: false
+14:07:56.455 7857 ┌───scanning: (helo=$sender_helo_name)
+14:07:56.455 7857 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──expanding: (helo=$sender_helo_name)
+14:07:56.455 7857
+14:07:56.455 7857 ├─────result: (helo=)
+14:07:56.455 7857
+14:07:56.455 7857 └───skipping: result is not used
+14:07:56.455 7857 ├──expanding: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 }}
+14:07:56.455 7857 └─────result: from CALLER
+14:07:56.455 7857 ├──condition: def:received_protocol
+14:07:56.455 7857 ├─────result: true
+14:07:56.455 7857 ┌considering: with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──expanding: with $received_protocol
+14:07:56.455 7857 └─────result: with local
+14:07:56.455 7857 ├──condition: def:tls_cipher
+14:07:56.455 7857 ├─────result: false
+14:07:56.455 7857 ┌───scanning: ($tls_cipher)
+14:07:56.455 7857 }}(Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──expanding: ($tls_cipher)
+14:07:56.455 7857
+14:07:56.455 7857 ├─────result: ()
+14:07:56.455 7857
+14:07:56.455 7857 └───skipping: result is not used
+14:07:56.455 7857 ├──condition: def:sender_address
+14:07:56.455 7857 ├─────result: true
+14:07:56.455 7857 ┌considering: (envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──expanding: (envelope-from <$sender_address>)
+14:07:56.455 7857
+14:07:56.455 7857 └─────result: (envelope-from <CALLER@myhost.test.ex>)
+14:07:56.455 7857
+14:07:56.455 7857 ├──condition: def:received_for
+14:07:56.455 7857 ├─────result: true
+14:07:56.455 7857 ┌considering:
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 ├──expanding:
+14:07:56.455 7857 for $received_for
+14:07:56.455 7857 └─────result:
+14:07:56.455 7857 for userx@test.ex
+14:07:56.455 7857 ├──expanding: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+14:07:56.455 7857 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455 7857 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455 7857}} (Exim $version_number)
+14:07:56.455 7857 ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455 7857 }}id $message_exim_id${if def:received_for {
+14:07:56.455 7857 for $received_for}}
+14:07:56.455 7857 └─────result: Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+14:07:56.455 7857 (envelope-from <CALLER@myhost.test.ex>)
+14:07:56.455 7857 id 10HmaZ-0005vi-00
+14:07:56.455 7857 for userx@test.ex
+14:07:56.455 7857 >>Generated Received: header line
+14:07:56.455 7857 P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+14:07:56.455 7857 (envelope-from <CALLER@myhost.test.ex>)
+14:07:56.455 7857 id 10HmaZ-0005vi-00
+14:07:56.455 7857 for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.455 7857 calling local_scan(); timeout=300
+14:07:56.455 7857 local_scan() returned 0 NULL
+14:07:56.455 7857 ┌considering: ${tod_full}
+14:07:56.455 7857 ├──expanding: ${tod_full}
+14:07:56.455 7857 └─────result: Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.455 7857 Writing spool header file: TESTSUITE/spool//input//hdr.7857
+14:07:56.455 7857 DSN: Write SPOOL :-dsn_envid NULL
+14:07:56.455 7857 DSN: Write SPOOL :-dsn_ret 0
+14:07:56.455 7857 DSN: Flags :0
+14:07:56.455 7857 DSN: **** SPOOL_OUT - address: |userx@test.ex| errorsto: |NULL| orcpt: |NULL| dsn_flags: 0
+14:07:56.457 7857 Renaming spool header file: TESTSUITE/spool//input//10HmaZ-0005vi-00-H
+14:07:56.459 7857 Size of headers = sss
+14:07:56.459 7857 LOG: MAIN
+14:07:56.459 7857 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+14:07:56.459 7857 search_tidyup called
+14:07:56.459 7858 exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -C TESTSUITE/test-config -d=0xfffdffff -odi -Mc 10HmaZ-0005vi-00
+14:07:56 7858 Exim version x.yz uid=EXIM_UID gid=EXIM_GID pid=pppp D=fffdffff
+14:07:56 7858 Total 20 lookups
+14:07:56 7858 changed uid/gid: forcing real = effective
+14:07:56 7858 uid=uuuu gid=EXIM_GID pid=pppp
+14:07:56.565 7858 configuration file is TESTSUITE/test-config
+14:07:56.565 7858 log selectors = 00000ffc 0c64c60a
+14:07:56.565 7858 cwd=TESTSUITE/spool 9 args: TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -C TESTSUITE/test-config -d=0xfffdffff -odi -Mc 10HmaZ-0005vi-00
+14:07:56.565 7858 trusted user
+14:07:56.565 7858 admin user
+14:07:56.565 7858 DSN: r1 propagating DSN
+14:07:56.565 7858 seeking password data for user "CALLER": cache not available
+14:07:56.565 7858 getpwnam() succeeded uid=CALLER_UID gid=CALLER_GID
+14:07:56.565 7858 set_process_info: pppp delivering specified messages
+14:07:56.565 7858 set_process_info: pppp delivering 10HmaZ-0005vi-00
+14:07:56.565 7858 Trying spool file TESTSUITE/spool//input//10HmaZ-0005vi-00-D
+14:07:56.565 7858 reading spool file 10HmaZ-0005vi-00-H
+14:07:56.565 7858 user=CALLER uid=CALLER_UID gid=CALLER_GID sender=CALLER@myhost.test.ex
+14:07:56.565 7858 sender_local=1 ident=CALLER
+14:07:56.565 7858 Non-recipients:
+14:07:56.565 7858 Empty Tree
+14:07:56.565 7858 ---- End of tree ----
+14:07:56.565 7858 recipients_count=1
+14:07:56.565 7858 **** SPOOL_IN - No additional fields
+14:07:56.565 7858 body_linecount=1 message_linecount=7
+14:07:56.565 7858 DSN: set orcpt: NULL flags: 0
+14:07:56.565 7858 Delivery address list:
+14:07:56.565 7858 userx@test.ex
+14:07:56.566 7858 locking TESTSUITE/spool/db/retry.lockfile
+14:07:56.566 7858 locked TESTSUITE/spool/db/retry.lockfile
+14:07:56.566 7858 EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+14:07:56.566 7858 returned from EXIM_DBOPEN: (nil)
+14:07:56.566 7858 failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
+14:07:56.566 7858 no retry data available
+14:07:56.566 7858 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+14:07:56.566 7858 Considering: userx@test.ex
+14:07:56.566 7858 unique = userx@test.ex
+14:07:56.566 7858 no domain retry record
+14:07:56.566 7858 no address retry record
+14:07:56.566 7858 userx@test.ex: queued for routing
+14:07:56.566 7858 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+14:07:56.566 7858 routing userx@test.ex
+14:07:56.566 7858 --------> r1 router <--------
+14:07:56.566 7858 local_part=userx domain=test.ex
+14:07:56.566 7858 calling r1 router
+14:07:56.566 7858 r1 router called for userx@test.ex
+14:07:56.566 7858 domain = test.ex
+14:07:56.566 7858 set transport t1
+14:07:56.566 7858 queued for t1 transport: local_part = userx
+14:07:56.566 7858 domain = test.ex
+14:07:56.566 7858 errors_to=NULL
+14:07:56.566 7858 domain_data=NULL localpart_data=NULL
+14:07:56.566 7858 routed by r1 router
+14:07:56.566 7858 envelope to: userx@test.ex
+14:07:56.566 7858 transport: t1
+14:07:56.566 7858 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+14:07:56.566 7858 After routing:
+14:07:56.566 7858 Local deliveries:
+14:07:56.566 7858 userx@test.ex
+14:07:56.566 7858 Remote deliveries:
+14:07:56.566 7858 Failed addresses:
+14:07:56.566 7858 Deferred addresses:
+14:07:56.566 7858 search_tidyup called
+14:07:56.566 7858 >>>>>>>>>>>>>>>> Local deliveries >>>>>>>>>>>>>>>>
+14:07:56.566 7858 --------> userx@test.ex <--------
+14:07:56.566 7858 locking TESTSUITE/spool/db/retry.lockfile
+14:07:56.566 7858 locked TESTSUITE/spool/db/retry.lockfile
+14:07:56.566 7858 EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+14:07:56.566 7858 returned from EXIM_DBOPEN: (nil)
+14:07:56.566 7858 failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
+14:07:56.566 7858 no retry data available
+14:07:56.566 7858 search_tidyup called
+14:07:56.566 7859 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
+14:07:56.566 7859 uid=CALLER_UID gid=CALLER_GID pid=pppp
+14:07:56.566 7859 home=NULL current=/
+14:07:56.566 7859 set_process_info: pppp delivering 10HmaZ-0005vi-00 to userx using t1
+14:07:56.566 7859 appendfile transport entered
+14:07:56.566 7859 ┌considering: TESTSUITE/test-mail/$local_part
+14:07:56.566 7859 ├──expanding: TESTSUITE/test-mail/$local_part
+14:07:56.566 7859 └─────result: TESTSUITE/test-mail/userx
+14:07:56.566 7859 appendfile: mode=600 notify_comsat=0 quota=0 warning=0
+14:07:56.566 7859 file=TESTSUITE/test-mail/userx format=unix
+14:07:56.566 7859 message_prefix=From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}\n
+14:07:56.566 7859 message_suffix=\n
+14:07:56.566 7859 maildir_use_size_file=no
+14:07:56.566 7859 locking by lockfile fcntl
+14:07:56.566 7859 lock name: TESTSUITE/test-mail/userx.lock
+14:07:56.566 7859 hitch name: TESTSUITE/test-mail/userx.lock.test.ex.dddddddd.pppppppp
+14:07:56.566 7859 lock file created
+14:07:56.566 7859 mailbox TESTSUITE/test-mail/userx is locked
+14:07:56.566 7859 writing to file TESTSUITE/test-mail/userx
+14:07:56.566 7859 ┌considering: From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566 7859
+14:07:56.566 7859 ├──condition: def:return_path
+14:07:56.566 7859 ├─────result: true
+14:07:56.566 7859 ┌considering: $return_path}{MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566 7859
+14:07:56.566 7859 ├──expanding: $return_path
+14:07:56.566 7859 └─────result: CALLER@myhost.test.ex
+14:07:56.566 7859 ┌───scanning: MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566 7859
+14:07:56.566 7859 ├──expanding: MAILER-DAEMON
+14:07:56.566 7859 ├─────result: MAILER-DAEMON
+14:07:56.566 7859 └───skipping: result is not used
+14:07:56.566 7859 ├──expanding: From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566 7859
+14:07:56.566 7859 └─────result: From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+14:07:56.566 7859
+14:07:56.566 7859 writing data block fd=6 size=sss timeout=0
+14:07:56.567 7859 cannot use sendfile for body: spoolfile not wireformat
+14:07:56.567 7859 writing data block fd=6 size=sss timeout=0
+14:07:56.567 7859 writing data block fd=6 size=sss timeout=0
+14:07:56.568 7859 appendfile yields 0 with errno=dd more_errno=dd
+14:07:56.568 7859 search_tidyup called
+14:07:56.868 7858 journalling userx@test.ex
+14:07:56.871 7858 t1 transport returned OK for userx@test.ex
+14:07:56.871 7858 post-process userx@test.ex (0)
+14:07:56.871 7858 userx@test.ex delivered
+14:07:56.871 7858 LOG: MAIN
+14:07:56.871 7858 => userx <userx@test.ex> R=r1 T=t1 QT=q.qqqs DT=q.qqqs
+14:07:56.871 7858 >>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>
+14:07:56.871 7858 changed uid/gid: post-delivery tidying
+14:07:56.871 7858 uid=EXIM_UID gid=EXIM_GID pid=pppp
+14:07:56.871 7858 set_process_info: pppp tidying up after delivering 10HmaZ-0005vi-00
+14:07:56.871 7858 Processing retry items
+14:07:56.871 7858 Succeeded addresses:
+14:07:56.871 7858 userx@test.ex: no retry items
+14:07:56.871 7858 Failed addresses:
+14:07:56.871 7858 Deferred addresses:
+14:07:56.871 7858 end of retry processing
+14:07:56.871 7858 DSN: processing router : r1
+14:07:56.871 7858 DSN: processing successful delivery address: userx@test.ex
+14:07:56.871 7858 DSN: Sender_address: CALLER@myhost.test.ex
+14:07:56.871 7858 DSN: orcpt: NULL flags: 0
+14:07:56.871 7858 DSN: envid: NULL ret: 0
+14:07:56.871 7858 DSN: Final recipient: userx@test.ex
+14:07:56.871 7858 DSN: Remote SMTP server supports DSN: 0
+14:07:56.871 7858 DSN: not sending DSN success message
+14:07:56.871 7858 LOG: MAIN
+14:07:56.871 7858 Completed QT=q.qqqs
+14:07:56.871 7858 end delivery of 10HmaZ-0005vi-00
+14:07:56.871 7858 search_tidyup called
+14:07:56.871 7858 search_tidyup called
+14:07:56.871 7858 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+14:07:56.871 7857 search_tidyup called
+14:07:56.871 7857 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/0578 b/test/stderr/0578
index 74581fd9c..9f634c8c4 100644
--- a/test/stderr/0578
+++ b/test/stderr/0578
@@ -337,10 +337,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
SMTP(close)>>
wrote callout cache domain record for otherhost3:
result=1 postmaster=0 random=1
-LOG: MAIN REJECT
- H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK accepting that random recipient
-LOG: MAIN REJECT
- H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
LOG: smtp_connection MAIN
SMTP connection from root closed by QUIT
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -389,10 +385,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
SMTP(close)>>
wrote callout cache domain record for otherhost4:
result=1 postmaster=0 random=1
-LOG: MAIN REJECT
- H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-LOG: MAIN REJECT
- H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
LOG: smtp_connection MAIN
SMTP connection from root closed by QUIT
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/0609 b/test/stderr/0609
index be6514446..ea998d6d7 100644
--- a/test/stderr/0609
+++ b/test/stderr/0609
@@ -45,7 +45,7 @@ ppppp delay cancelled by peer close
ppppp accept: condition test succeeded in ACL "delay4_accept"
ppppp end of ACL "delay4_accept": ACCEPT
ppppp LOG: lost_incoming_connection MAIN
-ppppp unexpected disconnection while reading SMTP command from [127.0.0.1]
+ppppp unexpected disconnection while reading SMTP command from [127.0.0.1] D=qqs
ppppp child ppppp ended: status=0x100
ppppp normal exit, 1
ppppp 0 SMTP accept processes now running
diff --git a/test/stderr/0907 b/test/stderr/0907
new file mode 100644
index 000000000..fe9ba7150
--- /dev/null
+++ b/test/stderr/0907
@@ -0,0 +1,2 @@
+1999-03-02 09:44:33 Exim configuration error in line 1 of TESTSUITE/test-config:
+ found unexpected BOM (Byte Order Mark)
diff --git a/test/stderr/0908 b/test/stderr/0908
new file mode 100644
index 000000000..ad35a1ae6
--- /dev/null
+++ b/test/stderr/0908
@@ -0,0 +1,2 @@
+1999-03-02 09:44:33 Exim configuration error in line 1 of TESTSUITE/confs/0907:
+ found unexpected BOM (Byte Order Mark)
diff --git a/test/stderr/2013 b/test/stderr/2013
index 60b23885f..dc42978c7 100644
--- a/test/stderr/2013
+++ b/test/stderr/2013
@@ -49,7 +49,7 @@ cmd buf flush ddd bytes
SMTP<< 250 OK id=10HmbB-0005vi-00
SMTP(close)>>
LOG: MAIN
- => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+ => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbB-0005vi-00"
LOG: MAIN
Completed
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -70,7 +70,86 @@ cmd buf flush ddd bytes
SMTP(close)>>
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
LOG: MAIN
- => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+ => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+LOG: MAIN
+ Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: queue_run MAIN
+ End queue run: pid=pppp -qqf
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: queue_run MAIN
+ Start queue run: pid=pppp -qqf
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+ SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250-STARTTLS
+ 250 HELP
+ SMTP>> STARTTLS
+cmd buf flush ddd bytes
+ SMTP<< 220 TLS go ahead
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250 HELP
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> RCPT TO:<usera@test.ex>
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP<< 250 OK id=10HmbG-0005vi-00
+LOG: MAIN
+ => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+LOG: MAIN
+ Completed
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> RCPT TO:<userc@test.ex>
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP<< 250 OK id=10HmbH-0005vi-00
+ SMTP(close)>>
+LOG: MAIN
+ => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+LOG: MAIN
+ Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> RCPT TO:<userb@test.ex>
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP<< 250 OK id=10HmbI-0005vi-00
+ SMTP>> QUIT
+cmd buf flush ddd bytes
+ SMTP(close)>>
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+ => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbI-0005vi-00"
LOG: MAIN
Completed
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/2035 b/test/stderr/2035
new file mode 100644
index 000000000..dedf4ad48
--- /dev/null
+++ b/test/stderr/2035
@@ -0,0 +1,74 @@
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: smtp_connection MAIN
+ SMTP connection from CALLER
+Transport port=25 replaced by host-specific port=1225
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+ SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250-STARTTLS
+ 250 HELP
+ SMTP>> STARTTLS
+cmd buf flush ddd bytes
+ SMTP<< 220 TLS go ahead
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250 HELP
+using PIPELINING
+not using DSN
+ SMTP>> MAIL FROM:<usera@ok.example>
+ SMTP>> RCPT TO:<userb@test.ex>
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+LOG: MAIN
+ <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss
+LOG: smtp_connection MAIN
+ SMTP connection from CALLER closed by QUIT
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+>>>>>>>>>>>>>>>> Remote deliveries >>>>>>>>>>>>>>>>
+--------> userb@test.ex <--------
+t1 transport entered
+ userb@test.ex
+hostlist:
+ 127.0.0.1:1225
+already connected to 127.0.0.1 [127.0.0.1] (on fd 0)
+checking status of 127.0.0.1
+127.0.0.1 [127.0.0.1]:1111 retry-status = usable
+delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (userb@test.ex)
+Transport port=25 replaced by host-specific port=1225
+continued connection, proxied TLS
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP>> writing message and terminating "."
+cannot use sendfile for body: spoolfile not wireformat
+writing data block fd=dddd size=sss timeout=300
+ SMTP<< 250 OK id=10HmaY-0005vi-00
+ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL
+ SMTP>> QUIT
+cmd buf flush ddd bytes
+ SMTP(close)>>
+Leaving t1 transport
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+ => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+LOG: MAIN
+ Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+
+******** SERVER ********
diff --git a/test/stderr/2113 b/test/stderr/2113
index 55cfc39dd..35cdabe47 100644
--- a/test/stderr/2113
+++ b/test/stderr/2113
@@ -49,7 +49,7 @@ cmd buf flush ddd bytes
SMTP<< 250 OK id=10HmbB-0005vi-00
SMTP(close)>>
LOG: MAIN
- => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+ => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbB-0005vi-00"
LOG: MAIN
Completed
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -70,7 +70,86 @@ cmd buf flush ddd bytes
SMTP(close)>>
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
LOG: MAIN
- => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+ => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+LOG: MAIN
+ Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: queue_run MAIN
+ End queue run: pid=pppp -qqf
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: queue_run MAIN
+ Start queue run: pid=pppp -qqf
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+ SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250-STARTTLS
+ 250 HELP
+ SMTP>> STARTTLS
+cmd buf flush ddd bytes
+ SMTP<< 220 TLS go ahead
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250 HELP
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> RCPT TO:<usera@test.ex>
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP<< 250 OK id=10HmbG-0005vi-00
+LOG: MAIN
+ => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+LOG: MAIN
+ Completed
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> RCPT TO:<userc@test.ex>
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP<< 250 OK id=10HmbH-0005vi-00
+ SMTP(close)>>
+LOG: MAIN
+ => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+LOG: MAIN
+ Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> RCPT TO:<userb@test.ex>
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP<< 250 OK id=10HmbI-0005vi-00
+ SMTP>> QUIT
+cmd buf flush ddd bytes
+ SMTP(close)>>
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+ => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbI-0005vi-00"
LOG: MAIN
Completed
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/2135 b/test/stderr/2135
new file mode 100644
index 000000000..ac524d2af
--- /dev/null
+++ b/test/stderr/2135
@@ -0,0 +1,74 @@
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: smtp_connection MAIN
+ SMTP connection from CALLER
+Transport port=25 replaced by host-specific port=1225
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+ SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250-STARTTLS
+ 250 HELP
+ SMTP>> STARTTLS
+cmd buf flush ddd bytes
+ SMTP<< 220 TLS go ahead
+ SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+ SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+ 250-SIZE 52428800
+ 250-8BITMIME
+ 250-PIPELINING
+ 250 HELP
+using PIPELINING
+not using DSN
+ SMTP>> MAIL FROM:<usera@ok.example>
+ SMTP>> RCPT TO:<userb@test.ex>
+cmd buf flush ddd bytes
+ SMTP<< 250 OK
+ SMTP<< 250 Accepted
+LOG: MAIN
+ <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss
+LOG: smtp_connection MAIN
+ SMTP connection from CALLER closed by QUIT
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+>>>>>>>>>>>>>>>> Remote deliveries >>>>>>>>>>>>>>>>
+--------> userb@test.ex <--------
+t1 transport entered
+ userb@test.ex
+hostlist:
+ 127.0.0.1:1225
+already connected to 127.0.0.1 [127.0.0.1] (on fd 0)
+checking status of 127.0.0.1
+127.0.0.1 [127.0.0.1]:1111 retry-status = usable
+delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (userb@test.ex)
+Transport port=25 replaced by host-specific port=1225
+continued connection, proxied TLS
+ SMTP>> DATA
+cmd buf flush ddd bytes
+ SMTP<< 354 Enter message, ending with "." on a line by itself
+ SMTP>> writing message and terminating "."
+cannot use sendfile for body: spoolfile not wireformat
+writing data block fd=dddd size=sss timeout=300
+ SMTP<< 250 OK id=10HmaY-0005vi-00
+ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL
+ SMTP>> QUIT
+cmd buf flush ddd bytes
+ SMTP(close)>>
+Leaving t1 transport
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+ => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+LOG: MAIN
+ Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+
+******** SERVER ********
diff --git a/test/stderr/2600 b/test/stderr/2600
index 4e9974733..ffdad152f 100644
--- a/test/stderr/2600
+++ b/test/stderr/2600
@@ -362,9 +362,10 @@ Delivery address list:
userx@myhost.test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@myhost.test.ex
@@ -409,8 +410,9 @@ search_tidyup called
--------> userx@myhost.test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@myhost.test.ex> transport=t1
@@ -439,6 +441,7 @@ lock file created
mailbox TESTSUITE/test-mail/userx is locked
writing to file TESTSUITE/test-mail/userx
writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
writing data block fd=dddd size=sss timeout=0
appendfile yields 0 with errno=dd more_errno=dd
diff --git a/test/stderr/3400 b/test/stderr/3400
index 99e927c6b..78b0e158f 100644
--- a/test/stderr/3400
+++ b/test/stderr/3400
@@ -440,6 +440,13 @@ host in "10.0.0.1"? no (end of list)
host in "10.0.0.4"? no (end of list)
host in "10.0.0.3 : 10.0.0.4"? no (end of list)
host in auth_advertise_hosts? yes (matched "10.0.0.5")
+Evaluating advertise_condition for mylogin athenticator
+Evaluating advertise_condition for PLAIN athenticator
+Evaluating advertise_condition for EXPLAIN athenticator
+Evaluating advertise_condition for EXPANDED athenticator
+Evaluating advertise_condition for EXPANDFAIL athenticator
+Evaluating advertise_condition for DEFER athenticator
+Evaluating advertise_condition for LOGIN athenticator
host in chunking_advertise_hosts? no (end of list)
SMTP>> 250-myhost.test.ex Hello CALLER at testing.testing [10.0.0.5]
250-SIZE 52428800
diff --git a/test/stderr/4520 b/test/stderr/4520
index c2a856bb1..d8d2d7a03 100644
--- a/test/stderr/4520
+++ b/test/stderr/4520
@@ -23,23 +23,28 @@ cmd buf flush ddd bytes
SMTP<< 250 OK
SMTP<< 250 Accepted
SMTP<< 354 Enter message, ending with "." on a line by itself
-PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ sel_bad._domainkey.test.ex.
Raw record: v=DKIM1\;{SP}p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB
v=DKIM1\
p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB
+ Bad v= field
Error while parsing public key record
WARNING: bad dkim key in dns
-PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
content{CR}{LF}
PDKIM [test.ex] Body bytes hashed: 9
-PDKIM [test.ex] Body hash computed: fc06f48221d98ad6106c3845b33a2a41152482ab9e697f736ad26db4853fa657
-PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>
-sender:CALLER_NAME{SP}<CALLER@myhost.test.ex>{CR}{LF}
-message-id:<E10HmbD-0005vi-00@myhost.test.ex>{CR}{LF}
+PDKIM [test.ex] Body sha256 computed: fc06f48221d98ad6106c3845b33a2a41152482ab9e697f736ad26db4853fa657
+PDKIM >> Headers to be signed: >>>>>>>>>>>>
+ From
+PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>
from:nobody@example.com{CR}{LF}
+PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>
+DKIM-Signature:{SP}v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{CR}{LF}{TB}s=sel_bad;{SP}h=From;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=;
PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>
-dkim-signature:v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{SP}s=sel_bad;{SP}h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:{SP}Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:{SP}Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:{SP}In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:{SP}List-Post:List-Owner:List-Archive;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=;
+dkim-signature:v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{SP}s=sel_bad;{SP}h=From;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=;
+PDKIM [test.ex] Header sha256 computed: 241e16230df5723d899cfae9474c6b376a2ab1f81d1094e358f50ffd0e0067b3
SMTP<< 250 OK id=10HmbE-0005vi-00
SMTP>> QUIT
cmd buf flush ddd bytes
diff --git a/test/stderr/5004 b/test/stderr/5004
index ad5c9b331..08b4c9784 100644
--- a/test/stderr/5004
+++ b/test/stderr/5004
@@ -78,9 +78,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -116,8 +117,9 @@ routed by r1 router
transport: <none>
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: TESTSUITE/test-mail
@@ -135,8 +137,9 @@ search_tidyup called
--------> TESTSUITE/test-mail <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to TESTSUITE/test-mail <TESTSUITE/test-mail> transport=t1
@@ -155,6 +158,7 @@ created directory TESTSUITE/test-mail/new
created directory TESTSUITE/test-mail/cur
delivering in maildir format in TESTSUITE/test-mail
writing to tmp/MAILDIR.mail.test.ex
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
renaming temporary file
renamed tmp/MAILDIR.mail.test.ex as new/MAILDIR.mail.test.ex
diff --git a/test/stderr/5005 b/test/stderr/5005
index 8b28b7055..7e6ea98b2 100644
--- a/test/stderr/5005
+++ b/test/stderr/5005
@@ -74,9 +74,10 @@ Delivery address list:
nofile@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: nofile@test.ex
@@ -111,8 +112,9 @@ search_tidyup called
--------> nofile@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to nofile <nofile@test.ex> transport=t1
@@ -149,6 +151,7 @@ delivering in maildir format in TESTSUITE/test-mail/nofile
writing to tmp/MAILDIR.myhost.test.ex
Exim quota = 500 old size = sssss this message = sss (included)
file count quota = 0 count = 0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
added 'ddd 1' to maildirsize file
renaming temporary file
@@ -262,8 +265,9 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -298,8 +302,9 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -338,6 +343,7 @@ delivering in maildir format in TESTSUITE/test-mail/userx
writing to tmp/MAILDIR.myhost.test.ex
Exim quota = 500 old size = sssss this message = sss (included)
file count quota = 0 count = 0
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
added 'ddd 1' to maildirsize file
renaming temporary file
@@ -451,8 +457,9 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -487,8 +494,9 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -545,8 +553,8 @@ Deferred addresses:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR
address match test: subject=userx@test.ex pattern=*
test.ex in "*"? yes (matched "*")
@@ -558,6 +566,7 @@ Writing retry data for T:userx@test.ex
first failed=dddd last try=dddd next try=+86400 expired=0
errno=-22 more_errno=dd mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
dbfn_write: key=T:userx@test.ex
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
end of retry processing
delivery deferred: update_spool=1 header_rewritten=0
@@ -649,8 +658,8 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -661,6 +670,7 @@ dbfn_read: key=R:userx@test.ex:<CALLER@test.ex>
no domain retry record
no address retry record
userx@test.ex: queued for routing
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
routing userx@test.ex
@@ -689,12 +699,13 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY
dbfn_read: key=T:userx@test.ex
retry record exists: age=ttt (max 1w)
time to retry = tttt expired = 0
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -738,8 +749,8 @@ Deferred addresses:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR
address match test: subject=userx@test.ex pattern=*
test.ex in "*"? yes (matched "*")
@@ -751,6 +762,7 @@ Writing retry data for T:userx@test.ex
first failed=dddd last try=dddd next try=+86400 expired=0
errno=-22 more_errno=dd mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
dbfn_write: key=T:userx@test.ex
+EXIM_DBCLOSE(0xAAAAAAAA)
closed hints database and lockfile
end of retry processing
delivery deferred: update_spool=1 header_rewritten=0
diff --git a/test/stderr/5006 b/test/stderr/5006
index dce0d0050..e494f83b5 100644
--- a/test/stderr/5006
+++ b/test/stderr/5006
@@ -74,9 +74,10 @@ Delivery address list:
userx@test.ex
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
no retry data available
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Considering: userx@test.ex
@@ -111,8 +112,9 @@ search_tidyup called
--------> userx@test.ex <--------
locking TESTSUITE/spool/db/retry.lockfile
locked TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
no retry data available
search_tidyup called
changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -147,6 +149,7 @@ maildir_compute_size (timestamp_only): ddddddd
returning maildir size=sss filecount=0
delivering in maildir format in TESTSUITE/test-mail/userx
writing to tmp/MAILDIR.myhost.test.ex
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
added 'ddd 1' to maildirsize file
renaming temporary file
diff --git a/test/stderr/5008 b/test/stderr/5008
index fd4ae87ec..b3bf8f785 100644
--- a/test/stderr/5008
+++ b/test/stderr/5008
@@ -25,6 +25,7 @@ delivering in maildir format in TESTSUITE/test-mail/userx
writing to tmp/MAILDIR.myhost.test.ex
Exim quota = 1048576 old size = sssss this message = sss (included)
file count quota = 0 count = -1
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
renaming temporary file
renamed tmp/MAILDIR.myhost.test.ex as new/MAILDIR.myhost.test.ex
@@ -64,6 +65,7 @@ delivering in maildir format in TESTSUITE/test-mail/userx
writing to tmp/MAILDIR.myhost.test.ex
Exim quota = 1048576 old size = sssss this message = sss (included)
file count quota = 20 count = 4
+cannot use sendfile for body: spoolfile not wireformat
writing data block fd=dddd size=sss timeout=0
renaming temporary file
renamed tmp/MAILDIR.myhost.test.ex as new/MAILDIR.myhost.test.ex
diff --git a/test/stderr/5410 b/test/stderr/5410
index 6a37deb6e..b4db690ab 100644
--- a/test/stderr/5410
+++ b/test/stderr/5410
@@ -119,7 +119,7 @@ cmd buf flush ddd bytes
using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
- SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
SMTP>> RCPT TO:<userx@domain.com>
cmd buf flush ddd bytes
SMTP<< 250 OK
@@ -345,7 +345,7 @@ cmd buf flush ddd bytes
using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
- SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
SMTP>> RCPT TO:<usery@domain.com>
cmd buf flush ddd bytes
SMTP<< 250 OK
@@ -571,7 +571,7 @@ cmd buf flush ddd bytes
using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
- SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
SMTP>> RCPT TO:<usery@domain.com>
cmd buf flush ddd bytes
SMTP<< 250 OK
diff --git a/test/stderr/5420 b/test/stderr/5420
index eaa40bce8..b34440046 100644
--- a/test/stderr/5420
+++ b/test/stderr/5420
@@ -118,7 +118,7 @@ cmd buf flush ddd bytes
using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
- SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
SMTP>> RCPT TO:<userx@domain.com>
cmd buf flush ddd bytes
SMTP<< 250 OK
@@ -344,7 +344,7 @@ cmd buf flush ddd bytes
using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
- SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
SMTP>> RCPT TO:<usery@domain.com>
cmd buf flush ddd bytes
SMTP<< 250 OK
@@ -570,7 +570,7 @@ cmd buf flush ddd bytes
using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
- SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+ SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
SMTP>> RCPT TO:<usery@domain.com>
cmd buf flush ddd bytes
SMTP<< 250 OK
diff --git a/test/stderr/5840 b/test/stderr/5840
index e4cf15c51..51962ce66 100644
--- a/test/stderr/5840
+++ b/test/stderr/5840
@@ -20,10 +20,7 @@
>>> Attempting full verification using callout
>>> callout cache: no domain record found for dane256ee.test.ex
>>> callout cache: no address record found for rcptuser@dane256ee.test.ex
-MUNGED: ::1 will be omitted in what follows
->>> get[host|ipnode]byname[2] looked up these IP addresses:
->>> name=thishost.test.ex address=127.0.0.1
->>> ip4.ip4.ip4.ip4 in hosts_require_dane? yes (end of list)
+>>> ip4.ip4.ip4.ip4 in hosts_require_dane? yes (matched "ip4.ip4.ip4.ip4")
>>> interface=NULL port=1225
>>> Connecting to dane256ee.test.ex [ip4.ip4.ip4.ip4]:1225 ... connected
>>> SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
@@ -53,9 +50,9 @@ MUNGED: ::1 will be omitted in what follows
>>> 250 HELP
>>> ip4.ip4.ip4.ip4 in hosts_avoid_pipelining? no (option unset)
>>> ip4.ip4.ip4.ip4 in hosts_require_auth? no (option unset)
->>> SMTP>> MAIL FROM:<> SIZE=ssss
+>>> SMTP>> MAIL FROM:<>
>>> SMTP>> RCPT TO:<rcptuser@dane256ee.test.ex>
->>> cmd buf flush 62 bytes
+>>> cmd buf flush 52 bytes
>>> SMTP<< 250 OK
>>> SMTP<< 250 Accepted
>>> SMTP>> QUIT
@@ -68,13 +65,16 @@ MUNGED: ::1 will be omitted in what follows
>>> ----------- end verify ------------
>>> accept: condition test succeeded in inline ACL
>>> end of inline ACL: ACCEPT
-LOG: unexpected disconnection while reading SMTP command from [127.0.0.1]
+LOG: unexpected disconnection while reading SMTP command from [127.0.0.1] D=qqs
### TLSA (2 0 1)
### A server with a nonverifying cert and no TLSA
### A server with a verifying cert and no TLSA
### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
******** SERVER ********
### TLSA (3 1 1)
@@ -84,5 +84,8 @@ LOG: unexpected disconnection while reading SMTP command from [127.0.0.1]
### A server with a nonverifying cert and no TLSA
### A server with a verifying cert and no TLSA
### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
diff --git a/test/stdout/0002 b/test/stdout/0002
index fa445b01c..5593f06cc 100644
--- a/test/stdout/0002
+++ b/test/stdout/0002
@@ -393,6 +393,8 @@ newline tab\134backslash ~tilde\177DEL\200\201.
> isip: y 1.2.3.4
> isip4: y 1.2.3.4
> isip6: n 1.2.3.4
+> isip: n ::1.2.3.256
+> isip4: n 1.2.3.256
> isip: n 1:2:3:4
> isip4: n 1:2:3:4
> isip6: n 1:2:3:4
@@ -402,6 +404,7 @@ newline tab\134backslash ~tilde\177DEL\200\201.
> isip: y fe80::a00:20ff:fe86:a061
> isip4: n fe80::a00:20ff:fe86:a061
> isip6: y fe80::a00:20ff:fe86:a061
+> isip: y fe80::1.2.3.4
> isip: n rhubarb
> isip4: n rhubarb
> isip6: n rhubarb
diff --git a/test/stdout/0035 b/test/stdout/0035
index 6855c1d31..60e2c62d2 100644
--- a/test/stdout/0035
+++ b/test/stdout/0035
@@ -144,6 +144,7 @@ End of script
EXIMUSER EXIM_UID EXIM_GID
<notsubmit@y>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
@@ -164,6 +165,7 @@ dddP Received: from [127.0.0.1] (helo=rhu.barb)
EXIMUSER EXIM_UID EXIM_GID
<a@y>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
@@ -187,6 +189,7 @@ dddF From: a@y
EXIMUSER EXIM_UID EXIM_GID
<>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
@@ -208,6 +211,7 @@ dddP Received: from [127.0.0.1] (helo=rhu.barb)
EXIMUSER EXIM_UID EXIM_GID
<notsubmit@y>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
@@ -229,6 +233,7 @@ dddS Sender: sender@some.where
EXIMUSER EXIM_UID EXIM_GID
<a@y>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
@@ -253,6 +258,7 @@ dddF From: a@y
EXIMUSER EXIM_UID EXIM_GID
<a@y>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
@@ -277,6 +283,7 @@ dddF From: a@y
EXIMUSER EXIM_UID EXIM_GID
<a@y>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-interface_address 127.0.0.1.1225
diff --git a/test/stdout/0211 b/test/stdout/0211
index 2d484bda5..708632ded 100644
--- a/test/stdout/0211
+++ b/test/stdout/0211
@@ -43,3 +43,13 @@ EHLO the.local.host.name
550 You are banned
HELO the.local.host.name
End of script
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+554 no smtp service here
+QUIT
+220 bye
+Expected EOF read from client
+Listening on port 1224 ...
+Connection request from [ip4.ip4.ip4.ip4]
+*sleep 2
+End of script
diff --git a/test/stdout/0227 b/test/stdout/0227
index ea8520ef1..9ee7e9f54 100644
--- a/test/stdout/0227
+++ b/test/stdout/0227
@@ -88,6 +88,33 @@
250 Accepted
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello root at me [V4NET.0.0.3]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+550 relay not permitted
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello root at me [V4NET.0.0.3]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+550 relay not permitted
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello root at me [V4NET.0.0.7]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+550 relay not permitted
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
550-Callout verification failed:
550 550 Recipient not liked
@@ -248,10 +275,10 @@ Listening on port 1224 ...
Connection request from [127.0.0.1]
220 Server ready
EHLO myhost.test.ex
-250- wotcher
+250- wotcher sverifier
250-SIZE
250 OK
-MAIL FROM:<> SIZE=ssss
+MAIL FROM:<>
250 OK
RCPT TO:<ok@localhost1>
250 OK
@@ -261,6 +288,54 @@ End of script
Listening on port 1224 ...
Connection request from [127.0.0.1]
220 Server ready
+EHLO myhost.test.ex
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<> SIZE=ssss
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<>
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<ok@localhost1>
+250 OK
+RCPT TO:<myhost.test.ex-dddddddd-testing@remote.domain>
+550 RANDOM NOT OK
+RSET
+250 OK
+MAIL FROM:<ok@localhost1> SIZE=ssss
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+220 Server ready
LHLO myhost.test.ex
250 OK
MAIL FROM:<>
diff --git a/test/stdout/0245 b/test/stdout/0245
index 36332a61b..5d0f2df34 100644
--- a/test/stdout/0245
+++ b/test/stdout/0245
@@ -7,6 +7,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 1
diff --git a/test/stdout/0250 b/test/stdout/0250
index 1d364b4e9..c19185e84 100644
--- a/test/stdout/0250
+++ b/test/stdout/0250
@@ -2,6 +2,7 @@
CALLER UID GID
<CALLER-rewritten@test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
@@ -32,6 +33,7 @@ ddd* X-rewrote-sender: CALLER@test.ex
CALLER UID GID
<CALLER-rewritten@test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
@@ -62,6 +64,7 @@ ddd* X-rewrote-sender: CALLER@test.ex
CALLER UID GID
<CALLER-rewritten@test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0254 b/test/stdout/0254
index 3e044dd6f..69b80a192 100644
--- a/test/stdout/0254
+++ b/test/stdout/0254
@@ -2,6 +2,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
@@ -38,6 +39,7 @@ dddS Resent-Sender: CALLER_NAME <CALLER@myhost.test.ex>
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
@@ -67,6 +69,7 @@ dddS Resent-Sender: CALLER_NAME <CALLER@myhost.test.ex>
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0311 b/test/stdout/0311
index 45190072f..960e8e0b7 100644
--- a/test/stdout/0311
+++ b/test/stdout/0311
@@ -2,6 +2,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
@@ -30,6 +31,7 @@ dddF From: CALLER_NAME <CALLER@myhost.test.ex>
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0338 b/test/stdout/0338
index 52bd7ee37..fbbbc69c5 100644
--- a/test/stdout/0338
+++ b/test/stdout/0338
@@ -6,6 +6,7 @@
CALLER UID GID
<CALLER@test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0376 b/test/stdout/0376
index 8c2b9685c..a0af2cb92 100644
--- a/test/stdout/0376
+++ b/test/stdout/0376
@@ -78,7 +78,7 @@
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
-451 Could not complete sender verify callout
+250 Accepted
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
@@ -86,7 +86,7 @@
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
-451 Could not complete sender verify callout
+250 Accepted
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
diff --git a/test/stdout/0377 b/test/stdout/0377
index 59742e666..de1e5e305 100644
--- a/test/stdout/0377
+++ b/test/stdout/0377
@@ -2,6 +2,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0378 b/test/stdout/0378
index e64fdef16..c60701cbc 100644
--- a/test/stdout/0378
+++ b/test/stdout/0378
@@ -2,6 +2,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0379 b/test/stdout/0379
index 7bfea116f..d26d23523 100644
--- a/test/stdout/0379
+++ b/test/stdout/0379
@@ -2,6 +2,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local
-body_linecount 0
diff --git a/test/stdout/0389 b/test/stdout/0389
index 69b1bfc00..bb5977af7 100644
--- a/test/stdout/0389
+++ b/test/stdout/0389
@@ -8,6 +8,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local-smtp
-aclm 0 22
diff --git a/test/stdout/0488 b/test/stdout/0488
index ff89ff2f7..d6d3b4b18 100644
--- a/test/stdout/0488
+++ b/test/stdout/0488
@@ -8,6 +8,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local-smtp
-body_linecount 0
diff --git a/test/stdout/0490 b/test/stdout/0490
index f9cb83d19..ee77a71e6 100644
--- a/test/stdout/0490
+++ b/test/stdout/0490
@@ -12,6 +12,7 @@
CALLER UID GID
<CALLER@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident CALLER
-received_protocol local-smtp
-body_linecount 2
diff --git a/test/stdout/0514 b/test/stdout/0514
index 83111ea92..5b8677c65 100644
--- a/test/stdout/0514
+++ b/test/stdout/0514
@@ -5,6 +5,7 @@
CALLER UID GID
<"spaced user"@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-ident spaced user
-received_protocol local
-body_linecount 1
diff --git a/test/stdout/0551 b/test/stdout/0551
index 8af281557..9b99fcc54 100644
--- a/test/stdout/0551
+++ b/test/stdout/0551
@@ -4,13 +4,13 @@
1999-03-02 09:44:33 [1235] 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 [1236] 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=qqs
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1 QT=qqs
1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=q.qqqs DT=q.qqqs
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed QT=q.qqqs
exigrep exit code = 0
diff --git a/test/stdout/0578 b/test/stdout/0578
index 40b265041..d3089e7e4 100644
--- a/test/stdout/0578
+++ b/test/stdout/0578
@@ -78,7 +78,7 @@
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
-451 Could not complete sender verify callout
+250 Accepted
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
@@ -86,7 +86,7 @@
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
-451 Could not complete sender verify callout
+250 Accepted
221 myhost.test.ex closing connection
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
diff --git a/test/stdout/0901 b/test/stdout/0901
index 99eb81231..a982ac8b6 100644
--- a/test/stdout/0901
+++ b/test/stdout/0901
@@ -324,14 +324,14 @@ Connecting to 127.0.0.1 port 1225 ... connected
<<< 250-CHUNKING
??? 250 HELP
<<< 250 HELP
->>> mail from:someone9@some.domain
+>>> MAIL FROM:someone9@some.domain
??? 250
<<< 250 OK
->>> rcpt to:CALLER@test.ex
+>>> RCPT TO:CALLER@test.ex
??? 250
<<< 250 Accepted
->>> bdat 1\r\nTbdat 87 last
->>> To: Susan@random.com
+>>> BDAT 1\r\nTBDAT 87 last
+>>> o: Susan@random.com
>>> From: Sam@random.com
>>> Subject: This is a bodyless test message
>>>
diff --git a/test/stdout/0906 b/test/stdout/0906
new file mode 100644
index 000000000..0eb13cc3f
--- /dev/null
+++ b/test/stdout/0906
@@ -0,0 +1,123 @@
+Connecting to 127.0.0.1 port 1224 ... connected
+??? 220
+<<< 220 testhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO test.com
+??? 250-
+<<< 250-testhost.test.ex Hello test.com [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-CHUNKING
+??? 250
+<<< 250 HELP
+>>> MAIL FROM:<sender@dom>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<a@test.ex>
+??? 250
+<<< 250 Accepted
+>>> BDAT 8408 LAST
+>>> Subject: foo
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>>
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> .dot
+>>> tail
+??? 250-
+<<< 250- 8408 byte chunk, total 8408
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+End of script
diff --git a/test/stdout/2090 b/test/stdout/2090
index 7bf70310a..f08abd10b 100644
--- a/test/stdout/2090
+++ b/test/stdout/2090
@@ -89,13 +89,7 @@ Succeeded in starting TLS
<<< 250-CHUNKING
??? 250 HELP
<<< 250 HELP
->>> MAIL FROM:<someone@some.domain>
->>> RCPT TO:<CALLER@test.ex>
->>> BDAT 88 LAST
->>> To: Susan@random.com
->>> From: Sam@random.com
->>> Subject: This is a bodyless test message
->>>
+>>> MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
??? 250
<<< 250 OK
??? 250
diff --git a/test/stdout/2190 b/test/stdout/2190
index 9d386bdf7..e09556e69 100644
--- a/test/stdout/2190
+++ b/test/stdout/2190
@@ -91,13 +91,7 @@ Succeeded in starting TLS
<<< 250-CHUNKING
??? 250 HELP
<<< 250 HELP
->>> MAIL FROM:<someone@some.domain>
->>> RCPT TO:<CALLER@test.ex>
->>> BDAT 88 LAST
->>> To: Susan@random.com
->>> From: Sam@random.com
->>> Subject: This is a bodyless test message
->>>
+>>> MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
??? 250
<<< 250 OK
??? 250
diff --git a/test/stdout/3415 b/test/stdout/3415
index f675c6c74..8e20252e2 100644
--- a/test/stdout/3415
+++ b/test/stdout/3415
@@ -155,6 +155,7 @@ End of script
EXIMUSER EXIM_UID EXIM_GID
<username@myhost.test.ex>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-host_auth au1
@@ -181,6 +182,7 @@ dddS Sender: username@myhost.test.ex
EXIMUSER EXIM_UID EXIM_GID
<>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-host_auth au1
@@ -205,6 +207,7 @@ dddF From: username@myhost.test.ex
EXIMUSER EXIM_UID EXIM_GID
<>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-host_auth au1
@@ -229,6 +232,7 @@ dddF From: username@another.domain
EXIMUSER EXIM_UID EXIM_GID
<>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-host_auth au1
@@ -253,6 +257,7 @@ dddF From: username@auth.id.domain
EXIMUSER EXIM_UID EXIM_GID
<>
ddddddddd 0
+-received_time_usec .uuuuuu
-helo_name rhu.barb
-host_address 127.0.0.1.9999
-host_auth au1
diff --git a/test/stdout/4027 b/test/stdout/4027
new file mode 100644
index 000000000..74837c4ac
--- /dev/null
+++ b/test/stdout/4027
@@ -0,0 +1,66 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaX-0005vi-00
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaY-0005vi-00
+221 myhost.test.ex closing connection
+
+******** SERVER ********
+Listening on port 1225 ...
+Connection request from [ip4.ip4.ip4.ip4]
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me
+R
+250 accepted OK
+QUIT
+250 bye
+End of script
+Listening on port 1225 ...
+Connection request from [ip4.ip4.ip4.ip4]
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me mate
+R
+250 accepted OK
+QUIT
+250 bye
+End of script
diff --git a/test/stdout/4530 b/test/stdout/4530
new file mode 100644
index 000000000..9d64ae5f5
--- /dev/null
+++ b/test/stdout/4530
@@ -0,0 +1,75 @@
+Connecting to 127.0.0.1 port 1224 ... connected
+??? 220
+<<< 220 testhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO xxx
+??? 250-
+<<< 250-testhost.test.ex Hello xxx [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-CHUNKING
+??? 250
+<<< 250 HELP
+>>> MAIL FROM:<CALLER@bloggs.com>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<z@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: simple test
+>>>
+>>> Line 1: This is a simple test.
+>>> Line 2: This is a simple test.
+>>> ..Line 3 has a leading dot
+>>> last line: 4
+>>> .
+??? 250
+<<< 250 OK id=10HmaZ-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 testhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1224 ... connected
+??? 220
+<<< 220 testhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO xxx
+??? 250-
+<<< 250-testhost.test.ex Hello xxx [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-CHUNKING
+??? 250
+<<< 250 HELP
+>>> MAIL FROM:<CALLER@bloggs.com>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<y@test.ex>
+??? 250
+<<< 250 Accepted
+>>> BDAT 129 LAST
+>>> Subject: simple test
+>>>
+>>> Line 1: This is a simple test.
+>>> Line 2: This is a simple test.
+>>> .Line 3 has a leading dot
+>>> last line: 4
+??? 250-
+<<< 250- 129 byte chunk, total 129
+??? 250
+<<< 250 OK id=10HmbA-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 testhost.test.ex closing connection
+End of script
diff --git a/test/stdout/5840 b/test/stdout/5840
index 1d94564ad..32425d2e2 100644
--- a/test/stdout/5840
+++ b/test/stdout/5840
@@ -14,8 +14,11 @@
### A server with a nonverifying cert and no TLSA
### A server with a verifying cert and no TLSA
### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
******** SERVER ********
### TLSA (3 1 1)
@@ -25,5 +28,8 @@
### A server with a nonverifying cert and no TLSA
### A server with a verifying cert and no TLSA
### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
diff --git a/test/t/00-basic.t b/test/t/00-basic.t
index 0612a20af..2fbd2decd 100644
--- a/test/t/00-basic.t
+++ b/test/t/00-basic.t
@@ -45,7 +45,8 @@ subtest 'flavour' => sub {
is flavour('t/samples/debian.sid/etc'), 'debian' => 'got flavour debian from debian sid w/o VERSION_ID';
is flavour('t/samples/fedora24/etc'), 'fedora24' => 'got flavour fedora24 from os-release';
is flavour('t/samples/empty'), undef() => 'got empty flavour (undef)';
- is_deeply [flavours()], ['debian8'] => 'got available flavours';
+ # we do not have flavours anymore (2017-03-18)
+ # is_deeply [flavours()], ['debian8'] => 'got available flavours';
};
done_testing;