aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Neil Shapiro <gshapiro@FreeBSD.org>2024-01-31 23:53:48 +0000
committerGregory Neil Shapiro <gshapiro@FreeBSD.org>2024-02-13 21:47:33 +0000
commitb36ddb27b3b96a3d42dba6b0cc5c103b70911ddb (patch)
treec02491eb7ba66344113818a75daaf65a9fb11103
parent16eebc4e19de99bdc0457f483c97d749a27e7603 (diff)
downloadsrc-b36ddb27b3b96a3d42dba6b0cc5c103b70911ddb.tar.gz
src-b36ddb27b3b96a3d42dba6b0cc5c103b70911ddb.zip
Merge sendmail 8.18.1 from stable/13 to releng/13.3
Merge commit '850ef5ae11d69ea3381bd310f564f025fc8caea3' Merge vendor sendmail 8.18.1 into HEAD (cherry picked from commit d39bd2c1388b520fcba9abed1932acacead60fba) Add new source file for sendmail 8.18.1 (cherry picked from commit 19d4fb85bf17579780e8f0c3cbae8a5e92a6922e) New sendmail 8.18.1 cf file (cherry picked from commit 1b6a5580c1f999fb1ba5f9860cf63a8aefc55b3c) Minor change to update these files so new freebsd*.cf files are generated (cherry picked from commit 2c191ba6b0b5d1b3729a5ac428d51cfc5d5f3d2e) Belatedly update version and date for sendmail 8.18.1 upgrade (cherry picked from commit 31fbc98c949bfca30ab55afef04b4396a61b7e92) Add a note about sendmail 8.18.1's stricter SMTP protocol enforcement (akin to commit 21c1f1deb6a3ac6a60e4516261e5264a28e0b7a6 in main) Update import date for stable/14 Relnotes: Yes Security: CVE-2023-51765 Approved-by: re (cperciva) (cherry picked from commit a64caf2cb2dc3ddd6f325e323c281d1463a80ccf)
-rw-r--r--UPDATING7
-rw-r--r--contrib/sendmail/FREEBSD-upgrade4
-rw-r--r--contrib/sendmail/KNOWNBUGS17
-rw-r--r--contrib/sendmail/PGPKEYS625
-rw-r--r--contrib/sendmail/README26
-rw-r--r--contrib/sendmail/RELEASE_NOTES215
-rw-r--r--contrib/sendmail/cf/README29
-rw-r--r--contrib/sendmail/cf/cf/submit.cf15
-rw-r--r--contrib/sendmail/cf/feature/check_cert_altnames.m42
-rw-r--r--contrib/sendmail/cf/feature/enhdnsbl.m414
-rw-r--r--contrib/sendmail/cf/feature/fips3.m416
-rw-r--r--contrib/sendmail/cf/feature/ldap_routing.m42
-rw-r--r--contrib/sendmail/cf/hack/xconnect.m44
-rw-r--r--contrib/sendmail/cf/m4/proto.m484
-rw-r--r--contrib/sendmail/cf/m4/version.m42
-rw-r--r--contrib/sendmail/cf/sh/makeinfo.sh2
-rwxr-xr-xcontrib/sendmail/contrib/buildvirtuser2
-rw-r--r--contrib/sendmail/doc/op/Makefile6
-rw-r--r--contrib/sendmail/doc/op/op.me271
-rw-r--r--contrib/sendmail/include/libsmdb/smdb.h2
-rw-r--r--contrib/sendmail/include/sendmail/sendmail.h1
-rw-r--r--contrib/sendmail/include/sm/conf.h8
-rw-r--r--contrib/sendmail/include/sm/fdset.h1
-rw-r--r--contrib/sendmail/include/sm/gen.h4
-rw-r--r--contrib/sendmail/include/sm/ixlen.h1
-rw-r--r--contrib/sendmail/include/sm/notify.h7
-rw-r--r--contrib/sendmail/include/sm/os/sm_os_openbsd.h14
-rw-r--r--contrib/sendmail/include/sm/rpool.h2
-rw-r--r--contrib/sendmail/libmilter/README3
-rw-r--r--contrib/sendmail/libmilter/docs/overview.html2
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_getsymval.html17
-rw-r--r--contrib/sendmail/libmilter/docs/smfi_replacebody.html2
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_body.html2
-rw-r--r--contrib/sendmail/libmilter/docs/xxfi_header.html4
-rw-r--r--contrib/sendmail/libmilter/engine.c24
-rw-r--r--contrib/sendmail/libsm/Makefile.m41
-rw-r--r--contrib/sendmail/libsm/README4
-rw-r--r--contrib/sendmail/libsm/b-strl.c2
-rw-r--r--contrib/sendmail/libsm/exc.html2
-rw-r--r--contrib/sendmail/libsm/heap.c2
-rw-r--r--contrib/sendmail/libsm/io.html14
-rw-r--r--contrib/sendmail/libsm/ldap.c110
-rw-r--r--contrib/sendmail/libsm/lowercase.c35
-rw-r--r--contrib/sendmail/libsm/mpeix.c2
-rw-r--r--contrib/sendmail/libsm/notify.c68
-rw-r--r--contrib/sendmail/libsm/notify.h111
-rw-r--r--contrib/sendmail/libsm/rewind.c2
-rw-r--r--contrib/sendmail/libsm/setvbuf.c3
-rw-r--r--contrib/sendmail/libsm/stdio.c2
-rw-r--r--contrib/sendmail/libsm/strcaseeq.c12
-rw-r--r--contrib/sendmail/libsm/t-ixlen.c56
-rw-r--r--contrib/sendmail/libsm/t-notify.c141
-rw-r--r--contrib/sendmail/libsm/t-qic.c16
-rw-r--r--contrib/sendmail/libsm/t-streq.c42
-rwxr-xr-xcontrib/sendmail/libsm/t-streq.sh19
-rw-r--r--contrib/sendmail/libsm/test.c2
-rw-r--r--contrib/sendmail/libsm/util.c10
-rw-r--r--contrib/sendmail/libsm/vfprintf.c16
-rw-r--r--contrib/sendmail/libsm/vfscanf.c2
-rw-r--r--contrib/sendmail/libsmdb/smcdb.c2
-rw-r--r--contrib/sendmail/libsmdb/smdb.c7
-rw-r--r--contrib/sendmail/libsmdb/smdb1.c2
-rw-r--r--contrib/sendmail/libsmdb/smdb2.c2
-rw-r--r--contrib/sendmail/libsmdb/smndbm.c4
-rw-r--r--contrib/sendmail/libsmutil/t-lockfile.c104
-rw-r--r--contrib/sendmail/mail.local/mail.local.c2
-rw-r--r--contrib/sendmail/makemap/makemap.88
-rw-r--r--contrib/sendmail/makemap/makemap.c187
-rw-r--r--contrib/sendmail/smrsh/README2
-rw-r--r--contrib/sendmail/src/Makefile.m42
-rw-r--r--contrib/sendmail/src/README25
-rw-r--r--contrib/sendmail/src/SECURITY14
-rw-r--r--contrib/sendmail/src/TRACEFLAGS16
-rw-r--r--contrib/sendmail/src/alias.c209
-rw-r--r--contrib/sendmail/src/bf.c2
-rw-r--r--contrib/sendmail/src/collect.c258
-rw-r--r--contrib/sendmail/src/conf.c158
-rw-r--r--contrib/sendmail/src/conf.h8
-rw-r--r--contrib/sendmail/src/control.c2
-rw-r--r--contrib/sendmail/src/daemon.c137
-rw-r--r--contrib/sendmail/src/daemon.h2
-rw-r--r--contrib/sendmail/src/deliver.c1603
-rw-r--r--contrib/sendmail/src/domain.c482
-rw-r--r--contrib/sendmail/src/err.c4
-rw-r--r--contrib/sendmail/src/headers.c32
-rw-r--r--contrib/sendmail/src/helpfile6
-rw-r--r--contrib/sendmail/src/macro.c59
-rw-r--r--contrib/sendmail/src/main.c126
-rw-r--r--contrib/sendmail/src/map.c438
-rw-r--r--contrib/sendmail/src/map.h8
-rw-r--r--contrib/sendmail/src/mci.c13
-rw-r--r--contrib/sendmail/src/milter.c27
-rw-r--r--contrib/sendmail/src/mime.c8
-rw-r--r--contrib/sendmail/src/parseaddr.c44
-rw-r--r--contrib/sendmail/src/queue.c214
-rw-r--r--contrib/sendmail/src/ratectrl.c3
-rw-r--r--contrib/sendmail/src/readcf.c238
-rw-r--r--contrib/sendmail/src/recipient.c11
-rw-r--r--contrib/sendmail/src/savemail.c4
-rw-r--r--contrib/sendmail/src/sched.c172
-rw-r--r--contrib/sendmail/src/sendmail.84
-rw-r--r--contrib/sendmail/src/sendmail.h179
-rw-r--r--contrib/sendmail/src/sfsasl.c8
-rw-r--r--contrib/sendmail/src/sm_resolve.c206
-rw-r--r--contrib/sendmail/src/sm_resolve.h28
-rw-r--r--contrib/sendmail/src/srvrsmtp.c465
-rw-r--r--contrib/sendmail/src/stab.c6
-rw-r--r--contrib/sendmail/src/tls.c599
-rw-r--r--contrib/sendmail/src/tls.h91
-rw-r--r--contrib/sendmail/src/tlsh.c37
-rw-r--r--contrib/sendmail/src/udb.c16
-rw-r--r--contrib/sendmail/src/usersmtp.c75
-rw-r--r--contrib/sendmail/src/util.c142
-rw-r--r--contrib/sendmail/src/version.c2
-rw-r--r--contrib/sendmail/test/README9
-rw-r--r--contrib/sendmail/vacation/vacation.125
-rw-r--r--contrib/sendmail/vacation/vacation.c232
-rw-r--r--etc/sendmail/freebsd.mc1
-rw-r--r--etc/sendmail/freebsd.submit.mc1
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc1
-rw-r--r--usr.sbin/sendmail/Makefile2
121 files changed, 6716 insertions, 2169 deletions
diff --git a/UPDATING b/UPDATING
index 21873313b3be..8e7fa2999475 100644
--- a/UPDATING
+++ b/UPDATING
@@ -12,6 +12,13 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
+20240207:
+ sendmail 8.18.1 has been imported and merged. This version enforces
+ stricter RFC compliance by default, especially with respect to line
+ endings. This may cause issues with receiving messages from
+ non-compliant MTAs; please see the first 8.18.1 release note in
+ contrib/sendmail/RELEASE_NOTES for mitigations.
+
20230913:
Improvements to libtacplus(8) mean that tacplus.conf(5) now
follows POSIX shell syntax rules. This may cause TACACS+
diff --git a/contrib/sendmail/FREEBSD-upgrade b/contrib/sendmail/FREEBSD-upgrade
index c8206c4bc351..03969cef2119 100644
--- a/contrib/sendmail/FREEBSD-upgrade
+++ b/contrib/sendmail/FREEBSD-upgrade
@@ -1,6 +1,6 @@
$FreeBSD$
-sendmail 8.17.1
+sendmail 8.18.1
originals can be found at: ftp://ftp.sendmail.org/pub/sendmail/
For the import of sendmail, the following directories were renamed:
@@ -102,4 +102,4 @@ infrastructure in FreeBSD:
usr.sbin/mailwrapper/Makefile
gshapiro@FreeBSD.org
-31-January-2022
+07-February-2024
diff --git a/contrib/sendmail/KNOWNBUGS b/contrib/sendmail/KNOWNBUGS
index b44f931af585..7a75b4975c35 100644
--- a/contrib/sendmail/KNOWNBUGS
+++ b/contrib/sendmail/KNOWNBUGS
@@ -25,7 +25,7 @@ This list is not guaranteed to be complete.
For Linux the default is to use fcntl() for file locking. However,
this does not work with Berkeley DB 5.x and probably later.
Switching to flock(), i.e., compile with -DHASFLOCK fixes this
- (however, the have been problems with flock() on some Linux
+ (however, there have been problems with flock() on some Linux
versions). Alternatively, use CDB or an earlier BDB version.
* Delivery to programs that generate too much output may cause problems
@@ -105,11 +105,6 @@ Kresolve sequence dnsmx canon
DSN does not contain the illegal address, but only the valid
address(es).
-* \231 considered harmful.
-
- Header addresses that have the \231 character (and possibly others
- in the range \201 - \237) behave in odd and usually unexpected ways.
-
* AuthRealm for Cyrus SASL may not work as expected. The man page
and the actual usage for sasl_server_new() seem to differ.
Feedback for the "correct" usage is welcome, a patch to match
@@ -178,11 +173,11 @@ Kresolve sequence dnsmx canon
* Client ignores SIZE parameter.
- When sendmail acts as client and the server specifies a limit
- for the mail size, sendmail will ignore this and try to send the
- mail anyway. The server will usually reject the MAIL command
- which specifies the size of the message and hence this problem
- is not significant.
+ When sendmail acts as client and the server specifies a limit for
+ the mail size, sendmail will ignore this and try to send the mail
+ anyway (unless _FFR_CLIENT_SIZE is used). The server will usually
+ reject the MAIL command which specifies the size of the message
+ and hence this problem is not significant.
* Paths to programs being executed and the mode of program files are
not checked. Essentially, the RunProgramInUnsafeDirPath and
diff --git a/contrib/sendmail/PGPKEYS b/contrib/sendmail/PGPKEYS
index 0d0b0d5a766c..13ec5a6ee56a 100644
--- a/contrib/sendmail/PGPKEYS
+++ b/contrib/sendmail/PGPKEYS
@@ -187,6 +187,625 @@ mk6wxhyuojEHuR7it6IU5BP8vaAGrL1jb1c2EeAe+pdJwpAb1Aq6MU6uWqOGup8t
=xY3m
-----END PGP PUBLIC KEY BLOCK-----
+pub rsa4096/0xC4065A87C71F6844 2024-01-02 [SC]
+ Key fingerprint = 8AB0 63D7 A4C5 939D A9C0 1E38 C406 5A87 C71F 6844
+uid [ultimate] Sendmail Signing Key/2024 <sendmail@Sendmail.ORG>
+sub rsa4096/0x8DBCFBC42AF9E161 2024-01-02 [E]
+ Key fingerprint = 2B52 755B 17D4 44EB EC39 5497 8DBC FBC4 2AF9 E161
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+=2S83
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub rsa4096/0xCFF9F96740ED9550 2023-01-12 [SC]
+ Key fingerprint = 8186 4A03 75F2 7810 64FE 8E4D CFF9 F967 40ED 9550
+uid [ full ] Sendmail Signing Key/2023 <sendmail@Sendmail.ORG>
+sub rsa4096/0x592DCD45F765BAB2 2023-01-12 [E]
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+kYi0
+=c0eH
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub 4096R/81D9210A 2022-01-22
+ Key fingerprint = 6327 DDCB 5E7E 80E4 987E A3B7 FD79 DC0C 81D9 210A
+uid Sendmail Signing Key/2022 <sendmail@Sendmail.ORG>
+sub 4096R/03142938 2022-01-22
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+0Kb4rGd12E5b+czXoxg=
+=LSBA
+-----END PGP PUBLIC KEY BLOCK-----
pub 4096R/4BEE1BEE 2021-01-24
Key fingerprint = F4CE 2263 2102 53D6 A9F9 79B0 4C66 EA8D 4BEE 1BEE
@@ -363,7 +982,6 @@ ra/bqVWSpZTlHZ0xT9seCUSs1urxGw9Z
=3HCo
-----END PGP PUBLIC KEY BLOCK-----
-
pub rsa4096/0xD583210EF51471A7 2020-04-08 [SC]
Key fingerprint = ADFD B709 FE1E A682 E585 5971 D583 210E F514 71A7
uid [ full ] Sendmail Signing Key/2020 <sendmail@Sendmail.ORG>
@@ -557,7 +1175,6 @@ gmOJ78JKVfONBpmdVsw/emTMU5I/C/8m9l0nO0P4Q6diao23krgWk73x7dBoBqDn
=jgHV
-----END PGP PUBLIC KEY BLOCK-----
-
pub rsa4096/0x09E01FA03C0C504E 2019-01-09 [SC]
Key fingerprint = 50A3 0309 8EA2 DD7B CBEE 2ADA 09E0 1FA0 3C0C 504E
uid Sendmail Signing Key/2019 <sendmail@Sendmail.ORG>
@@ -739,7 +1356,6 @@ HcRQfq7rqZkS3NE+iD9D/lUyXVYfH9A=
=jN/3
-----END PGP PUBLIC KEY BLOCK-----
-
pub 4096R/0xF06059FD5DC7CC3F 2018-04-24 [SC]
Key fingerprint = A687 3D24 A4D6 D628 4AE4 2A75 F060 59FD 5DC7 CC3F
uid Sendmail Signing Key/2018 <sendmail@Sendmail.ORG>
@@ -883,7 +1499,6 @@ fvZ+LS/6hJ9C77uOaBqoDPmtpn0WDqc3oDeT81Ans73BZhwhFAjzpHp+XnJQ
=K0Kz
-----END PGP PUBLIC KEY BLOCK-----
-
pub 4096R/6BF726AD 2016-12-31
Key fingerprint = 3C8A 1E8E 7F44 CADE 114F ED46 4BC9 BDA6 6BF7 26AD
uid Sendmail Signing Key/2017 <sendmail@Sendmail.ORG>
@@ -1069,7 +1684,6 @@ FtJxkIHVIx/VvvBqS3HEm8QCRvr+o10/Ue7NljolDV13B7fljxgvLFyJ8T91jWsz
=Lt+h
-----END PGP PUBLIC KEY BLOCK-----
-
pub 2048R/29FB03DE 2016-01-04
fingerprint: 0F5C 96AE C8E6 9E9C 8E54 2E5C 6D4C D194 29FB 03DE
uid Sendmail Signing Key/2016 <sendmail@Sendmail.ORG>
@@ -1269,7 +1883,6 @@ j68I
=MdUt
-----END PGP PUBLIC KEY BLOCK-----
-
pub 2048R/0xAAF5B5DE05BDCC53 2015-01-02
fingerprint: 30BC A747 05FA 4154 5573 1D7B AAF5 B5DE 05BD CC53
uid Sendmail Signing Key/2015 <sendmail@Sendmail.ORG>
diff --git a/contrib/sendmail/README b/contrib/sendmail/README
index 50cbce25e169..468d29fcaffb 100644
--- a/contrib/sendmail/README
+++ b/contrib/sendmail/README
@@ -4,11 +4,12 @@
This directory has the latest sendmail(TM) software from Proofpoint, Inc.
Report any bugs to sendmail-bugs-YYYY@support.sendmail.org
-where YYYY is the current year, e.g., 2005.
+where YYYY is the current year, e.g., 2023.
-There is a web site at http://www.sendmail.org/ -- see that site for
+There is a web site at https://www.sendmail.org/ -- see that site for
the latest updates.
+
+--------------+
| INTRODUCTION |
+--------------+
@@ -40,6 +41,7 @@ the latest updates.
Sendmail is a trademark of Proofpoint, Inc.
US Patent Numbers 6865671, 6986037.
+
+-----------------------+
| DIRECTORY PERMISSIONS |
+-----------------------+
@@ -197,14 +199,6 @@ There are other files you should read. Rooted in this directory are:
This sets a word in a smaller pointsize.
- - with new groff versions (1.18 seems affected)
-
- GROFF_NO_SGR=1
-
- needs to be set, e.g., in doc/op/Makefile:
-
- ROFF_CMD= GROFF_NO_SGR=1 groff
-
+--------------+
| RELATED RFCS |
@@ -248,6 +242,13 @@ Important RFCs for electronic mail are:
RFC2822 Internet Message Format
RFC2852 Deliver By SMTP Service Extension
RFC2920 SMTP Service Extension for Command Pipelining
+ RFC5321 Simple Mail Transfer Protocol
+ RFC5322 Internet Message Format
+ RFC6530 Overview and Framework for Internationalized Email
+ RFC6531 SMTP Extension for Internationalized Email
+ RFC6532 Internationalized Email Headers
+ RFC6533 Internationalized Delivery Status and Disposition Notifications
+ RFC8461 SMTP MTA Strict Transport Security (MTA-STS)
Other standards that may be of interest (but which are less directly
relevant to sendmail) are:
@@ -325,6 +326,10 @@ DB 2.X and 3.X. If you are upgrading from one of those versions, you must
recreate your database file(s). Do this by rebuilding all maps with
makemap and rebuilding the alias file with newaliases.
+File locking using fcntl() does not interoperate with Berkeley DB
+5.x (and probably later). Use CDB, flock() (-DHASFLOCK), or an
+earlier Berkeley DB version.
+
+--------------------+
| HOST NAME SERVICES |
@@ -391,6 +396,7 @@ CommuniGate Pro
in .mc file if you have compiled sendmail with Cyrus SASL
and you communicate with CommuniGate Pro servers.
+
+---------------------+
| DIRECTORY STRUCTURE |
+---------------------+
diff --git a/contrib/sendmail/RELEASE_NOTES b/contrib/sendmail/RELEASE_NOTES
index d8186f05e0f4..85f8368e28ce 100644
--- a/contrib/sendmail/RELEASE_NOTES
+++ b/contrib/sendmail/RELEASE_NOTES
@@ -5,6 +5,187 @@ This listing shows the version of the sendmail binary, the version
of the sendmail configuration files, the date of release, and a
summary of the changes in that release.
+
+8.18.1/8.18.1 2024/01/31
+ sendmail is now stricter in following the RFCs and rejects
+ some invalid input with respect to line endings
+ and pipelining:
+ - Prevent transaction stuffing by ensuring SMTP clients
+ wait for the HELO/EHLO and DATA response before sending
+ further SMTP commands. This can be disabled using
+ the new srv_features option 'F'. Issue reported by
+ Yepeng Pan and Christian Rossow from CISPA Helmholtz
+ Center for Information Security.
+ - Accept only CRLF . CRLF as end of an SMTP message
+ as required by the RFCs, which can disabled by the
+ new srv_features option 'O'.
+ - Do not accept a CR or LF except in the combination
+ CRLF (as required by the RFCs). These checks can
+ be disabled by the new srv_features options
+ 'U' and 'G', respectively. In this case it is
+ suggested to use 'u2' and 'g2' instead so the server
+ replaces offending bare CR or bare LF with a space.
+ It is recommended to only turn these protections off
+ for trusted networks due to the potential for abuse.
+ Full DANE support is available if OpenSSL versions 1.1.1 or 3.x
+ are used, i.e., TLSA RR 2-x-y and 3-x-y are supported
+ as required by RFC 7672.
+ OpenSSL version 3.0.x is supported. Note: OpenSSL 3 loads by
+ default an openssl.cnf file from a location specified
+ in the library which may cause unwanted behaviour
+ in sendmail. Hence sendmail sets the environment
+ variable OPENSSL_CONF to /etc/mail/sendmail.ossl
+ to override the default. The file name can be
+ changed by defining confOPENSSL_CNF in the mc file;
+ using an empty value prevents setting OPENSSL_CONF.
+ Note: referring to a file which does not exist does
+ not cause an an error.
+ Two new values have been added for {verify}:
+ "DANE_TEMP": DANE verification failed temporarily.
+ "DANE_NOTLS": DANE was required but STARTTLS was not
+ offered by the server.
+ The default rules return a temporary error for these
+ cases, so delivery is not attempted.
+ If the TLS setup code in the client fails and DANE requirements
+ exist then {verify} will be set to "DANE_TEMP" thus
+ preventing delivery by default.
+ DANE related logging has been slightly changed for clarification:
+ "DANE configured in DNS but no STARTTLS available"
+ changed to
+ "DANE configured in DNS but STARTTLS not offered"
+ When the compile time option USE_EAI is enabled, vacation could
+ fail to respond when it should (the code change in
+ 8.17.2 was incomplete). Problem reported by Alex
+ Hautequest.
+ If SMTPUTF8 BODY=7BIT are used as parameters for the MAIL command
+ the parsing of UTF8 addresses could fail (USE_EAI).
+ If a reply to a previous RCPT was received while sending
+ another RCPT in pipelining mode then parts of the
+ reply could have been assigned to the wrong RCPT.
+ New DontBlameSendmail option CertOwner to relax requirement
+ for certificate public and private key ownership.
+ Based on suggestion from Marius Strobl of the
+ FreeBSD project.
+ clt_features was not checked for connections via Unix domain
+ sockets.
+ CONFIG: FEATURE(`enhdnsbl') did not handle multiple replies
+ from DNS lookups thus potentially causing random
+ "false negatives".
+ Note: the fix creates an incompatibility:
+ the arguments must not have a trailing dot anymore
+ because the -a. option has been removed (as it only
+ applies to the entire result, not individual values).
+ CONFIG: New FEATURE(`fips3') for basic FIPS support in OpenSSL 3.
+ VACATION: Add support for Return-Path header to set sender
+ to match OpenBSD and NetBSD functionality.
+ VACATION: Honor RFC3834 and avoid an auto-reply if
+ 'Auto-Submitted: no' is found in the headers to
+ match OpenBSD and NetBSD functionality.
+ VACATION: Avoid an auto-reply if a 'List-Id:' is found in
+ the headers to match OpenBSD functionality.
+ VACATION: Add support for $SUBJECT in .vacation.msg which
+ is replaced with the first line of the subject of the
+ original message to match OpenBSD and NetBSD
+ functionality.
+ Portability:
+ Add support for Darwin 23.
+ New Files:
+ cf/feature/fips3.m4
+ devtools/OS/Darwin.23.x
+
+8.17.2/8.17.2 2023/06/03
+ Make sure DANE checks (if enabled) are performed even if
+ CACertPath or CACertFile are not set or unusable.
+ Note: if the code to set up TLS in the client fails, then
+ {verify} will be set to TEMP but DANE requirements
+ will be ignored, i.e., by default mail will be sent
+ without STARTTLS. This can be changed via a
+ LOCAL_TLS_SERVER ruleset.
+ Pass server name to clt_features ruleset instead of client
+ name to account for limitations in macro availability
+ described below in CONFIG section. This may break
+ custom clt_features rulesets which expect to receive
+ the client name as input.
+ Fix a regression introduced in 8.17.1: aliases file which
+ contain continuation lines caused parsing errors.
+ Add an FFR (for future release) compile time option _FFR_LOG_STAGE
+ to log the protocol stage as stage= for some errors during
+ delivery attempts to make troubleshooting simpler. This
+ new logging may be enabled in a future release.
+ When EAI is enabled, milters also got the arguments of MAIL/RCPT
+ commands in argv[0] for xxfi_envfrom()/xxfi_envrcpt()
+ callbacks instead of just the mail address.
+ Problem reported by Dilyan Palauzo.
+ When EAI is enabled, mailq prints UTF-8 addresses as such
+ if SMTPUTF8 was used.
+ When EAI is enabled, the $h macro is now in the correct format.
+ Previously this could cause wrong values for relay=
+ in log entries and the mailer argument vector.
+ When the compile time option USE_EAI is enabled, vacation could
+ fail to respond when it should. Problem reported by
+ Alex Hautequest.
+ When EAI was enabled, header truncation might not have been
+ logged even when it happened. Problem reported by
+ Werner Wiethege.
+ Handle a possible change in an upcoming release of Cyrus-SASL
+ (2.1.28) by changing the definition of an internal flag.
+ Patch from Dilyan Palauzo.
+ Avoid an assertion failure when an smtps connection is made
+ to the server and a milter is unavailable.
+ Problem reported by Dilyan Palauzo.
+ Fixed some spelling errors in documentation and comments,
+ based on a codespell report by Jens Schleusener
+ of fossies.org.
+ The result of try_tls is now logged using status= instead
+ of reject=.
+ If tls_rcpt rejected the delivery of a recipient then a bogus
+ dsn= entry might have been logged under some circumstances.
+ If a server replied with 421 to a RCPT command then a bogus reply=
+ might have been logged.
+ When quoting the value for ${currHeader} avoid causing a syntax
+ error (Unbalanced '"') when truncating a header value
+ which is too long. Problem reported by Werner Wiethege.
+ Reduce the performance impact of a change introduced in
+ 8.12.9: the default for MaxMimeHeaderLength was
+ set to 2048/1024. Problem reported by Tabata
+ Shintaro of Internet Initiative Japan Inc.
+ CONFIG: The default clt_features ruleset tried to access
+ ${server_name} and ${server_addr} which are not set
+ when the ruleset is invoked. Only the server name
+ is available which is passed as an argument.
+ CONFIG: Properly quote host variable to prevent cf build
+ breakage when a hostname contains 'dnl'. Problem
+ reported by Maxim Shalomikhin of Kaspersky.
+ DEVTOOLS: Add configure.sh support for BSD's mandoc as an
+ alternative man page formatting tool.
+ DOC: Document that USAGE is a possible value for {verify}.
+ LIBMILTER: The macros for the EOH and EOM callbacks are
+ sent in reverse order which means accessing macros
+ in the EOM callback got the macro for the EOH
+ callback. Store those macros in the expected order
+ in libmilter. Note: this does not affect sendmail
+ because the macros for both callbacks are the same
+ because the message is sent to libmilter after it
+ is completely read by sendmail. Fix and problem
+ report from David Buergin.
+ Portability:
+ Make use of IN_LOOPBACK, if defined, to determine if
+ using a loopback address. Patch from Mike Karels of
+ FreeBSD.
+ On Linux use gethostbyname2(3) if glibc 2.19 or newer
+ is used to avoid potential problems with IPv6 lookups.
+ Patch from Werner Wiethege.
+ Add support for Darwin 21 and Darwin 22.
+ Solaris 12 has been renamed to Solaris 11.4, hence
+ adapt a condition for sigwait(2) taking one argument.
+ Patch from John Beck.
+ New Files:
+ devtools/M4/UNIX/sharedlib.m4
+ devtools/OS/Darwin.21.x
+ devtools/OS/Darwin.22.x
+ sendmail/sched.c
+ libsm/notify.h
+
8.17.1/8.17.1 2021/08/17
Deprecation notice: due to compatibility problems with some
third party code, we plan to finally switch from K&R
@@ -37,6 +218,9 @@ summary of the changes in that release.
in the SMTP client per server. Currently only two
flags are available: D/M to disable DANE/MTA-STS,
respectively.
+ New compile time option NO_EOH_FIELDS to disable the special
+ meaning of the headers Message: and Text: to denote the
+ end of the message header.
Avoid leaking session macros for an envelope between
delivery attempts to different servers. This problem
could have affected check_compat.
@@ -76,10 +260,17 @@ summary of the changes in that release.
properly, as the persistent macro applies to all
RCPTs and hence implicitly to all destinations (servers).
The option TLSFallbacktoClear should be used if needed.
+ CONTRIB: AuthRealm.p0 has been modified for 8.16.1 by Anne Bennett.
+ CONTRIB: Added cidrexpand -O option for suppressing duplicates from
+ a CIDR expansion that overlaps a later entry and -S option
+ for skipping comments exactly like makemap does.
MAIL.LOCAL: Enhance some error messages to simplify
troubleshooting.
Portability:
Add support for Darwin 19 & 20.
+ Use proper FreeBSD version define to allow for cross
+ compiling. Fix from Brooks Davis of the FreeBSD
+ project.
NOTE: File locking using fcntl() does not interoperate
with Berkeley DB 5.x (and probably later). Use
CDB, flock() (-DHASFLOCK), or an earlier Berkeley
@@ -104,22 +295,6 @@ summary of the changes in that release.
libsmutil/t-lockfile-0.sh
libsmutil/t-maplock-0.sh
-8.16.2/8.16.2 202X/XX/XX
- New compile time option NO_EOH_FIELDS to disable the special
- meaning of the headers Message: and Text: to denote the
- end of the message header.
- CONTRIB: AuthRealm.p0 has been modified for 8.16.1 by Anne Bennett.
- CONTRIB: Added cidrexpand -O option for suppressing duplicates from
- a CIDR expansion that overlaps a later entry and -S option
- for skipping comments exactly like makemap does.
- Portability:
- Add support for Darwin 19 (Mac OS X 10.15).
- Use proper FreeBSD version define to allow for cross
- compiling. Fix from Brooks Davis of the FreeBSD
- project.
- New Files:
- devtools/OS/Darwin.19.x
-
8.16.1/8.16.1 2020/07/05
SECURITY: If sendmail tried to reuse an SMTP session which had
already been closed by the server, then the connection
@@ -5392,7 +5567,7 @@ summary of the changes in that release.
characters (in LMTP mode), mail.local split the incoming
line up into 2046-character output lines (excluding the
newline). If an input line was 2047 characters long
- (excluding CR-LF) and the last character was a '.',
+ (excluding CRLF) and the last character was a '.',
mail.local saw it as the end of input, transferred it to the
user mailbox and tried to write an `ok' back to sendmail.
If the message was much longer, both sendmail and
@@ -7675,7 +7850,7 @@ summary of the changes in that release.
files that are group writable are considered "unsafe" -- that
is, programs and files referenced from such files are not
valid recipients.
- Delete bogosity test for FallBackMX host; this prevented it to be a
+ Delete bogosity test for FallBackMXhost; this prevented it to be a
name that was not in DNS or was a domain-literal. Problem
noted by Tom May.
Change the introduction to error messages to more clearly delineate
@@ -8414,7 +8589,7 @@ summary of the changes in that release.
should show the pathname rather than hex bytes.
Restore ``-ba'' mode -- this reads a file from stdin and parses
the header for envelope sender information and uses
- CR-LF as message terminators. It was thought to be
+ CRLF as message terminators. It was thought to be
obsolete (used only for Arpanet NCP protocols), but it
turns out that the UK ``Grey Book'' protocols require
that functionality.
@@ -10742,7 +10917,7 @@ summary of the changes in that release.
as well as the effective. The program test/t_setreuid.c
will test to see if your implementation of setreuid(2)
is appropriately functional.
- The FallBackMX (option V) handling failed to properly identify
+ The FallBackMXhost (option V) handling failed to properly identify
fallback to yourself -- most of the code was there,
but it wasn't being enabled. Problem noted by Murray
Kucherawy of the University of Waterloo.
diff --git a/contrib/sendmail/cf/README b/contrib/sendmail/cf/README
index cfabe5eefe45..6191337ea625 100644
--- a/contrib/sendmail/cf/README
+++ b/contrib/sendmail/cf/README
@@ -1301,6 +1301,8 @@ dnsbl Turns on rejection, discarding, or quarantining of hosts
definition from `host'. Set the DNSBL_MAP_OPT mc option
to add additional options to the map specification used.
+ Note: currently only IPv4 addresses are checked.
+
Some DNS based rejection lists cause failures if asked
for AAAA records. If your sendmail version is compiled
with IPv6 support (NETINET6) and you experience this
@@ -1326,10 +1328,10 @@ enhdnsbl Enhanced version of dnsbl (see above). Further arguments
compared with the supplied argument(s), and only if a match
occurs an error is generated. For example,
- FEATURE(`enhdnsbl', `dnsbl.example.com', `', `t', `127.0.0.2.')
+ FEATURE(`enhdnsbl', `dnsbl.example.com', `', `t', `127.0.0.2')
will reject the e-mail if the lookup returns the value
- ``127.0.0.2.'', or generate a 451 response if the lookup
+ ``127.0.0.2'', or generate a 451 response if the lookup
temporarily failed. The arguments can contain metasymbols
as they are allowed in the LHS of rules. As the example
shows, the default values are also used if an empty argument,
@@ -1616,6 +1618,12 @@ sts Experimental support for Strict Transport Security
for the default value).
For more information see doc/op/op.me.
+fips3 Basic support for FIPS in OpenSSL 3 by setting
+ the environment variables OPENSSL_CONF and
+ OPENSSL_MODULES to the first and second argument,
+ respectively. For details, see the file and
+ the OpenSSL documentation.
+
+-------+
| HACKS |
+-------+
@@ -1688,6 +1696,7 @@ The macro LOCAL_UUCP can be used to add rules into the generated
cf file at the place where MAILER(`uucp') inserts its rules. This
should only be used if really necessary.
+
+--------------------+
| USING UUCP MAILERS |
+--------------------+
@@ -3183,8 +3192,8 @@ VERIFY:bits verification must have succeeded and ${cipher_bits} must
ENCR:bits ${cipher_bits} must be greater than or equal bits.
The RHS can optionally be prefixed by TEMP+ or PERM+ to select a temporary
-or permanent error. The default is a temporary error code (403 4.7.0)
-unless the macro TLS_PERM_ERR is set during generation of the .cf file.
+or permanent error. The default is a temporary error code unless
+the macro TLS_PERM_ERR is set during generation of the .cf file.
If a certain level of encryption is required, then it might also be
possible that this level is provided by the security layer from a SASL
@@ -3256,9 +3265,10 @@ default TLS options are not modified.
About 2): the rulesets try_tls, srv_features, and clt_features can
be used together with the access map. Entries for the access map
must be tagged with Try_TLS, Srv_Features, Clt_Features and refer
-to the hostname or IP address of the connecting system. A default
-case can be specified by using just the tag. For example, the
-following entries in the access map:
+to the hostname or IP address of the connecting system (the latter
+is not available for clt_features). A default case can be specified
+by using just the tag. For example, the following entries in the
+access map:
Try_TLS:broken.server NO
Srv_Features:my.domain v
@@ -3376,6 +3386,7 @@ or FEATURE(`authinfo') must be used which provides a separate map.
Notice: It is not checked whether the map is actually
group/world-unreadable, this is left to the user.
+
+--------------------------------+
| ADDING NEW MAILERS OR RULESETS |
+--------------------------------+
@@ -3461,6 +3472,7 @@ groups can be defined using the command:
For details about queue groups, please see doc/op/op.{me,ps,txt}.
+
+-------------------------------+
| NON-SMTP BASED CONFIGURATIONS |
+-------------------------------+
@@ -4406,6 +4418,9 @@ confCERT_FINGERPRINT_ALGORITHM CertFingerprintAlgorithm
confSSL_ENGINE SSLEngine [undefined] Name of SSLEngine.
confSSL_ENGINE_PATH SSLEnginePath [undefined] Path to dynamic library
for SSLEngine.
+confOPENSSL_CNF [/etc/mail/sendmail.ossl] Set the
+ environment variable OPENSSL_CONF.
+ An empty value disables setting it.
confNICE_QUEUE_RUN NiceQueueRun [undefined] If set, the priority of
queue runners is set the given value
(nice(3)).
diff --git a/contrib/sendmail/cf/cf/submit.cf b/contrib/sendmail/cf/cf/submit.cf
index 1faab23e9e39..92e8cb497c22 100644
--- a/contrib/sendmail/cf/cf/submit.cf
+++ b/contrib/sendmail/cf/cf/submit.cf
@@ -16,8 +16,8 @@
#####
##### SENDMAIL CONFIGURATION FILE
#####
-##### built by ca@lab.smi.sendmail.com on Sun Aug 15 23:05:00 PDT 2021
-##### in /var/tmp/ca/sm8.head/sendmail/OpenSource/sendmail-8.17.1/cf/cf
+##### built by xbuild@xenon14.us.proofpoint.com on Tue Jan 30 22:39:25 PST 2024
+##### in /export/jenkins/jenkins3/workspace/pps-sendmail/OpenSource/sendmail-8.18.1/cf/cf
##### using ../ as configuration include directory
#####
######################################################################
@@ -111,11 +111,13 @@ Kdequote dequote
DnMAILER-DAEMON
+
D{MTAHost}[127.0.0.1]
+EOPENSSL_CONF=/etc/mail/sendmail.ossl
# Configuration version number
-DZ8.17.1/Submit
+DZ8.18.1/Submit
###############
@@ -1248,6 +1250,7 @@ Stry_tls
+
######################################################################
### tls_rcpt: is connection with server "good" enough?
### (done in client, per recipient)
@@ -1256,7 +1259,10 @@ Stry_tls
### $1: recipient
######################################################################
Stls_rcpt
-
+R$* $: $1 $| $&{verify}
+R$* $| DANE_NOTLS $#error $@ 4.7.0 $: "454 DANE: missing STARTTLS."
+R$* $| DANE_TEMP $#error $@ 4.7.0 $: "454 DANE check failed temporarily."
+R$* $| DANE_FAIL $#error $@ 4.7.0 $: "454 DANE check failed."
######################################################################
### tls_client: is connection with client "good" enough?
@@ -1288,7 +1294,6 @@ R$* $@ $>"TLS_connection" $1
######################################################################
STLS_connection
RSOFTWARE $#error $@ 4.7.0 $: "454 TLS handshake failed."
-RDANE_FAIL $#error $@ 4.7.0 $: "454 DANE check failed."
RPROTOCOL $#error $@ 4.7.0 $: "454 STARTTLS failed."
RCONFIG $#error $@ 4.7.0 $: "454 STARTTLS temporarily not possible."
diff --git a/contrib/sendmail/cf/feature/check_cert_altnames.m4 b/contrib/sendmail/cf/feature/check_cert_altnames.m4
index baa10697fd95..428ef28c8587 100644
--- a/contrib/sendmail/cf/feature/check_cert_altnames.m4
+++ b/contrib/sendmail/cf/feature/check_cert_altnames.m4
@@ -13,5 +13,5 @@ divert(0)dnl
VERSIONID(`$Id: check_cert_altnames.m4 1.0 2019-01-01 01:01:01 ca Exp $')
divert(-1)
define(`_FFR_TLS_ALTNAMES', `1')
-divert(6)dnl
+LOCAL_CONFIG
O SetCertAltnames=true
diff --git a/contrib/sendmail/cf/feature/enhdnsbl.m4 b/contrib/sendmail/cf/feature/enhdnsbl.m4
index a1f5f62a004b..72ef7c98bd56 100644
--- a/contrib/sendmail/cf/feature/enhdnsbl.m4
+++ b/contrib/sendmail/cf/feature/enhdnsbl.m4
@@ -17,7 +17,7 @@ VERSIONID(`$Id: enhdnsbl.m4,v 1.13 2013-11-22 20:51:11 ca Exp $')
LOCAL_CONFIG
define(`_EDNSBL_R_',`')dnl
# map for enhanced DNS based blocklist lookups
-Kednsbl dns -R A -a. -T<TMP> -r`'ifdef(`EDNSBL_TO',`EDNSBL_TO',`5')
+Kednsbl dns -R A -T<TMP> -z -Z32 -r`'ifdef(`EDNSBL_TO',`EDNSBL_TO',`5')
')
divert(-1)
define(`_EDNSBL_SRV_', `_ARG_')dnl
@@ -39,15 +39,15 @@ R<?>OK $: OKSOFAR
ifelse(len(X`'_ARG3_),`1',
`R<?>$+<TMP> $: TMPOK',
`R<?>$+<TMP> $#error $@ 4.4.3 $: _EDNSBL_MSG_TMP_')
-R<?>_EDNSBL_MATCH_ _EDNSBL_ACTION_ $: _EDNSBL_MSG_
+R<?>$* patsubst(_EDNSBL_MATCH_, `\.$', `') $* _EDNSBL_ACTION_ $: _EDNSBL_MSG_
ifelse(len(X`'_ARG5_),`1',`dnl',
-`R<?>_ARG5_ _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
+`R<?>$* patsubst(_ARG5_, `\.$', `') $* _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
ifelse(len(X`'_ARG6_),`1',`dnl',
-`R<?>_ARG6_ _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
+`R<?>$* patsubst(_ARG6_, `\.$', `') $* _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
ifelse(len(X`'_ARG7_),`1',`dnl',
-`R<?>_ARG7_ _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
+`R<?>$* patsubst(_ARG7_, `\.$', `') $* _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
ifelse(len(X`'_ARG8_),`1',`dnl',
-`R<?>_ARG8_ _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
+`R<?>$* patsubst(_ARG8_, `\.$', `') $* _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
ifelse(len(X`'_ARG9_),`1',`dnl',
-`R<?>_ARG9_ _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
+`R<?>$* patsubst(_ARG9_, `\.$', `') $* _EDNSBL_ACTION_ $: _EDNSBL_MSG_')
divert(-1)
diff --git a/contrib/sendmail/cf/feature/fips3.m4 b/contrib/sendmail/cf/feature/fips3.m4
new file mode 100644
index 000000000000..0d17642a111b
--- /dev/null
+++ b/contrib/sendmail/cf/feature/fips3.m4
@@ -0,0 +1,16 @@
+divert(-1)
+#
+# Copyright (c) 2023 Proofpoint, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+divert(0)
+define(`confOPENSSL_CNF', dnl
+ifelse(defn(`_ARG_'), `', `/etc/mail/fips.ossl', `_ARG_'))dnl
+ifelse(len(X`'_ARG2_),`1',`',`LOCAL_CONFIG
+EOPENSSL_MODULES=_ARG2_')
diff --git a/contrib/sendmail/cf/feature/ldap_routing.m4 b/contrib/sendmail/cf/feature/ldap_routing.m4
index 0d8ccb9730c2..f8717877ad58 100644
--- a/contrib/sendmail/cf/feature/ldap_routing.m4
+++ b/contrib/sendmail/cf/feature/ldap_routing.m4
@@ -18,7 +18,7 @@ ifelse(len(X`'_ARG1_), `1', `define(`_LDAP_ROUTING_WARN_', `yes')')
ifelse(len(X`'_ARG2_), `1', `define(`_LDAP_ROUTING_WARN_', `yes')')
ifelse(len(X`'_ARG5_), `1', `', `define(`_LDAP_ROUTE_NODOMAIN_', `yes')')
-# Check for third argument to indicate how to deal with non-existant
+# Check for third argument to indicate how to deal with non-existent
# LDAP records
ifelse(len(X`'_ARG3_), `1', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')',
_ARG3_, `passthru', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')',
diff --git a/contrib/sendmail/cf/hack/xconnect.m4 b/contrib/sendmail/cf/hack/xconnect.m4
index 72fba31d7bdb..b6b46baa7af1 100644
--- a/contrib/sendmail/cf/hack/xconnect.m4
+++ b/contrib/sendmail/cf/hack/xconnect.m4
@@ -20,6 +20,8 @@ LOCAL_RULESETS
#
# x_connect ruleset for looking up XConnect: tag in access DB to enable
# XCONNECT support in MTA
+# if the RHS of the map entry is haproxy1,
+# then HAproxy protocol version 1 is used
#
Sx_connect
dnl workspace: {client_name} $| {client_addr}
@@ -32,6 +34,6 @@ R<?> <$+> $: $>A < $1 > <?> <! XConnect> <> no: another lookup
dnl workspace: <result-of-lookup> (<>|<{client_addr}>)
R<?> <$*> $# no found nothing
dnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
-R<$+> <$*> $@ yes found in access DB',
+R<$+> <$*> $@ $1 found in access DB',
`errprint(`*** ERROR: HACK(xconnect) requires FEATURE(access_db)
')')
diff --git a/contrib/sendmail/cf/m4/proto.m4 b/contrib/sendmail/cf/m4/proto.m4
index cfd71b3f9cad..ff7eb0bedc2a 100644
--- a/contrib/sendmail/cf/m4/proto.m4
+++ b/contrib/sendmail/cf/m4/proto.m4
@@ -247,7 +247,9 @@ DM`'MASQUERADE_NAME')
# my name for error messages
ifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
+ifdef(`confOPENSSL_CNF',, `define(`confOPENSSL_CNF', `/etc/mail/sendmail.ossl')')
undivert(6)dnl LOCAL_CONFIG
+ifelse(defn(`confOPENSSL_CNF'), `', `', `EOPENSSL_CONF=confOPENSSL_CNF')
include(_CF_DIR_`m4/version.m4')
###############
@@ -938,7 +940,7 @@ ifdef(`_CANONIFY_HOSTS_', `dnl
dnl this should only apply to unqualified hostnames
dnl but if a valid character inside an unqualified hostname is an OperatorChar
dnl then $- does not work.
-# lookup unqualified hostnames
+# look up unqualified hostnames
R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
dnl _NO_CANONIFY_ is not set: canonify unless:
dnl {daemon_flags} contains CC (do not canonify)
@@ -1234,7 +1236,7 @@ R$+ . USENET $#usenet $@ usenet $: $1',
ifdef(`_LOCAL_RULES_',
`# figure out what should stay in our local mail system
-undivert(1)', `dnl')
+undivert(1)dnl LOCAL_NET_CONFIG', `dnl')
# pass names that still have a host to a smarthost (if defined)
R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name
@@ -1436,11 +1438,12 @@ dnl if generics should be applied add a @ as mark
R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark
dnl workspace: either user<@domain> or <user@domain> user <@domain> @
dnl ignore the first case for now
-dnl if it has the mark lookup full address
+dnl if it has the mark look up full address
dnl broken: %1 is full address not just detail
R< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 >
dnl workspace: ... or <match|@user@domain> user <@domain>
-dnl no match, try user+detail@domain
+dnl no match, try user+detail@domain:
+dnl look up user+*@domain and user@domain
R<@$+ + $* @ $+> $+ < @ $+ >
$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 >
R<@$+ + $* @ $+> $+ < @ $+ >
@@ -1527,7 +1530,7 @@ R$={SMTPOpModes} $| TMPF <e r> $| $+ $#error $@ 4.3.0 $: _TMPFMSG_(`OPM')')
# ... return original address for MTA to queue up
R$* $| TMPF <$*> $| $+ $@ $3
-# if mailRoutingAddress and local or non-existant mailHost,
+# if mailRoutingAddress and local or non-existent mailHost,
# return the new mailRoutingAddress
ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
R<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2
@@ -1610,14 +1613,14 @@ dnl <result> <passthru>
SD
dnl workspace <key> <default> <passthru> <mark>
-dnl lookup with tag (in front, no delimiter here)
+dnl look up with tag (in front, no delimiter here)
dnl 2 3 4 5
R<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
-dnl lookup without tag?
+dnl look up without tag?
dnl 1 2 3 4
R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
-ifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
+ifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: look up .rest
dnl XXX apply this also to IP addresses?
dnl currently it works the wrong way round for [1.2.3.4]
dnl 1 2 3 4 5 6
@@ -1640,7 +1643,7 @@ R<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>')
dnl not found, but subdomain: try again
dnl 1 2 3 4 5 6
R<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6>
-ifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
+ifdef(`_FFR_LOOKUPTAG_', `dnl look up Tag:
dnl 1 2 3 4
R<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
dnl not found, no subdomain: return <default> and <passthru>
@@ -1669,10 +1672,10 @@ dnl <result> <passthru>
######################################################################
SA
-dnl lookup with tag
+dnl look up with tag
dnl 2 3 4 5
R<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
-dnl lookup without tag
+dnl look up without tag
dnl 1 2 3 4
R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
dnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
@@ -2402,7 +2405,7 @@ dnl otherwise call tls_client; see above
R$+ $| $#$* $@ $>"Delay_TLS_Clt" $2
R$+ $| $* $: <?> $>FullAddr $>CanonAddr $1
ifdef(`_SPAM_FH_',
-`dnl lookup user@ and user@address
+`dnl look up user@ and user@address
ifdef(`_ACCESS_TABLE_', `',
`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
')')dnl
@@ -2412,7 +2415,7 @@ dnl and simplified by omitting some < >.
R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
dnl R<?> $@ something_is_very_wrong_here
-# lookup the addresses only with Spam tag
+# look up the addresses only with Spam tag
R<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
R<@> $* $| $* $: $2 $1 reverse result
dnl', `dnl')
@@ -2608,16 +2611,16 @@ R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
### Parameters:
### <exact tag> $| <mark:address> <mark:address> ... <>
dnl maybe we should have a @ (again) in front of the mark to
-dnl avoid errorneous matches (with error messages?)
+dnl avoid erroneous matches (with error messages?)
dnl if we can make sure that tag is always a single token
dnl then we can omit the delimiter $|, otherwise we need it
-dnl to avoid errorneous matchs (first rule: D: if there
+dnl to avoid erroneous matches (first rule: D: if there
dnl is that mark somewhere in the list, it will be taken).
dnl moreover, we can do some tricks to enforce lookup with
dnl the tag only, e.g.:
### where "exact" is either "+" or "!":
-### <+ TAG> lookup with and w/o tag
-### <! TAG> lookup with tag
+### <+ TAG> look up with and w/o tag
+### <! TAG> look up with tag
dnl Warning: + and ! should be in OperatorChars (otherwise there must be
dnl a blank between them and the tag.
### possible values for "mark" are:
@@ -2706,8 +2709,9 @@ R$* $: $1 $| $>"Local_clt_features" $1
R$* $| $#$* $#$2
R$* $| $* $: $1', `dnl')
ifdef(`_ACCESS_TABLE_', `dnl
-R$* $: $>D <$&{client_name}> <?> <! CLT_FEAT_TAG> <>
-R<?>$* $: $>A <$&{client_addr}> <?> <! CLT_FEAT_TAG> <>
+dnl the servername can have a trailing dot from canonification
+R$* . $1
+R$+ $: $>D <$1> <?> <! CLT_FEAT_TAG> <>
R<?>$* $: <$(access CLT_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
R<?>$* $@ OK
ifdef(`_ATMPF_', `dnl tempfail?
@@ -2802,6 +2806,18 @@ R:$* $| $-.$+ $: $(macro {TLS_Name} $@ .$3 $) $>TLS_NameInList :$1
R$* ok $@ $>STS_SAN
R:$*: $#error $@ 4.7.0 $: 450 $&{server_name} not found in " "$1', `dnl')
+ifdef(`TLS_PERM_ERR', `dnl
+define(`TLS_DSNCODE', `5.7.0')dnl
+define(`TLS_ERRCODE', `554')',`dnl
+define(`TLS_DSNCODE', `4.7.0')dnl
+define(`TLS_ERRCODE', `454')')dnl
+define(`SW_MSG', `TLS handshake failed.')dnl
+define(`DANE_MSG', `DANE check failed.')dnl
+define(`DANE_TEMP_MSG', `DANE check failed temporarily.')dnl
+define(`DANE_NOTLS_MSG', `DANE: missing STARTTLS.')dnl
+define(`PROT_MSG', `STARTTLS failed.')dnl
+define(`CNF_MSG', `STARTTLS temporarily not possible.')dnl
+
######################################################################
### tls_rcpt: is connection with server "good" enough?
### (done in client, per recipient)
@@ -2833,12 +2849,22 @@ R<?> $+ $: $1 $| <U:$1@> <E:>
dnl look it up
dnl also look up a default value via E:
R$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
+dnl no applicable requirements; trigger an error on DANE_FAIL
+dnl note: this allows to disable DANE per RCPT.
+R$* $| <?> $: $1 $| $&{verify} $| <?>
+R$* $| DANE_FAIL $| <?> $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_MSG"
+R$* $| DANE_NOTLS $| <?> $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_NOTLS_MSG"
+R$* $| DANE_TEMP $| <?> $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_TEMP_MSG"
dnl found nothing: stop here
R$* $| <?> $@ OK
ifdef(`_ATMPF_', `dnl tempfail?
R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: _TMPFMSG_(`TR')', `dnl')
dnl use the generic routine (for now)
-R$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>')
+R$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>', `dnl
+R$* $: $1 $| $&{verify}
+R$* $| DANE_NOTLS $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_NOTLS_MSG"
+R$* $| DANE_TEMP $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_TEMP_MSG"
+R$* $| DANE_FAIL $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_MSG"')
######################################################################
### tls_client: is connection with client "good" enough?
@@ -2915,22 +2941,14 @@ dnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
dnl extensions: could be a list of further requirements
dnl for now: CN:string {cn_subject} == string
######################################################################
-ifdef(`TLS_PERM_ERR', `dnl
-define(`TLS_DSNCODE', `5.7.0')dnl
-define(`TLS_ERRCODE', `554')',`dnl
-define(`TLS_DSNCODE', `4.7.0')dnl
-define(`TLS_ERRCODE', `454')')dnl
-define(`SW_MSG', `TLS handshake failed.')dnl
-define(`DANE_MSG', `DANE check failed.')dnl
-define(`PROT_MSG', `STARTTLS failed.')dnl
-define(`CNF_MSG', `STARTTLS temporarily not possible.')dnl
STLS_connection
ifdef(`_FULL_TLS_CONNECTION_CHECK_', `dnl', `dnl use default error
dnl deal with TLS handshake failures: abort
RSOFTWARE $#error $@ TLS_DSNCODE $: "TLS_ERRCODE SW_MSG"
-RDANE_FAIL $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_MSG"
+dnl RDANE_FAIL $#error $@ TLS_DSNCODE $: "TLS_ERRCODE DANE_MSG"
RPROTOCOL $#error $@ TLS_DSNCODE $: "TLS_ERRCODE PROT_MSG"
RCONFIG $#error $@ TLS_DSNCODE $: "TLS_ERRCODE CNF_MSG"
+dnl RDANE_TEMP $#error $@ 4.7.0 $: "454 DANE_TEMP_MSG"
divert(-1)')
dnl common ruleset for tls_{client|server}
dnl input: ${verify} $| <ResultOfLookup> [<>]
@@ -2953,10 +2971,12 @@ R`'$1 $| $`'* $`'#error $`'@ TLS_DSNCODE $: "TLS_ERRCODE $2"')dnl
TLS_ERRORS(SOFTWARE,SW_MSG)
# deal with TLS protocol errors: abort
TLS_ERRORS(PROTOCOL,PROT_MSG)
-# deal with DANE errors: abort
-TLS_ERRORS(DANE_FAIL,DANE_MSG)
+dnl # deal with DANE errors: abort
+dnl TLS_ERRORS(DANE_FAIL,DANE_MSG)
# deal with CONFIG (tls_clt_features) errors: abort
TLS_ERRORS(CONFIG,CNF_MSG)
+dnl # deal with DANE tempfail: abort
+dnl TLS_ERRORS(DANE_TEMP,DANE_TEMP_MSG)
R$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1
dnl separate optional requirements
R$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1
diff --git a/contrib/sendmail/cf/m4/version.m4 b/contrib/sendmail/cf/m4/version.m4
index 3942ca1a0691..bcdd76333d20 100644
--- a/contrib/sendmail/cf/m4/version.m4
+++ b/contrib/sendmail/cf/m4/version.m4
@@ -15,4 +15,4 @@ VERSIONID(`$Id: version.m4,v 8.237 2014-01-27 12:55:17 ca Exp $')
#
divert(0)
# Configuration version number
-DZ8.17.1`'ifdef(`confCF_VERSION', `/confCF_VERSION')
+DZ8.18.1`'ifdef(`confCF_VERSION', `/confCF_VERSION')
diff --git a/contrib/sendmail/cf/sh/makeinfo.sh b/contrib/sendmail/cf/sh/makeinfo.sh
index 1c907ccd68fa..4ab306665e24 100644
--- a/contrib/sendmail/cf/sh/makeinfo.sh
+++ b/contrib/sendmail/cf/sh/makeinfo.sh
@@ -57,4 +57,4 @@ fi
echo '#####' built by $user@$host
echo '#####' in `pwd` | sed 's/\/tmp_mnt//'
echo '#####' using $1 as configuration include directory | sed 's/\/tmp_mnt//'
-echo "define(\`__HOST__', $host)dnl"
+echo "define(\`__HOST__', \`$host')dnl"
diff --git a/contrib/sendmail/contrib/buildvirtuser b/contrib/sendmail/contrib/buildvirtuser
index 173f95b0cc8e..168718ed13e6 100755
--- a/contrib/sendmail/contrib/buildvirtuser
+++ b/contrib/sendmail/contrib/buildvirtuser
@@ -170,7 +170,7 @@ LINE: while (<DOMAIN>)
warn "Bogus line $line in $virts/$domain\n";
}
- # Variable subsitution
+ # Variable substitution
$key =~ s/\$DOMAIN/$domain/g;
$value =~ s/\$DOMAIN/$domain/g;
$value =~ s/\$LHS/$lhs/g;
diff --git a/contrib/sendmail/doc/op/Makefile b/contrib/sendmail/doc/op/Makefile
index 47673b47a13d..9f24a2e25694 100644
--- a/contrib/sendmail/doc/op/Makefile
+++ b/contrib/sendmail/doc/op/Makefile
@@ -13,9 +13,12 @@ PIC= ${PIC_CMD} -C
EQNASCII= ${EQN_CMD} -C -Tascii
EQNPS= ${EQN_CMD} -C -Tps
ROFFASCII= ${ROFF_CMD} -Tascii ${MACROS}
+ROFFNOSGR= GROFF_NO_SGR=1 ${ROFFASCII}
ROFFPS= ${ROFF_CMD} -Tps -mps ${MACROS}
ULASCII= ${UL_CMD} -t dumb
PS2PDF= ${PS2PDF_CMD}
+OPTXT_CMD= ${PIC} ${SRCS} | ${EQNASCII} | ${ROFFASCII} | ${ULASCII} 2>/dev/null
+OPTXTNS_CMD= ${PIC} ${SRCS} | ${EQNASCII} | ${ROFFNOSGR} | ${ULASCII}
all: ${OBJS}
@@ -26,8 +29,7 @@ op.ps: ${SRCS}
op.txt: ${SRCS}
rm -f $@
- @echo "Note: see README file in case of errors."
- ${PIC} ${SRCS} | ${EQNASCII} | ${ROFFASCII} | ${ULASCII} > $@
+ ${OPTXT_CMD} > $@ || ${OPTXTNS_CMD} > $@
op.pdf: op.ps
rm -f $@
diff --git a/contrib/sendmail/doc/op/op.me b/contrib/sendmail/doc/op/op.me
index b5b3cbac9e62..2dfe60f018af 100644
--- a/contrib/sendmail/doc/op/op.me
+++ b/contrib/sendmail/doc/op/op.me
@@ -92,7 +92,7 @@ Version \\$2
..
.rm Ve
.sp
-For Sendmail Version 8.17
+For Sendmail Version 8.18
.)l
.(f
Sendmail is a trademark of Proofpoint, Inc.
@@ -1690,22 +1690,17 @@ Blank lines and lines beginning with a sharp sign
.q # )
are comments.
.pp
-The second form is processed by the
+The second form is processed by one of the available map types,
+e.g.,
.i ndbm \|(3)\**
.(f
\**The
.i gdbm
package does not work.
.)f
-or the Berkeley DB library.
-This form is in the file
-.i /etc/mail/aliases.db
-(if using NEWDB)
+the Berkeley DB library,
or
-.i /etc/mail/aliases.dir
-and
-.i /etc/mail/aliases.pag
-(if using NDBM).
+.i cdb .
This is the form that
.i sendmail
actually uses to resolve aliases.
@@ -3246,6 +3241,9 @@ often cannot assume that a given file was created by the owner,
particularly when it is in a writable directory.
You can set this flag if you know that file giveaway is restricted
on your system.
+.ip CertOwner
+Accept certificate public and private key files
+which are not owned by RunAsUser for STARTTLS.
.ip ClassFileInUnsafeDirPath
When reading class files (using the
.b F
@@ -4415,17 +4413,18 @@ It can accept or reject the command.
The
.i clt_features
ruleset is called with the server's host name
-when sendmail connects to it.
+before sendmail connects to it
+(only if sendmail is compiled with STARTTLS or SASL).
This ruleset should return
.b $#
followed by a list of options
-(single characters delimited by white space).
+(in general, single characters delimited by white space).
If the return value starts with anything else it is silently ignored.
Generally upper case characters turn off a feature
while lower case characters turn it on.
Options `D'/`M' cause the client to not use DANE/MTA-STS,
respectively,
-which is useful to interact with MTAs/MUs that have broken
+which is useful to interact with MTAs that have broken
DANE/MTA-STS setups by simply not using it.
Note:
The
@@ -4454,15 +4453,18 @@ not passed on to the next relay.
.pp
The
.i tls_client
-ruleset is called when sendmail acts as server, after a STARTTLS command
-has been issued, and from
+ruleset is called when sendmail acts as server:
+after a STARTTLS command has been issued and the TLS handshake
+was performed,
+and from
.i check_mail.
The parameter is the value of
.b ${verify}
and STARTTLS or MAIL, respectively.
If the ruleset does resolve to the
.q error
-mailer, the appropriate error code is returned to the client.
+mailer, the appropriate error code is returned to the client,
+for STARTTLS this happens for (most) subsequent commands.
.sh 4 "tls_server"
.pp
The
@@ -4506,8 +4508,8 @@ ruleset is called with the connecting client's host name
when a client connects to sendmail.
This ruleset should return
.b $#
-followed by a list of options (single characters
-delimited by white space).
+followed by a list of options
+(in general, single characters delimited by white space).
If the return value starts with anything else it is silently ignored.
Generally upper case characters turn off a feature
while lower case characters turn it on.
@@ -4526,6 +4528,40 @@ If a client sends one of the (HTTP) commands GET, POST, CONNECT, or USER
the connection is immediately terminated in the following cases:
if sent as first command, if sent as first command after STARTTLS,
or if the 'h' option is set.
+Option 'F' disables SMTP transaction stuffing protection which is
+enabled by default.
+The protection checks for clients which try to send commands
+without waiting for the server HELO/EHLO and DATA response.
+Option 'o' causes the server to accept only
+CRLF . CRLF
+as end of an SMTP message as required by the RFCs
+which is also a defense against SMTP smuggling (CVE-2023-51765).
+Option 'O' allows the server to accept a single dot on a line by itself
+as end of an SMTP message.
+Option 'g' instructs the server to fail SMTP messages
+which have a LF without a CR directly before it ("bare LF")
+by dropping the session with a 421 error.
+Option 'G' accepts SMTP messages which have a "bare LF".
+Option 'u' instructs the server to fail SMTP messages
+which have a CR without a LF directly after it ("bare CR")
+by dropping the session with a 421 error.
+Option 'U' accepts SMTP messages which have a "bare CR".
+There is a variant for the options 'u' and 'g':
+a '2' can be appended to the single character,
+in which case the server will replace the offending bare CR
+or bare LF with a space.
+This allows to accept mail from broken systems,
+but the message is modified to avoid SMTP smuggling.
+If needed, systems with broken SMTP implementations
+can be allowed some violations, e.g., a combination of
+.(b
+G U g2 u2 O
+.)b
+A command like
+.(b
+egrep 'Bare.*(CR|LF).*not allowed' $MAILLOG
+.)b
+can be used to find hosts which send bare CR or LF.
.(b
.ta 9n
A Do not offer AUTH
@@ -4539,13 +4575,24 @@ D Do not offer DSN
d Offer DSN (default)
E Do not offer ETRN
e Offer ETRN (default)
+F Disable transaction stuffing protection
+f Enforce transaction stuffing protection (default)
+G Accept "bare LF"s in a message
+g Do not accept "bare LF"s in a message (default)
+g2 Replace "bare LF" in a message with space
h Terminate session after HTTP commands
L Do not require AUTH (default)
l Require AUTH
+O Accept a single dot on a line by itself
+ as end of an SMTP message
+o Require CRLF . CRLF as end of an SMTP message (default)
P Do not offer PIPELINING
p Offer PIPELINING (default)
S Do not offer STARTTLS
s Offer STARTTLS (default)
+U Accept "bare CR"s in a message
+u Do not accept "bare CR"s in a message (default)
+u2 Replace "bare CR" in a message with space
V Do not request a client certificate
v Request a client certificate (default)
X Do not offer EXPN
@@ -4566,6 +4613,7 @@ accept email.
The
.i try_tls
ruleset is called when sendmail connects to another MTA.
+The argument for the ruleset is the name of the server.
If the ruleset does resolve to the
.q error
mailer, sendmail does not try STARTTLS even if it is offered.
@@ -4667,6 +4715,10 @@ specifying only one is an error.
The
.i authinfo
ruleset is called when sendmail tries to authenticate to another MTA.
+The arguments for the ruleset are the host name and IP address
+of the server separated by
+.b $|
+(which is a metacharacter).
It should return
.b $#
followed by a list of tokens that are used for SMTP AUTH.
@@ -4713,6 +4765,10 @@ The
.i greet_pause
ruleset is used to specify the amount of time to pause before sending the
initial SMTP 220 greeting.
+The arguments for the ruleset are the host name and IP address
+of the client separated by
+.b $|
+(which is a metacharacter).
If any traffic is received during that pause, an SMTP 554 rejection
response is given instead of the 220 greeting and all SMTP commands are
rejected during that connection.
@@ -4967,26 +5023,6 @@ a richer set of operators is
which adds support for UUCP, the %-hack, and X.400 addresses.
.ip $p
Sendmail's process id.
-.ip $q\(dg
-Default format of sender address.
-The
-.b $q
-macro specifies how an address should appear in a message
-when it is defaulted.
-Defaults to
-.q "<$g>" .
-It is commonly redefined to be
-.q "$?x$x <$g>$|$g$."
-or
-.q "$g$?x ($x)$." ,
-corresponding to the following two formats:
-.(b
-Eric Allman <eric@CS.Berkeley.EDU>
-eric@CS.Berkeley.EDU (Eric Allman)
-.)b
-.i Sendmail
-properly quotes names that have special characters
-if the first form is used.
.ip $r
Protocol used to receive the message.
Set from the
@@ -5356,16 +5392,21 @@ Possible values are:
.(b
.ta 13n
TRUSTED verification via DANE succeeded.
+DANE_FAIL verification via DANE failed.
+DANE_TEMP verification via DANE failed temporarily.
+DANE_NOTLS DANE required but STARTTLS was not available.
OK verification succeeded.
NO no cert presented.
NOT no cert requested.
FAIL cert presented but could not be verified,
e.g., the signing CA is missing.
NONE STARTTLS has not been performed.
-CLEAR STARTTLS has been disabled internally for a clear text delivery attempt.
+CLEAR STARTTLS has been disabled internally
+ for a clear text delivery attempt.
TEMP temporary error occurred.
PROTOCOL some protocol error occurred
at the ESMTP level (not TLS).
+CONFIG tls_*_features failed due to a syntax error.
SOFTWARE STARTTLS handshake failed,
which is a fatal error for this session,
the e-mail will be queued.
@@ -5670,7 +5711,7 @@ will fill the class
.b $={VirtHosts}
from an LDAP map lookup and
.b $={MyClass}
-from a hash database map lookup of the
+from a hash database map lookup of the key
.b foo .
There is also a built-in schema that can be accessed by only specifying:
.(b
@@ -5703,7 +5744,7 @@ Some classes have internal meaning to
.nr ii 0.5i
.\".ip $=b
.\"A set of Content-Types that will not have the newline character
-.\"translated to CR-LF before encoding into base64 MIME.
+.\"translated to CRLF before encoding into base64 MIME.
.\"The class can have major times
.\"(e.g.,
.\".q image )
@@ -5793,6 +5834,24 @@ file into a class, use
FL/etc/passwd %[^:]
.)b
which reads every line up to the first colon.
+.sh 2 "E \*- Set or Propagate Environment Variables"
+.pp
+.b E
+configuration lines set or propagate environment variables into children.
+.(b F
+.b E \c
+.i name
+.)b
+will propagate the named variable from the environment when
+.i sendmail
+was invoked into any children it calls;
+.(b F
+.b E \c
+.i name =\c
+.i value
+.)b
+sets the named variable to the indicated value.
+Any variables not explicitly named will not be in the child environment.
.sh 2 "M \*- Define Mailer"
.pp
Programs and interfaces to mailers
@@ -5819,7 +5878,7 @@ Path The pathname of the mailer
Flags Special flags for this mailer
Sender Rewriting set(s) for sender addresses
Recipient Rewriting set(s) for recipient addresses
-recipients Maximum number of recipients per connection
+recipients Maximum number of recipients per envelope
Argv An argument vector to pass to this mailer
Eol The end-of-line string for this mailer
Maxsize The maximum message length to this mailer
@@ -6146,7 +6205,7 @@ Do not apply
.b FallbackMXhost
either.
.ip 1
-Don't send null characters ('\\0') to this mailer.
+Strip null characters ('\\0') when sending to this mailer.
.ip 2
Don't use ESMTP even if offered; this is useful for broken
systems that offer ESMTP but fail on EHLO (without recovering
@@ -6187,7 +6246,7 @@ do
7\(->8 bit MIME conversions.
These conversions are limited to text/plain data.
.ip :
-Check addresses to see if they begin
+Check addresses to see if they begin with
.q :include: ;
if they do, convert them to the
.q *include*
@@ -6679,13 +6738,11 @@ If it does not appear in the
.i timeout
interval issue a warning.
.ip AllowBogusHELO
-[no short name]
If set, allow HELO SMTP commands that don't include a host name.
Setting this violates RFC 1123 section 5.2.5,
but is necessary to interoperate with several SMTP clients.
If there is a value, it is still checked for legitimacy.
.ip AuthMaxBits=\fIN\fP
-[no short name]
Limit the maximum encryption strength for the security layer in
SMTP AUTH (SASL). Default is essentially unlimited.
This allows to turn off additional encryption in SASL if
@@ -6698,7 +6755,6 @@ Hence setting
.b AuthMaxBits
to 168 will disable any encryption in SASL.
.ip AuthMechanisms
-[no short name]
List of authentication mechanisms for AUTH (separated by spaces).
The advertised list of authentication mechanisms will be the
intersection of this list and the list of available mechanisms as
@@ -6706,7 +6762,6 @@ determined by the Cyrus SASL library.
If STARTTLS is active, EXTERNAL will be added to this list.
In that case, the value of {cert_subject} is used as authentication id.
.ip AuthOptions
-[no short name]
List of options for SMTP AUTH consisting of single characters
with intervening white space or commas.
.(b
@@ -6743,14 +6798,12 @@ The options 'a', 'c', 'd', 'f', 'p', and 'y' refer to properties of the
selected SASL mechanisms.
Explanations of these properties can be found in the Cyrus SASL documentation.
.ip AuthRealm
-[no short name]
The authentication realm that is passed to the Cyrus SASL library.
If no realm is specified,
.b $j
is used.
See also KNOWNBUGS.
.ip BadRcptThrottle=\fIN\fP
-[no short name]
If set and the specified number of recipients in a single SMTP
transaction have been rejected, sleep for one second after each subsequent
RCPT command in that transaction.
@@ -6761,12 +6814,10 @@ Set the blank substitution character to
Unquoted spaces in addresses are replaced by this character.
Defaults to space (i.e., no change is made).
.ip CACertPath
-[no short name]
Path to directory with certificates of CAs.
This directory directory must contain the hashes of each CA certificate
as filenames (or as links to them).
.ip CACertFile
-[no short name]
File containing one or more CA certificates;
see section about STARTTLS for more information.
.ip CertFingerprintAlgorithm
@@ -6811,19 +6862,16 @@ and subtracted from the priority.
Thus, messages with a higher Priority: will be favored.
Defaults to 1800.
.ip ClientCertFile
-[no short name]
File containing the certificate of the client, i.e., this certificate
is used when
.i sendmail
acts as client (for STARTTLS).
.ip ClientKeyFile
-[no short name]
File containing the private key belonging to the client certificate
(for STARTTLS if
.i sendmail
runs as client).
.ip ClientPortOptions=\fIoptions\fP
-[no short name]
Set client SMTP options.
The options are
.i key=value
@@ -6886,7 +6934,6 @@ Options can be cleared by preceding them with a minus sign.
It is also possible to specify numerical values, e.g.,
.b -0x0010 .
.ip ColonOkInAddr
-[no short name]
If set, colons are acceptable in e-mail addresses
(e.g.,
.q host:user ).
@@ -6935,11 +6982,9 @@ and avoid using up excessive resources
on the other end.
The default is five minutes.
.ip ConnectOnlyTo=\fIaddress\fP
-[no short name]
This can be used to
override the connection address (for testing purposes).
.ip ConnectionRateThrottle=\fIN\fP
-[no short name]
If set to a positive value,
allow no more than
.i N
@@ -6948,12 +6993,10 @@ This is intended to flatten out peaks
and allow the load average checking to cut in.
Defaults to zero (no limits).
.ip ConnectionRateWindowSize=\fIN\fP
-[no short name]
Define the length of the interval for which
the number of incoming connections is maintained.
The default is 60 seconds.
.ip ControlSocketName=\fIname\fP
-[no short name]
Name of the control socket for daemon management.
A running
.i sendmail
@@ -6974,13 +7017,11 @@ and the load average of the machine expressed as an integer.
If not set, no control socket will be available.
Solaris and pre-4.4BSD kernel users should see the note in sendmail/README .
.ip CRLFile=\fIname\fP
-[no short name]
Name of file that contains certificate
revocation status, useful for X.509v3 authentication.
Note: if a CRLFile is specified but the file is unusable,
STARTTLS is disabled.
.ip CRLPath=\fIname\fP
-[no short name]
Name of directory that contains hashes pointing to
certificate revocation status files.
Symbolic links can be generated with the following
@@ -7142,7 +7183,6 @@ The modifier ``O'' causes sendmail to ignore a socket
if it can't be opened.
This applies to failures from the socket(2) and bind(2) calls.
.ip DefaultAuthInfo
-[no short name]
Filename that contains default authentication information for outgoing
connections. This file must contain the user id, the authorization id,
the password (plain text), the realm and the list of mechanisms to use
@@ -7162,7 +7202,6 @@ will complain).
Use the authinfo ruleset instead which provides more control over
the usage of the data anyway.
.ip DefaultCharSet=\fIcharset\fP
-[no short name]
When a message that has 8-bit characters but is not in MIME format
is converted to MIME
(see the EightBitMode option)
@@ -7174,7 +7213,6 @@ If this option is not set, the value
.q unknown-8bit
is used.
.ip DataFileBufferSize=\fIthreshold\fP
-[no short name]
Set the
.i threshold ,
in bytes,
@@ -7183,7 +7221,6 @@ queue data file
becomes disk-based.
The default is 4096 bytes.
.ip DeadLetterDrop=\fIfile\fP
-[no short name]
Defines the location of the system-wide dead.letter file,
formerly hardcoded to /usr/tmp/dead.letter.
If this option is not set (the default),
@@ -7224,14 +7261,12 @@ option has been combined into the
option.
.)f
.ip DelayLA=\fILA\fP
-[no short name]
When the system load average exceeds
.i LA ,
.i sendmail
will sleep for one second on most SMTP commands and
before accepting connections.
.ip DeliverByMin=\fItime\fP
-[no short name]
Set minimum time for Deliver By SMTP Service Extension (RFC 2852).
If 0, no time is listed, if less than 0, the extension is not offered,
if greater than 0, it is listed as minimum time
@@ -7260,7 +7295,6 @@ Note: for internal reasons,
if a milter is enabled which can reject or delete recipients.
In that case the mode will be changed to ``b''.
.ip DialDelay=\fIsleeptime\fP
-[no short name]
Dial-on-demand network connections can see timeouts
if a connection is opened before the call is set up.
If this is set to an interval and a connection times out
@@ -7287,7 +7321,6 @@ is either "CC f" if the option
is used or "c u" otherwise.
Note that only the "CC", "c", "f", and "u" flags are checked.
.ip DontBlameSendmail=\fIoption,option,...\fP
-[no short name]
In order to avoid possible cracking attempts
caused by world- and group-writable files and directories,
.i sendmail
@@ -7304,7 +7337,6 @@ The details of these flags are described above.
.\"XXX should have more here!!! XXX
.b "Use of this option is not recommended."
.ip DontExpandCnames
-[no short name]
The standards say that all host addresses used in a mail message
must be fully canonical.
For example, if your host is named
@@ -7322,7 +7354,6 @@ so the behavior may become acceptable.
Please note that hosts downstream may still rewrite the address
to be the true canonical name however.
.ip DontInitGroups
-[no short name]
If set,
.i sendmail
will avoid using the initgroups(3) call.
@@ -7334,7 +7365,6 @@ will be their primary group (the one in the password file),
which will make file access permissions somewhat more restrictive.
Has no effect on systems that don't have group lists.
.ip DontProbeInterfaces
-[no short name]
.i Sendmail
normally finds the names of all interfaces active on your machine
when it starts up
@@ -7375,7 +7405,6 @@ and the mail will be sent to the first address in the route,
even if later addresses are known.
This may be useful if you are caught behind a firewall.
.ip DoubleBounceAddress=\fIerror-address\fP
-[no short name]
If an error occurs when sending an error message,
send the error report
(termed a
@@ -7483,7 +7512,7 @@ background delivery.
If specified, the
.i fallbackhost
acts like a very low priority MX
-on every host.
+on a host.
MX records will be looked up for this host,
unless the name is surrounded by square brackets.
This is intended to be used by sites with poor network connectivity.
@@ -7493,12 +7522,11 @@ also go to the FallbackMXhost.
.ip FallBackSmartHost=\fIhostname\fP
If specified, the
.i FallBackSmartHost
-will be used in a last-ditch effort for each host.
+will be used in a last-ditch effort for a host.
This is intended to be used by sites with "fake internal DNS",
e.g., a company whose DNS accurately reflects the world
inside that company's domain but not outside.
.ip FastSplit
-[no short name]
If set to a value greater than zero (the default is one),
it suppresses the MX lookups on addresses
when they are initially sorted, i.e., for the first delivery attempt.
@@ -7538,7 +7566,6 @@ and then in
.i ~username /.forward
(but only if the first file does not exist).
.ip HeloName=\fIname\fP
-[no short name]
Set the name to be used for HELO/EHLO (instead of $j).
.ip HelpFile=\fIfile\fP
[H]
@@ -7555,7 +7582,6 @@ To avoid providing this information to a client specify an empty file.
If an outgoing mailer is marked as being expensive,
don't connect immediately.
.ip HostsFile=\fIpath\fP
-[no short name]
The path to the hosts database,
normally
.q /etc/hosts .
@@ -7573,7 +7599,6 @@ that is under the control of the system
.i gethostbyname (3)
routine.
.ip HostStatusDirectory=\fIpath\fP
-[no short name]
The location of the long term host status information.
When set,
information about the status of hosts
@@ -7592,16 +7617,15 @@ A suggested value for sites desiring persistent host status is
(i.e., a subdirectory of the queue directory).
.ip IgnoreDots
[i]
-Ignore dots in incoming messages.
-This is always disabled (that is, dots are always accepted)
-when reading SMTP mail.
+Do not treat leading dots in incoming messages in a special way,
+e.g., as end of a message if it is the only character in a line.
+This is always disabled when reading SMTP mail.
.ip InputMailFilters=\fIname,name,...\fP
A comma separated list of filters which determines which filters
(see the "X \*- Mail Filter (Milter) Definitions" section)
and the invocation sequence are contacted for incoming SMTP messages.
If none are set, no filters will be contacted.
.ip LDAPDefaultSpec=\fIspec\fP
-[no short name]
Sets a default map specification for LDAP maps.
The value should only contain LDAP specific settings
such as
@@ -7625,14 +7649,12 @@ The
.b \-M
flag is preferred.
.ip MailboxDatabase
-[no short name]
Type of lookup to find information about local mailboxes,
defaults to ``pw'' which uses
.i getpwnam .
Other types can be introduced by adding them to the source code,
see libsm/mbdb.c for details.
.ip UseMSP
-[no short name]
Use as mail submission program, i.e.,
allow group writable queue files
if the group is the same as that of a set-group-ID sendmail binary.
@@ -7653,10 +7675,8 @@ This also requires that MATCHGECOS
be turned on during compilation.
This option is not recommended.
.ip MaxAliasRecursion=\fIN\fP
-[no short name]
The maximum depth of alias recursion (default: 10).
.ip MaxDaemonChildren=\fIN\fP
-[no short name]
If set,
.i sendmail
will refuse connections when it has more than
@@ -7676,7 +7696,6 @@ other than background must be used.
If not set, there is no limit to the number of children --
that is, the system load average controls this.
.ip MaxHeadersLength=\fIN\fP
-[no short name]
If set to a value greater than zero it specifies
the maximum length of the sum of all headers.
This can be used to prevent a denial of service attack.
@@ -7689,7 +7708,6 @@ Messages that have been processed more than
times are assumed to be in a loop and are rejected.
Defaults to 25.
.ip MaxMessageSize=\fIN\fP
-[no short name]
Specify the maximum message size
to be advertised in the ESMTP EHLO response.
Messages larger than this will be rejected.
@@ -7698,7 +7716,6 @@ that value will be listed in the SIZE response,
otherwise SIZE is advertised in the ESMTP EHLO response
without a parameter.
.ip MaxMimeHeaderLength=\fIN[/M]\fP
-[no short name]
Sets the maximum length of certain MIME header field values to
.i N
characters.
@@ -7724,7 +7741,6 @@ for the number of
commands, see Section
"Measures against Denial of Service Attacks".
.ip MaxQueueChildren=\fIN\fP
-[no short name]
When set, this limits the number of concurrent queue runner processes to
.i N.
This helps to control the amount of system resources used when processing
@@ -7748,7 +7764,6 @@ imposed by
This discrepancy can be large if some queue runners have to wait
for a slow server and if short intervals are used.
.ip MaxQueueRunSize=\fIN\fP
-[no short name]
The maximum number of jobs that will be processed
in a single queue run.
If not set, there is no limit on the size.
@@ -7773,14 +7788,12 @@ then only
.b N
entries are printed per queue group.
.ip MaxRecipientsPerMessage=\fIN\fP
-[no short name]
The maximum number of recipients that will be accepted per message
in an SMTP transaction.
Note: setting this too low can interfere with sending mail from
MUAs that use SMTP for initial submission.
If not set, there is no limit on the number of recipients per envelope.
.ip MaxRunnersPerQueue=\fIN\fP
-[no short name]
This sets the default maximum number of queue runners for queue groups.
Up to
.i N
@@ -7799,7 +7812,6 @@ even if I am in an alias expansion.
This option is deprecated
and will be removed from a future version.
.ip Milter
-[no short name]
This option has several sub(sub)options.
The names of the suboptions are separated by dots.
At the first level the following options are available:
@@ -7840,14 +7852,12 @@ gives a 452 response
to the MAIL command.
This invites the sender to try again later.
.ip MaxQueueAge=\fIage\fP
-[no short name]
If this is set to a value greater than zero,
entries in the queue will be retried during a queue run
only if the individual retry time has been reached
which is doubled for each attempt.
The maximum retry time is limited by the specified value.
.ip MinQueueAge=\fIage\fP
-[no short name]
Don't process any queued jobs
that have been in the queue less than the indicated time interval.
This is intended to allow you to get responsiveness
@@ -7859,7 +7869,6 @@ This option is ignored for queue runs that select a subset
of the queue, i.e.,
.q \-q[!][I|R|S|Q][string]
.ip MustQuoteChars=\fIs\fP
-[no short name]
Sets the list of characters that must be quoted if used in a full name
that is in the phrase part of a ``phrase <address>'' syntax.
The default is ``\'.''.
@@ -7871,11 +7880,9 @@ O MustQuoteChars=.
.)b
Moreover, relaxed header signing should be used for DKIM signatures.
.ip NiceQueueRun
-[no short name]
The priority of queue runners (nice(3)).
This value must be greater or equal zero.
.ip NoRecipientAction
-[no short name]
The action to take when you receive a message that has no valid
recipient headers (To:, Cc:, Bcc:, or Apparently-To: \(em
the last included for back compatibility with old
@@ -7933,7 +7940,6 @@ are always operators.
Note that OperatorChars must be set in the
configuration file before any rulesets.
.ip PidFile=\fIfilename\fP
-[no short name]
Filename of the pid file.
(default is _PATH_SENDMAILPID).
The
@@ -8029,7 +8035,6 @@ Authentication Warnings add warnings about various conditions
that may indicate attempts to spoof the mail system,
such as using a non-standard queue directory.
.ip ProcessTitlePrefix=\fIstring\fP
-[no short name]
Prefix the process title shown on 'ps' listings with
.i string .
The
@@ -8092,12 +8097,10 @@ Defaults to 8 multiplied by
the number of processors online on the system
(if that can be determined).
.ip QueueFileMode=\fImode\fP
-[no short name]
Default permissions for queue files (octal).
If not set, sendmail uses 0600 unless its real
and effective uid are different in which case it uses 0644.
.ip QueueSortOrder=\fIalgorithm\fP
-[no short name]
Sets the
.i algorithm
used for sorting the queue.
@@ -8142,7 +8145,6 @@ Use that form instead of the
.q QueueTimeout
form.
.ip RandFile
-[no short name]
Name of file containing random data or the name of the UNIX socket
if EGD is used.
A (required) prefix "egd:" or "file:" specifies the type.
@@ -8191,7 +8193,6 @@ Notice: it might be necessary to apply the same (or similar) options to
.i submit.cf
too.
.ip RequiresDirfsync
-[no short name]
This option can be used to override the compile time flag
.b REQUIRES_DIR_FSYNC
at runtime by setting it to
@@ -8205,14 +8206,12 @@ it is enabled by default for Linux.
According to some information this flag is not needed
anymore for kernel 2.4.16 and newer.
.ip RrtImpliesDsn
-[no short name]
If this option is set, a
.q Return-Receipt-To:
header causes the request of a DSN, which is sent to
the envelope sender as required by RFC 1891,
not to the address given in the header.
.ip RunAsUser=\fIuser\fP
-[no short name]
The
.i user
parameter may be a user name
@@ -8276,7 +8275,6 @@ Defaults to 12 multiplied by
the number of processors online on the system
(if that can be determined).
.ip RejectLogInterval=\fItimeout\fP
-[no short name]
Log interval when refusing connections for this long
(default: 3h).
.ip RetryFactor=\fIfact\fP
@@ -8292,7 +8290,6 @@ In most environments this should be positive,
since hosts that are down are all too often down for a long time.
Defaults to 90000.
.ip SafeFileEnvironment=\fIdir\fP
-[no short name]
If this option is set,
.i sendmail
will do a
@@ -8332,12 +8329,10 @@ will not return the DSN keyword in response to an EHLO
and will not do Delivery Status Notification processing as described in
RFC 1891.
.ip ServerCertFile
-[no short name]
File containing the certificate of the server, i.e., this certificate
is used when sendmail acts as server
(used for STARTTLS).
.ip ServerKeyFile
-[no short name]
File containing the private key belonging to the server certificate
(used for STARTTLS).
.ip ServerSSLOptions
@@ -8357,7 +8352,6 @@ Options can be cleared by preceding them with a minus sign.
It is also possible to specify numerical values, e.g.,
.b -0x0010 .
.ip ServiceSwitchFile=\fIfilename\fP
-[no short name]
If your host operating system has a service switch abstraction
(e.g., /etc/nsswitch.conf on Solaris
or /etc/svc.conf on Ultrix and DEC OSF/1)
@@ -8397,7 +8391,6 @@ The default file is
Strip input to seven bits for compatibility with old systems.
This shouldn't be necessary.
.ip SharedMemoryKey
-[no short name]
Key to use for shared memory segment;
if not set (or 0), shared memory will not be used.
If set to
@@ -8417,7 +8410,6 @@ This allows for more efficient program execution, since only
one process needs to update the data instead of each individual
process gathering the data each time it is required.
.ip SharedMemoryKeyFile
-[no short name]
If
.b SharedMemoryKey
is set to
@@ -8425,13 +8417,11 @@ is set to
then the automatically selected shared memory key will be stored
in the specified file.
.ip SingleLineFromHeader
-[no short name]
If set, From: lines that have embedded newlines are unwrapped
onto one line.
This is to get around a botch in Lotus Notes
that apparently cannot understand legally wrapped RFC 822 headers.
.ip SingleThreadDelivery
-[no short name]
If set, a client machine will never try to open two SMTP connections
to a single server machine at the same time,
even in different processes.
@@ -8532,7 +8522,6 @@ PostMilter is useful only when
is running as an SMTP server; in all other situations it
acts the same as True.
.ip TLSFallbacktoClear
-[no short name]
If set,
.i sendmail
immediately tries an outbound connection again without STARTTLS
@@ -8548,7 +8537,6 @@ Hence such requirements will cause an error on a retry without STARTTLS.
Therefore they should only trigger a temporary failure so the connection
is later on tried again.
.ip TLSSrvOptions
-[no short name]
List of options for SMTP STARTTLS for the server
consisting of single characters
with intervening white space or commas.
@@ -8587,7 +8575,6 @@ the TZ environment variable is cleared (so the system default is used);
if set but null, the user's TZ variable is used,
and if set and non-null the TZ variable is set to this value.
.ip TrustedUser=\fIuser\fP
-[no short name]
The
.i user
parameter may be a user name
@@ -8633,7 +8620,6 @@ Defaults to
Don't change this unless your system uses a different UNIX mailbox format
(very unlikely).
.ip UnsafeGroupWrites
-[no short name]
If set (default),
:include: and .forward files that are group writable are considered
.q unsafe ,
@@ -8645,7 +8631,6 @@ Note: use
.b DontBlameSendmail
instead; this option is deprecated.
.ip UseCompressedIPv6Addresses
-[no short name]
If set, the compressed format of IPv6 addresses,
such as IPV6:::1, will be used,
instead of the uncompressed format,
@@ -8699,7 +8684,6 @@ SMTP command with a suitable
.b PrivacyOptions
setting.
.ip XscriptFileBufferSize=\fIthreshold\fP
-[no short name]
Set the
.i threshold ,
in bytes,
@@ -9004,7 +8988,7 @@ For example, the rule
.ta 1.5i
R$\- ! $+ $: $(uucp $1 $@ $2 $: $2 @ $1 . UUCP $)
.)b
-Looks up the UUCP name in a (user defined) UUCP map;
+looks up the UUCP name in a (user defined) UUCP map;
if not found it turns it into
.q \&.UUCP
form.
@@ -10226,7 +10210,7 @@ the new version of the DBM library
that allows multiple databases will be used.
If neither CDB, NDBM, nor NEWDB are set,
a much less efficient method of alias lookup is used.
-.ip CWDB
+.ip CDB
If set, use the cdb (tinycdb) package.
.ip NEWDB
If set, use the new database package from Berkeley (from 4.4BSD).
@@ -11251,12 +11235,30 @@ as well as
{auth_authen} and {auth_author}.
.sh 2 "DANE"
.pp
-Initial support for DANE (see RFC 7672 et.al.)
+Support for DANE (see RFC 7672 et.al.)
is available if
.i sendmail
is compiled with the option
.b DANE .
-Only TLSA RR 3-1-x (DANE-EE) is currently implemented.
+If OpenSSL 1.1.1 or at least 3.0.0 are used,
+then full DANE support for DANE-EE and DANE-TA
+(as required by RFC 7672)
+is available via the functions
+provided by those OpenSSL versions
+(run
+.(b
+sendmail -bt -d0.3 < /dev/null
+.)b
+and check that HAVE_SSL_CTX_dane_enable is in the output),
+otherwise support for TLSA RR 3-1-x
+is implemented directly in
+.i sendmail .
+Note: if OpenSSL functions related to DANE cause a failure,
+then the macro
+.b ${verify}
+is set to
+.b DANE_TEMP .
+This also applies if TLS cannot be initialized at all.
The option
.(b
O DANE=true
@@ -11270,8 +11272,10 @@ to
.(b
O ResolverOptions
.)b
-This requires a (preferrably local)
-validating DNS resolver which supports those options.
+This requires a DNSSEC-validating recursive resolver
+which supports those options.
+The resolver must be reachable via a trusted connection,
+hence it is best to run it locally.
If the client finds a usable TLSA RR and the check
succeeds the macro
@@ -11281,9 +11285,8 @@ is set to
All non-DNS maps are considered
.i secure
just like DNS lookups with DNSSEC.
-Be aware that the implementation might not handle all
-error conditions as required by the RFCs.
-Moreover, TLSA RRs are not looked up for some features,
+Be aware that
+TLSA RRs are not looked up for some features,
e.g.,
.i FallBackSmartHost .
.sh 2 "EAI"
@@ -11943,6 +11946,8 @@ and
.ip Z
The original envelope id (from the ESMTP transaction).
For Deliver Status Notifications only.
+.ip !
+Information for Deliver-By SMTP extension.
.pp
As an example,
the following is a queue file sent to
diff --git a/contrib/sendmail/include/libsmdb/smdb.h b/contrib/sendmail/include/libsmdb/smdb.h
index bf102695a77b..fa46b512203b 100644
--- a/contrib/sendmail/include/libsmdb/smdb.h
+++ b/contrib/sendmail/include/libsmdb/smdb.h
@@ -117,7 +117,7 @@ typedef int (*db_get_func) __P((SMDB_DATABASE *db,
** key -- The key to use.
** data -- The data to store.
** flags -- put options:
-** SMDBF_NO_OVERWRITE - Return an error if key alread
+** SMDBF_NO_OVERWRITE - Return an error if key already
** exists.
**
** Returns:
diff --git a/contrib/sendmail/include/sendmail/sendmail.h b/contrib/sendmail/include/sendmail/sendmail.h
index 6ab789bd3679..bf8f0668d697 100644
--- a/contrib/sendmail/include/sendmail/sendmail.h
+++ b/contrib/sendmail/include/sendmail/sendmail.h
@@ -118,6 +118,7 @@ extern bool filechanged __P((char *, int, struct stat *));
#define DBS_WORLDWRITABLEINCLUDEFILE 40
#define DBS_GROUPREADABLEKEYFILE 41
#define DBS_GROUPREADABLEAUTHINFOFILE 42
+#define DBS_CERTOWNER 43
/* struct defining such things */
struct dbsval
diff --git a/contrib/sendmail/include/sm/conf.h b/contrib/sendmail/include/sm/conf.h
index be9f027cac33..43bb8cfb0411 100644
--- a/contrib/sendmail/include/sm/conf.h
+++ b/contrib/sendmail/include/sm/conf.h
@@ -473,8 +473,8 @@ typedef int pid_t;
# ifndef HASGETUSERSHELL
# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */
# endif
-# if SOLARIS < 21200
-# define SIGWAIT_TAKES_1_ARG 1 /* S12 moves to UNIX V7 semantic */
+# if SOLARIS < 21140
+# define SIGWAIT_TAKES_1_ARG 1 /* S11.4 moves to UNIX V7 semantic */
# endif
# else /* SOLARIS */
@@ -1575,9 +1575,11 @@ extern void *malloc();
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) && !defined(HASFCHMOD)
# define HASFCHMOD 1 /* fchmod(2) */
# endif
+# if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 19) && !defined(HAS_GETHOSTBYNAME2)
+# define HAS_GETHOSTBYNAME2 1
+# endif
# endif /* __linux__ */
-
/*
** DELL SVR4 Issue 2.2, and others
** From Kimmo Suominen <kim@grendel.lut.fi>
diff --git a/contrib/sendmail/include/sm/fdset.h b/contrib/sendmail/include/sm/fdset.h
index b4a1e7dec87b..10f121779370 100644
--- a/contrib/sendmail/include/sm/fdset.h
+++ b/contrib/sendmail/include/sm/fdset.h
@@ -17,6 +17,7 @@
** before.
*/
+#define SM_FD_CLR(fd, pfdset) FD_CLR(fd, pfdset)
#define SM_FD_SET(fd, pfdset) FD_SET(fd, pfdset)
#define SM_FD_ISSET(fd, pfdset) FD_ISSET(fd, pfdset)
#define SM_FD_SETSIZE FD_SETSIZE
diff --git a/contrib/sendmail/include/sm/gen.h b/contrib/sendmail/include/sm/gen.h
index 4f2066fa7447..588c4b6fefca 100644
--- a/contrib/sendmail/include/sm/gen.h
+++ b/contrib/sendmail/include/sm/gen.h
@@ -89,4 +89,8 @@ typedef unsigned int SM_ATOMIC_UINT_T;
# define _FFR_8BITENVADDR 1
#endif
+#if _FFR_HAPROXY && !defined(_FFR_XCNCT)
+# define _FFR_XCNCT 1
+#endif
+
#endif /* SM_GEN_H */
diff --git a/contrib/sendmail/include/sm/ixlen.h b/contrib/sendmail/include/sm/ixlen.h
index c3090ee07bbe..16e17d6bdeac 100644
--- a/contrib/sendmail/include/sm/ixlen.h
+++ b/contrib/sendmail/include/sm/ixlen.h
@@ -27,6 +27,7 @@ extern int xleni __P((const char *));
# if USE_EAI
extern bool asciistr __P((const char *));
+extern bool asciinstr __P((const char *, size_t));
extern int uxtext_unquote __P((const char *, char *, int));
extern char *sm_lowercase __P((const char *));
extern bool utf8_valid __P((const char *, size_t));
diff --git a/contrib/sendmail/include/sm/notify.h b/contrib/sendmail/include/sm/notify.h
index 4256ea94e747..d2366db85ec1 100644
--- a/contrib/sendmail/include/sm/notify.h
+++ b/contrib/sendmail/include/sm/notify.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2021 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -10,13 +10,10 @@
#ifndef SM_NOTIFY_H
#define SM_NOTIFY_H
-/* microseconds */
-#define SM_MICROS 1000000L
-
int sm_notify_init __P((int));
int sm_notify_start __P((bool, int));
int sm_notify_stop __P((bool, int));
int sm_notify_rcv __P((char *, size_t, long));
int sm_notify_snd __P((char *, size_t));
-#endif /* ! SM_MSG_H */
+#endif /* ! SM_NOTIFY_H */
diff --git a/contrib/sendmail/include/sm/os/sm_os_openbsd.h b/contrib/sendmail/include/sm/os/sm_os_openbsd.h
index 21e0a1010852..6baa7494e1e0 100644
--- a/contrib/sendmail/include/sm/os/sm_os_openbsd.h
+++ b/contrib/sendmail/include/sm/os/sm_os_openbsd.h
@@ -18,20 +18,6 @@
#define SM_OS_NAME "openbsd"
-/*
-** Temporary HACK for newer icu4c versions which include stdbool.h:
-** pretend that it is already included
-** otherwise compilation will break because bool is then
-** redefined between the prototype declaration and
-** the function definition, e.g.,
-** lowercase.c: error: conflicting types for 'asciistr'
-** ../../include/sm/ixlen.h:29:13: note: previous declaration is here
-*/
-
-#if USE_EAI && !SM_CONF_STDBOOL_H
-# define _STDBOOL_H_ 1
-#endif
-
#define SM_CONF_SYS_CDEFS_H 1
#ifndef SM_CONF_SHM
# define SM_CONF_SHM 1
diff --git a/contrib/sendmail/include/sm/rpool.h b/contrib/sendmail/include/sm/rpool.h
index 833474d9c911..b4645d62cf5c 100644
--- a/contrib/sendmail/include/sm/rpool.h
+++ b/contrib/sendmail/include/sm/rpool.h
@@ -163,6 +163,8 @@ extern void *
sm_rpool_malloc __P((
SM_RPOOL_T *_rpool,
size_t _size));
+# define sm_rpool_malloc_tagged(rpool, size, file, line, group) sm_rpool_malloc(rpool, size)
+# define sm_rpool_malloc_tagged_x(rpool, size, file, line, group) sm_rpool_malloc_x(rpool, size)
# endif /* SM_HEAP_CHECK */
#if DO_NOT_USE_STRCPY
diff --git a/contrib/sendmail/libmilter/README b/contrib/sendmail/libmilter/README
index 73953823b670..5cc20433be6e 100644
--- a/contrib/sendmail/libmilter/README
+++ b/contrib/sendmail/libmilter/README
@@ -15,6 +15,7 @@ the milter API.
Note: if you want to write a milter in Java, then see
http://sendmail-jilter.sourceforge.net/
+
+----------------+
| SECURITY HINTS |
+----------------+
@@ -26,6 +27,7 @@ if really necessary. A milter should probably check first whether
it runs as root and refuse to start in that case. libmilter will
not unlink a socket when running as root.
+
+----------------------+
| CONFIGURATION MACROS |
+----------------------+
@@ -36,6 +38,7 @@ features of the C compiler and standard C libraries.
SM_CONF_POLL
Set to 1 if poll(2) should be used instead of select(2).
+
+-------------------+
| BUILDING A FILTER |
+-------------------+
diff --git a/contrib/sendmail/libmilter/docs/overview.html b/contrib/sendmail/libmilter/docs/overview.html
index 5bbdc2f96a85..e5d1b908c010 100644
--- a/contrib/sendmail/libmilter/docs/overview.html
+++ b/contrib/sendmail/libmilter/docs/overview.html
@@ -60,7 +60,7 @@ returns to <CODE>MESSAGE</CODE>.
For each of N connections
{
For each filter
- egotiate MTA/milter capabilities/requirements (<A HREF="xxfi_negotiate.html">xxfi_negotiate</A>)
+ negotiate MTA/milter capabilities/requirements (<A HREF="xxfi_negotiate.html">xxfi_negotiate</A>)
For each filter
process connection (<A HREF="xxfi_connect.html">xxfi_connect</A>)
For each filter
diff --git a/contrib/sendmail/libmilter/docs/smfi_getsymval.html b/contrib/sendmail/libmilter/docs/smfi_getsymval.html
index 7e3e4d559434..71e9f2fec02d 100644
--- a/contrib/sendmail/libmilter/docs/smfi_getsymval.html
+++ b/contrib/sendmail/libmilter/docs/smfi_getsymval.html
@@ -76,13 +76,18 @@ By default, the following macros are valid in the given contexts:
<TR><TD>xxfi_eom</TD> <TD>msg_id</TD></TR>
</TABLE>
<P>
-All macros stay in effect from the point they are received
-until the end of the connection for the first two sets,
-the end of the message for the third (xxfi_envfrom) and last (xxfi_eom),
-and just for each recipient for xxfi_envrcpt.
+All macros stay in effect from the point they are received until
+<UL>
+<LI>the end of the connection for the first two sets,
+<LI>just for each recipient for xxfi_envrcpt.
+<LI>and the end of the message for the rest.
+</UL>
<P>
-The macro list can be changed using the confMILTER_MACROS_* options in
-sendmail.mc.
+The macro list can be changed using
+the confMILTER_MACROS_* options in sendmail.mc
+or via the
+<A HREF="smfi_setsymlist.html">smfi_setsymlist</A>
+function.
The scopes of such macros will be determined by when they are set by sendmail.
For descriptions of macros' values,
please see the
diff --git a/contrib/sendmail/libmilter/docs/smfi_replacebody.html b/contrib/sendmail/libmilter/docs/smfi_replacebody.html
index 0842298bc62c..b6dae6b61bcc 100644
--- a/contrib/sendmail/libmilter/docs/smfi_replacebody.html
+++ b/contrib/sendmail/libmilter/docs/smfi_replacebody.html
@@ -45,7 +45,7 @@ body.
<TD>Opaque context structure.
</TD></TR>
<TR valign="top"><TD>bodyp</TD>
- <TD>A pointer to the start of the new body data, which does not have to be null-terminated. If bodyp is NULL, it is treated as having length == 0. Body data should be in CR/LF form.
+ <TD>A pointer to the start of the new body data, which does not have to be null-terminated. If bodyp is NULL, it is treated as having length == 0. Body data should be in CRLF form.
</TD></TR>
<TR valign="top"><TD>bodylen</TD>
<TD>The number of data bytes pointed to by bodyp.
diff --git a/contrib/sendmail/libmilter/docs/xxfi_body.html b/contrib/sendmail/libmilter/docs/xxfi_body.html
index 511eeb3aae68..aee7526c0339 100644
--- a/contrib/sendmail/libmilter/docs/xxfi_body.html
+++ b/contrib/sendmail/libmilter/docs/xxfi_body.html
@@ -64,7 +64,7 @@ Hence even if a trailing '\0' is added, C string functions may still fail
to work as expected.
<LI>Since message bodies can be very large, defining xxfi_body can
significantly impact filter performance.
-<LI>End-of-lines are represented as received from SMTP (normally CR/LF).
+<LI>End-of-lines are represented as received from SMTP (normally CRLF).
<LI>Later filters will see body changes made by earlier ones.
<LI>Message bodies may be sent in multiple chunks, with one call to
xxfi_body per chunk.
diff --git a/contrib/sendmail/libmilter/docs/xxfi_header.html b/contrib/sendmail/libmilter/docs/xxfi_header.html
index bccada7e524f..cb5e03aa17f6 100644
--- a/contrib/sendmail/libmilter/docs/xxfi_header.html
+++ b/contrib/sendmail/libmilter/docs/xxfi_header.html
@@ -48,8 +48,8 @@ Handle a message header.
<TD>Header field value.
The content of the header may include folded white space,
i.e., multiple lines with following white space
- where lines are separated by LF (not CR/LF).
- The trailing line terminator (CR/LF) is removed.
+ where lines are separated by LF (not CRLF).
+ The trailing line terminator (CRLF) is removed.
</TD></TR>
</TABLE>
</TD></TR>
diff --git a/contrib/sendmail/libmilter/engine.c b/contrib/sendmail/libmilter/engine.c
index 5872c166ce0a..9a3f5e99eff2 100644
--- a/contrib/sendmail/libmilter/engine.c
+++ b/contrib/sendmail/libmilter/engine.c
@@ -60,32 +60,32 @@ typedef struct cmdfct_t cmdfct;
#define CI_MAIL 2
#define CI_RCPT 3
#define CI_DATA 4
-#define CI_EOM 5
-#define CI_EOH 6
-#define CI_LAST CI_EOH
+#define CI_EOH 5
+#define CI_EOM 6
+#define CI_LAST CI_EOM
#if CI_LAST < CI_DATA
-# ERROR "do not compile with CI_LAST < CI_DATA"
+# error "do not compile with CI_LAST < CI_DATA"
#endif
#if CI_LAST < CI_EOM
-# ERROR "do not compile with CI_LAST < CI_EOM"
+# error "do not compile with CI_LAST < CI_EOM"
#endif
#if CI_LAST < CI_EOH
-# ERROR "do not compile with CI_LAST < CI_EOH"
+# error "do not compile with CI_LAST < CI_EOH"
#endif
#if CI_LAST < CI_RCPT
-# ERROR "do not compile with CI_LAST < CI_RCPT"
+# error "do not compile with CI_LAST < CI_RCPT"
#endif
#if CI_LAST < CI_MAIL
-# ERROR "do not compile with CI_LAST < CI_MAIL"
+# error "do not compile with CI_LAST < CI_MAIL"
#endif
#if CI_LAST < CI_HELO
-# ERROR "do not compile with CI_LAST < CI_HELO"
+# error "do not compile with CI_LAST < CI_HELO"
#endif
#if CI_LAST < CI_CONN
-# ERROR "do not compile with CI_LAST < CI_CONN"
+# error "do not compile with CI_LAST < CI_CONN"
#endif
#if CI_LAST >= MAX_MACROS_ENTRIES
-# ERROR "do not compile with CI_LAST >= MAX_MACROS_ENTRIES"
+# error "do not compile with CI_LAST >= MAX_MACROS_ENTRIES"
#endif
/* function prototypes */
@@ -111,7 +111,7 @@ static int dec_arg2 __P((char *, size_t, char **, char **));
static void mi_clr_symlist __P((SMFICTX_PTR));
#if _FFR_WORKERS_POOL
-static bool mi_rd_socket_ready __P((int));
+static bool mi_rd_socket_ready __P((int));
#endif
/* states */
diff --git a/contrib/sendmail/libsm/Makefile.m4 b/contrib/sendmail/libsm/Makefile.m4
index 173427970f62..a7c624068c0f 100644
--- a/contrib/sendmail/libsm/Makefile.m4
+++ b/contrib/sendmail/libsm/Makefile.m4
@@ -45,7 +45,6 @@ dnl ? smcheck(`t-isprint', `compile-run')
smcheck(`t-ixlen', `compile')
smcheck(`t-ixlen.sh', `run')
smcheck(`t-streq', `compile')
-smcheck(`t-utf8_valid', `compile')
smcheck(`t-streq.sh', `run')
divert(bldTARGETS_SECTION)
divert(0)
diff --git a/contrib/sendmail/libsm/README b/contrib/sendmail/libsm/README
index 37345e05b111..7a1bfba181e7 100644
--- a/contrib/sendmail/libsm/README
+++ b/contrib/sendmail/libsm/README
@@ -34,6 +34,7 @@ The programs are:
b-strcmp.c tests strcasecmp().
+
+----------------------+
| CONFIGURATION MACROS |
+----------------------+
@@ -106,9 +107,6 @@ SM_CONF_SEM
SM_CONF_BROKEN_STRTOD
Set to 1 if your strtod() does not work properly.
-SM_CONF_GETOPT
- Set to 1 if your operating system does not include getopt(3).
-
SM_CONF_LDAP_INITIALIZE
Set to 1 if your LDAP client libraries include ldap_initialize(3).
diff --git a/contrib/sendmail/libsm/b-strl.c b/contrib/sendmail/libsm/b-strl.c
index 1e0e770cf62b..b70b28245759 100644
--- a/contrib/sendmail/libsm/b-strl.c
+++ b/contrib/sendmail/libsm/b-strl.c
@@ -101,7 +101,7 @@ main(argc, argv)
** the copy.
*/
(void) strlcpy(source,
- " This is the longer string that will be used for catenation and copying for the the performace testing. The longer the string being catenated or copied the greater the difference in measureable performance\n",
+ " This is the longer string that will be used for catenation and copying for the the performance testing. The longer the string being catenated or copied the greater the difference in measureable performance\n",
SRC_SIZE - 1);
/* Run-time comments to the user */
diff --git a/contrib/sendmail/libsm/exc.html b/contrib/sendmail/libsm/exc.html
index d9b7941f65c5..45253928faa2 100644
--- a/contrib/sendmail/libsm/exc.html
+++ b/contrib/sendmail/libsm/exc.html
@@ -350,7 +350,7 @@ of type SM_EXC_TYPE_T, which has the following members:
<dt><tt>"E"</tt>
<dd>The function could not complete its task because an error occurred.
(It might be useful to define subclasses of this category,
- in which case our taxonony becomes a tree, and 'F' becomes
+ in which case our taxonomy becomes a tree, and 'F' becomes
a subclass of 'E'.)
<dt><tt>"J"</tt>
diff --git a/contrib/sendmail/libsm/heap.c b/contrib/sendmail/libsm/heap.c
index 330739acef22..1192c461308a 100644
--- a/contrib/sendmail/libsm/heap.c
+++ b/contrib/sendmail/libsm/heap.c
@@ -242,7 +242,7 @@ size_t SmHeapMaxTotal = 0;
*/
SM_DEBUG_T SmHeapLimit = SM_DEBUG_INITIALIZER("sm_heap_limit",
- "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $");
+ "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $");
/*
** This is the data structure that keeps track of all currently
diff --git a/contrib/sendmail/libsm/io.html b/contrib/sendmail/libsm/io.html
index 3efdfebb58c7..97b7cbf37787 100644
--- a/contrib/sendmail/libsm/io.html
+++ b/contrib/sendmail/libsm/io.html
@@ -481,7 +481,7 @@ close file descriptors 0, 1 and 2).
Thus <tt>sm_io_open()</tt> should
never be called: the named file pointers should be used directly.
Calls to <b>stdio</b> are safe to make when using these three<b>sm_io</b>
-file pointers though no code is shared between the two libaries.
+file pointers though no code is shared between the two libraries.
However, the input and output between <i>sm_io</i> and <i>stdio</i> is
coordinated for these three file pointers: <i>smiostdin</i>,
<i>smiostdout</i> and <i>smiostderr</i> are layered on-top-of
@@ -574,10 +574,12 @@ SM_FILE_T. The file pointer content (internal structure members) of an active
file should only be set and observed with the "info" functions.
The two exceptions to the above statement are the structure members
<i>cookie</i> and <i>ival</i>. <i>Cookie</i> is of type <tt>void *</tt>
-while <i>ival</i> is of type <tt>int</tt>. These two structure members exist
-specificly for your created file type to use. The <i>sm_io</i> functions
-will not change or set these two structure members; only specific file type
-will change or set these variables.
+while <i>ival</i> is of type <tt>int</tt>.
+These two structure members exist specifically
+for your created file type to use.
+The <i>sm_io</i> functions
+will not change or set these two structure members;
+only specific file type will change or set these variables.
</p>
<p>
For maintaining information privately about status for a file type the
@@ -598,7 +600,7 @@ For the <i>cookie</i> to be passed to all members of a function type
cleanly the location of the cookie must assigned during
the call to open. The file type functions should not attempt to
maintain the <i>cookie</i> internally since the file type may have
-serveral instances (file pointers).
+several instances (file pointers).
</p>
<p>
The SM_FILE_T's member <i>ival</i> may be used in a manner similar to
diff --git a/contrib/sendmail/libsm/ldap.c b/contrib/sendmail/libsm/ldap.c
index a78ab4daa567..cf5aa18ab9d7 100644
--- a/contrib/sendmail/libsm/ldap.c
+++ b/contrib/sendmail/libsm/ldap.c
@@ -36,6 +36,8 @@ SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
static bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *));
static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *));
+static char *sm_ldap_geterror __P((LDAP *));
+
/*
** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
**
@@ -49,10 +51,10 @@ static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **,
# if _FFR_LDAP_VERSION
# if defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX
-# ERROR "_FFR_LDAP_VERSION > LDAP_VERSION_MAX"
+# error "_FFR_LDAP_VERSION > LDAP_VERSION_MAX"
# endif
# if defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN
-# ERROR "_FFR_LDAP_VERSION < LDAP_VERSION_MAX"
+# error "_FFR_LDAP_VERSION < LDAP_VERSION_MAX"
# endif
# define SM_LDAP_VERSION_DEFAULT _FFR_LDAP_VERSION
# else /* _FFR_LDAP_VERSION */
@@ -79,6 +81,9 @@ sm_ldap_clear(lmap)
lmap->ldap_options = 0;
# endif
lmap->ldap_attrsep = '\0';
+# if LDAP_NETWORK_TIMEOUT
+ lmap->ldap_networktmo = 0;
+# endif
lmap->ldap_binddn = NULL;
lmap->ldap_secret = NULL;
lmap->ldap_method = LDAP_AUTH_SIMPLE;
@@ -229,6 +234,23 @@ sm_ldap_setopts(ld, lmap)
# ifdef LDAP_OPT_RESTART
ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
# endif
+# if _FFR_TESTS
+ if (sm_debug_active(&SmLDAPTrace, 101))
+ {
+ char *cert;
+ char buf[PATH_MAX];
+
+ cert = getcwd(buf, sizeof(buf));
+ if (NULL != cert)
+ {
+ int r;
+
+ (void) sm_strlcat(buf, "/ldaps.pem", sizeof(buf));
+ r = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, cert);
+ sm_dprintf("LDAP_OPT_X_TLS_CACERTFILE(%s)=%d\n", cert, r);
+ }
+ }
+# endif /* _FFR_TESTS */
# else /* USE_LDAP_SET_OPTION */
/* From here on in we can use ldap internal timelimits */
@@ -305,6 +327,7 @@ sm_ldap_start(name, lmap)
{
int save_errno = 0;
char *id;
+ char *errmsg;
# if !USE_LDAP_INIT || !LDAP_NETWORK_TIMEOUT
SM_EVENT *ev = NULL;
# endif
@@ -312,6 +335,7 @@ sm_ldap_start(name, lmap)
struct timeval tmo;
int msgid, err, r;
+ errmsg = NULL;
if (sm_debug_active(&SmLDAPTrace, 2))
sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
@@ -439,37 +463,66 @@ sm_ldap_start(name, lmap)
lmap->ldap_method);
save_errno = errno;
if (sm_debug_active(&SmLDAPTrace, 9))
- sm_dprintf("ldap_bind(%s)=%d, errno=%d, tmo=%ld\n",
+ {
+ errmsg = sm_ldap_geterror(ld);
+ sm_dprintf("ldap_bind(%s)=%d, errno=%d, ldaperr=%d, ld_error=%s, tmo=%lld\n",
lmap->ldap_uri, msgid, save_errno,
- (long) tmo.tv_sec);
+ sm_ldap_geterrno(ld), errmsg, (long long) tmo.tv_sec);
+ if (NULL != errmsg)
+ {
+ ldap_memfree(errmsg);
+ errmsg = NULL;
+ }
+ }
if (-1 == msgid)
{
r = -1;
+ err = sm_ldap_geterrno(ld);
+ if (LDAP_SUCCESS != err)
+ save_errno = err + E_LDAPBASE;
goto fail;
}
errno = 0;
r = ldap_result(ld, msgid, LDAP_MSG_ALL,
tmo.tv_sec == 0 ? NULL : &(tmo), &(lmap->ldap_res));
+ save_errno = errno;
if (sm_debug_active(&SmLDAPTrace, 9))
- sm_dprintf("ldap_result(%s)=%d, errno=%d\n", lmap->ldap_uri, r, errno);
+ {
+ errmsg = sm_ldap_geterror(ld);
+ sm_dprintf("ldap_result(%s)=%d, errno=%d, ldaperr=%d, ld_error=%s\n",
+ lmap->ldap_uri, r, errno,
+ sm_ldap_geterrno(ld), errmsg);
+ if (NULL != errmsg)
+ {
+ ldap_memfree(errmsg);
+ errmsg = NULL;
+ }
+ }
if (-1 == r)
+ {
+ err = sm_ldap_geterrno(ld);
+ if (LDAP_SUCCESS != err)
+ save_errno = err + E_LDAPBASE;
goto fail;
+ }
if (0 == r)
{
save_errno = ETIMEDOUT;
r = -1;
goto fail;
}
- r = ldap_parse_result(ld, lmap->ldap_res, &err, NULL, NULL, NULL, NULL,
- 1);
+ r = ldap_parse_result(ld, lmap->ldap_res, &err, NULL, &errmsg, NULL,
+ NULL, 1);
+ save_errno = errno;
if (sm_debug_active(&SmLDAPTrace, 9))
- sm_dprintf("ldap_parse_result(%s)=%d, err=%d\n", lmap->ldap_uri, r, err);
+ sm_dprintf("ldap_parse_result(%s)=%d, err=%d, errmsg=%s\n",
+ lmap->ldap_uri, r, err, errmsg);
if (r != LDAP_SUCCESS)
goto fail;
if (err != LDAP_SUCCESS)
{
- r = -1;
+ r = err;
goto fail;
}
@@ -487,12 +540,22 @@ sm_ldap_start(name, lmap)
errno = save_errno;
else
errno = r + E_LDAPBASE;
+ if (NULL != errmsg)
+ {
+ ldap_memfree(errmsg);
+ errmsg = NULL;
+ }
return false;
}
/* Save PID to make sure only this PID closes the LDAP connection */
lmap->ldap_pid = getpid();
lmap->ldap_ld = ld;
+ if (NULL != errmsg)
+ {
+ ldap_memfree(errmsg);
+ errmsg = NULL;
+ }
return true;
}
@@ -536,7 +599,7 @@ sm_ldap_search_m(lmap, argv)
if (lmap->ldap_multi_args)
{
# if SM_LDAP_ARGS < 10
-# ERROR _SM_LDAP_ARGS must be 10
+# error _SM_LDAP_ARGS must be 10
# endif
if (q[1] == 's')
key = argv[0];
@@ -1559,7 +1622,6 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
**
** Returns:
** None.
-**
*/
void
@@ -1574,6 +1636,7 @@ sm_ldap_close(lmap)
lmap->ldap_ld = NULL;
lmap->ldap_pid = 0;
}
+
/*
** SM_LDAP_GETERRNO -- get ldap errno value
**
@@ -1582,7 +1645,6 @@ sm_ldap_close(lmap)
**
** Returns:
** LDAP errno.
-**
*/
int
@@ -1614,4 +1676,28 @@ sm_ldap_geterrno(ld)
# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
return err;
}
+
+/*
+** SM_LDAP_GETERROR -- get ldap error value
+**
+** Parameters:
+** ld -- LDAP session handle
+**
+** Returns:
+** LDAP error
+*/
+
+static char *
+sm_ldap_geterror(ld)
+ LDAP *ld;
+{
+ char *error = NULL;
+
+# if defined(LDAP_OPT_DIAGNOSTIC_MESSAGE)
+ (void) ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &error);
+# endif
+ return error;
+}
+
+
#endif /* LDAPMAP */
diff --git a/contrib/sendmail/libsm/lowercase.c b/contrib/sendmail/libsm/lowercase.c
index 8448eee5ad40..430d2ac79039 100644
--- a/contrib/sendmail/libsm/lowercase.c
+++ b/contrib/sendmail/libsm/lowercase.c
@@ -15,10 +15,11 @@
#include <sm/string.h>
#include <sm/heap.h>
#if USE_EAI
-# include <sm/ixlen.h>
+# include <sm/limits.h>
# include <unicode/ucasemap.h>
# include <unicode/ustring.h>
# include <unicode/uchar.h>
+# include <sm/ixlen.h>
/*
** ASCIISTR -- check whether a string is printable ASCII
@@ -42,6 +43,38 @@ asciistr(str)
str++;
return ch == '\0';
}
+
+/*
+** ASCIINSTR -- check whether a string is printable ASCII up to len
+**
+** Parameters:
+** str -- string
+** len -- length to check
+**
+** Returns:
+** TRUE iff printable ASCII
+*/
+
+bool
+asciinstr(str, len)
+ const char *str;
+ size_t len;
+{
+ unsigned char ch;
+ int n;
+
+ if (str == NULL)
+ return true;
+ SM_REQUIRE(len < INT_MAX);
+ n = 0;
+ while (n < len && (ch = (unsigned char)*str) != '\0'
+ && ch >= 32 && ch < 127)
+ {
+ n++;
+ str++;
+ }
+ return n == len || ch == '\0';
+}
#endif /* USE_EAI */
/*
diff --git a/contrib/sendmail/libsm/mpeix.c b/contrib/sendmail/libsm/mpeix.c
index 3fe361709f69..e80f23d510a7 100644
--- a/contrib/sendmail/libsm/mpeix.c
+++ b/contrib/sendmail/libsm/mpeix.c
@@ -314,7 +314,7 @@ sendmail_mpe_getpwnam(name)
/*
** SENDMAIL_MPE_GETPWUID -- shadow function for getpwuid()
**
-** Initializes the uninitalized fields in the passwd struct.
+** Initializes the uninitialized fields in the passwd struct.
**
** Parameters:
** uid -- uid to obtain passwd data for
diff --git a/contrib/sendmail/libsm/notify.c b/contrib/sendmail/libsm/notify.c
index 4ed3fd7f2bd1..8b35d9e3839a 100644
--- a/contrib/sendmail/libsm/notify.c
+++ b/contrib/sendmail/libsm/notify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2020 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -10,11 +10,12 @@
#include <sm/gen.h>
-#if _FFR_DMTRIGGER
+#if _FFR_DMTRIGGER && _FFR_NOTIFY < 2
#include <sm/conf.h> /* FDSET_CAST */
#include <sm/fdset.h>
#include <sm/assert.h>
#include <sm/notify.h>
+#include "notify.h"
#include <sm/time.h>
#include <sm/string.h>
@@ -28,12 +29,6 @@
#include <fcntl.h>
#include <string.h> /* for memset() */
-#if SM_NOTIFY_DEBUG
-#define SM_DBG(p) fprintf p
-#else
-#define SM_DBG(p)
-#endif
-
static int Notifypipe[2];
#define NotifyRDpipe Notifypipe[0]
#define NotifyWRpipe Notifypipe[1]
@@ -129,9 +124,6 @@ sm_notify_stop(owner, flags)
** <0: -errno
*/
-#define MAX_NETSTR 1024
-#define NETSTRPRE 5
-
int
sm_notify_snd(buf, buflen)
char *buf;
@@ -152,7 +144,7 @@ sm_notify_snd(buf, buflen)
len = sm_snprintf(netstr, sizeof(netstr), "%04d:%s,", (int)buflen, buf);
r = write(NotifyWRpipe, netstr, len);
save_errno = errno;
- SM_DBG((stderr, "write=%d, fd=%d, e=%d\n", r, NotifyWRpipe, save_errno));
+ SM_DBG((stderr, "pid=%ld, write=%d, fd=%d, e=%d\n", (long)getpid(), r, NotifyWRpipe, save_errno));
return r >= 0 ? 0 : -save_errno;
}
@@ -165,7 +157,8 @@ sm_notify_snd(buf, buflen)
** tmo -- timeout (micro seconds)
**
** Returns:
-** 0: success
+** 0: EOF (XXX need to provide info about client)
+** >0: length of received data
** <0: -errno
*/
@@ -186,55 +179,14 @@ sm_notify_rcv(buf, buflen, tmo)
return -EINVAL;
FD_ZERO(&readfds);
SM_FD_SET(NotifyRDpipe, &readfds);
- if (tmo < 0)
- tval = NULL;
- else
- {
- timeout.tv_sec = (long) (tmo / SM_MICROS);
- timeout.tv_usec = tmo % SM_MICROS;
- tval = &timeout;
- }
+ SM_MICROS2TVAL(tmo, tval, timeout);
do {
r = select(NotifyRDpipe + 1, FDSET_CAST &readfds, NULL, NULL, tval);
save_errno = errno;
- SM_DBG((stderr, "select=%d, fd=%d, e=%d\n", r, NotifyRDpipe, save_errno));
+ SM_DBG((stderr, "pid=%ld, select=%d, fd=%d, e=%d\n", (long)getpid(), r, NotifyRDpipe, save_errno));
} while (r < 0 && save_errno == EINTR);
- if (r <= 0)
- {
- SM_DBG((stderr, "select=%d, e=%d\n", r, save_errno));
- return -ETIMEDOUT;
- }
-
- /* bogus... need to check again? */
- if (!FD_ISSET(NotifyRDpipe, &readfds))
- return -ETIMEDOUT;
-
- r = read(NotifyRDpipe, buf, NETSTRPRE);
- if (NETSTRPRE != r)
- return -1; /* ??? */
-
- if (sm_io_sscanf(buf, "%4u:", &len) != 1)
- return -EINVAL; /* ??? */
- if (len >= MAX_NETSTR)
- return -E2BIG; /* ??? */
- if (len >= buflen - 1)
- return -E2BIG; /* ??? */
- if (len <= 0)
- return -EINVAL; /* ??? */
- r = read(NotifyRDpipe, buf, len + 1);
- save_errno = errno;
- SM_DBG((stderr, "read=%d, e=%d\n", r, save_errno));
- if (r == 0)
- return -1; /* ??? */
- if (r < 0)
- return -save_errno;
- if (len + 1 != r)
- return -1; /* ??? */
- if (buf[len] != ',')
- return -EINVAL; /* ??? */
- buf[len] = '\0';
- return r;
+ RDNETSTR(r, NotifyRDpipe, (void)0);
}
-#endif /* _FFR_DMTRIGGER */
+#endif /* _FFR_DMTRIGGER && _FFR_NOTIFY < 2 */
diff --git a/contrib/sendmail/libsm/notify.h b/contrib/sendmail/libsm/notify.h
new file mode 100644
index 000000000000..a314e75a4bb2
--- /dev/null
+++ b/contrib/sendmail/libsm/notify.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2021 Proofpoint, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ */
+
+#ifndef LIBSM_NOTIFY_H
+#define LIBSM_NOTIFY_H
+
+#if SM_NOTIFY_DEBUG
+#define SM_DBG(p) fprintf p
+#else
+#define SM_DBG(p)
+#endif
+
+/* microseconds */
+#define SM_MICROS 1000000L
+
+#define SM_MICROS2TVAL(tmo, tval, timeout) \
+ do \
+ { \
+ if (tmo < 0) \
+ tval = NULL; \
+ else \
+ { \
+ timeout.tv_sec = (long) (tmo / SM_MICROS); \
+ timeout.tv_usec = tmo % SM_MICROS; \
+ tval = &timeout; \
+ } \
+ } while (0)
+
+#define MAX_NETSTR 1024
+#define NETSTRPRE 5
+
+/* flow through code, be careful how to use! */
+#define RDNETSTR(rc, fd, SM_NOTIFY_EOF) \
+ if ((rc) <= 0) \
+ { \
+ SM_DBG((stderr, "pid=%ld, select=%d, e=%d\n", (long)getpid(), (rc), save_errno)); \
+ return -ETIMEDOUT; \
+ } \
+ \
+ /* bogus... need to check again? */ \
+ if (!FD_ISSET(fd, &readfds)) \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, isset=false\n", (long)getpid(), fd)); \
+ return -ETIMEDOUT; \
+ } \
+ r = read(fd, buf, NETSTRPRE); \
+ if (0 == r) \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read1=EOF, e=%d\n", (long)getpid(), fd, errno)); \
+ SM_NOTIFY_EOF; \
+ return r; \
+ } \
+ if (NETSTRPRE != r) \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read1=%d, e=%d\n", (long)getpid(), fd, r, errno)); \
+ return -1; /* ??? */ \
+ } \
+ \
+ if (sm_io_sscanf(buf, "%4u:", &len) != 1) \
+ { \
+ SM_DBG((stderr, "pid=%ld, scanf, e=%d\n", (long)getpid(), errno)); \
+ return -EINVAL; /* ??? */ \
+ } \
+ if (len >= MAX_NETSTR) \
+ { \
+ SM_DBG((stderr, "pid=%ld, 1: len=%d\n", (long)getpid(), len)); \
+ return -E2BIG; /* ??? */ \
+ } \
+ if (len >= buflen - 1) \
+ { \
+ SM_DBG((stderr, "pid=%ld, 2: len=%d\n", (long)getpid(), len)); \
+ return -E2BIG; /* ??? */ \
+ } \
+ if (len <= 0) \
+ { \
+ SM_DBG((stderr, "pid=%ld, 3: len=%d\n", (long)getpid(), len)); \
+ return -EINVAL; /* ??? */ \
+ } \
+ r = read(fd, buf, len + 1); \
+ save_errno = errno; \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read=%d, len=%d, e=%d\n", (long)getpid(), fd, r, len+1, save_errno)); \
+ if (r == 0) \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read2=%d, e=%d\n", (long)getpid(), fd, r, save_errno)); \
+ return -1; /* ??? */ \
+ } \
+ if (r < 0) \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read3=%d, e=%d\n", (long)getpid(), fd, r, save_errno)); \
+ return -save_errno; \
+ } \
+ if (len + 1 != r) \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read4=%d, len=%d\n", (long)getpid(), fd, r, len)); \
+ return -1; /* ??? */ \
+ } \
+ if (buf[len] != ',') \
+ { \
+ SM_DBG((stderr, "pid=%ld, fd=%d, read5=%d, f=%d\n", (long)getpid(), fd, r, buf[len])); \
+ return -EINVAL; /* ??? */ \
+ } \
+ buf[len] = '\0'; \
+ return r
+
+#endif /* ! LIBSM_MSG_H */
diff --git a/contrib/sendmail/libsm/rewind.c b/contrib/sendmail/libsm/rewind.c
index 2bbb26d2a9a9..bfbbbab4dd80 100644
--- a/contrib/sendmail/libsm/rewind.c
+++ b/contrib/sendmail/libsm/rewind.c
@@ -25,7 +25,7 @@ SM_RCSID("@(#)$Id: rewind.c,v 1.19 2013-11-22 20:51:43 ca Exp $")
** Seeks the file to the beginning and clears any outstanding errors.
**
** Parameters:
-** fp -- the flie pointer for rewind
+** fp -- the file pointer for rewind
** timeout -- time to complete the rewind
**
** Returns:
diff --git a/contrib/sendmail/libsm/setvbuf.c b/contrib/sendmail/libsm/setvbuf.c
index 85b178b60c85..092a1fc93fb0 100644
--- a/contrib/sendmail/libsm/setvbuf.c
+++ b/contrib/sendmail/libsm/setvbuf.c
@@ -17,6 +17,7 @@ SM_RCSID("@(#)$Id: setvbuf.c,v 1.33 2013-11-22 20:51:43 ca Exp $")
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
+#include <sm/limits.h>
#include <sm/io.h>
#include <sm/heap.h>
#include <sm/assert.h>
@@ -67,7 +68,7 @@ sm_io_setvbuf(fp, timeout, buf, mode, size)
if (mode != SM_IO_NBF)
if ((mode != SM_IO_FBF && mode != SM_IO_LBF &&
- mode != SM_IO_NOW) || (int) size < 0)
+ mode != SM_IO_NOW) || size > INT_MAX)
return SM_IO_EOF;
/*
diff --git a/contrib/sendmail/libsm/stdio.c b/contrib/sendmail/libsm/stdio.c
index 7e045fa56fec..2cdb0dfedbcf 100644
--- a/contrib/sendmail/libsm/stdio.c
+++ b/contrib/sendmail/libsm/stdio.c
@@ -162,7 +162,7 @@ sm_stdwrite(fp, buf, n)
/*
** SM_STDSEEK -- set the file offset position
**
-** Parmeters:
+** Parameters:
** fp -- file pointer to position
** offset -- how far to position from "base" (set by 'whence')
** whence -- indicates where the "base" of the 'offset' to start
diff --git a/contrib/sendmail/libsm/strcaseeq.c b/contrib/sendmail/libsm/strcaseeq.c
index c252d85e53e0..ec1a942e3c65 100644
--- a/contrib/sendmail/libsm/strcaseeq.c
+++ b/contrib/sendmail/libsm/strcaseeq.c
@@ -17,7 +17,7 @@
#include <sm/ixlen.h>
/*
-** SM_STRCASEEQ -- are two strings equal (case-insenstive)?
+** SM_STRCASEEQ -- are two strings equal (case-insensitive)?
**
** Parameters:
** s1 -- string
@@ -63,7 +63,7 @@ sm_strcaseeq(s1, s2)
}
/*
-** SM_STRNCASEEQ -- are two strings (up to a length) equal (case-insenstive)?
+** SM_STRNCASEEQ -- are two strings (up to a length) equal (case-insensitive)?
**
** Parameters:
** s1 -- string
@@ -86,13 +86,13 @@ sm_strncaseeq(s1, s2, n)
if (0 == n)
return true;
- if (asciistr(s1))
+ if (asciinstr(s1, n))
{
- if (!asciistr(s2))
+ if (!asciinstr(s2, n))
return false;
return (sm_strncasecmp(s1, s2, n) == 0);
}
- if (asciistr(s2))
+ if (asciinstr(s2, n))
return false;
l1 = sm_lowercase(s1);
if (l1 != s1)
@@ -104,7 +104,7 @@ sm_strncaseeq(s1, s2, n)
f1 = NULL;
l2 = sm_lowercase(s2);
- while (*l1 == *l2 && '\0' != *l1 && n-- > 0)
+ while (*l1 == *l2 && '\0' != *l1 && --n > 0)
l1++, l2++;
same = *l1 == *l2;
diff --git a/contrib/sendmail/libsm/t-ixlen.c b/contrib/sendmail/libsm/t-ixlen.c
index cc29431725a8..cdf96f04c4ad 100644
--- a/contrib/sendmail/libsm/t-ixlen.c
+++ b/contrib/sendmail/libsm/t-ixlen.c
@@ -19,6 +19,7 @@ SM_IDSTR(id, "@(#)$Id: t-qic.c,v 1.10 2013-11-22 20:51:43 ca Exp $")
#if _FFR_8BITENVADDR
extern bool SmTestVerbose;
+static int Verbose = 0;
static void
chkilenx(str, len)
@@ -30,11 +31,42 @@ chkilenx(str, len)
xlen = ilenx(str);
SM_TEST(len == xlen);
if (len != xlen)
- fprintf(stderr, "str=\"%s\", len=%d, excpected=%d\n",
+ fprintf(stderr, "str=\"%s\", len=%d, expected=%d\n",
str, xlen, len);
}
static void
+chkilen(str)
+ char *str;
+{
+ char *obp;
+ int outlen, leni, lenx, ilen;
+ char line_in[1024];
+ XLENDECL
+
+ lenx = strlen(str);
+ sm_strlcpy(line_in, str, sizeof(line_in));
+ obp = quote_internal_chars(str, NULL, &outlen, NULL);
+ leni = strlen(obp);
+
+ for (ilen = 0; *obp != '\0'; obp++, ilen++)
+ {
+ XLEN(*obp);
+ }
+ if (Verbose)
+ fprintf(stderr, "str=\"%s\", ilen=%d, xlen=%d\n",
+ str, ilen, xlen);
+ SM_TEST(ilen == leni);
+ if (ilen != leni)
+ fprintf(stderr, "str=\"%s\", ilen=%d, leni=%d\n",
+ str, ilen, leni);
+ SM_TEST(xlen == lenx);
+ if (xlen != lenx)
+ fprintf(stderr, "str=\"%s\", xlen=%d, lenx=%d\n",
+ str, xlen, lenx);
+}
+
+static void
chkxleni(str, len)
const char *str;
int len;
@@ -44,7 +76,7 @@ chkxleni(str, len)
ilen = xleni(str);
SM_TEST(len == ilen);
if (len != ilen)
- fprintf(stderr, "str=\"%s\", len=%d, excpected=%d\n",
+ fprintf(stderr, "str=\"%s\", len=%d, expected=%d\n",
str, ilen, len);
}
@@ -64,18 +96,26 @@ main(argc, argv)
char *argv[];
{
int o, len;
- bool x;
+ bool x, both;
char line[1024];
- x = false;
- while ((o = getopt(argc, argv, "x")) != -1)
+ x = both = false;
+ while ((o = getopt(argc, argv, "bxV")) != -1)
{
switch ((char) o)
{
+ case 'b':
+ both = true;
+ break;
+
case 'x':
x = true;
break;
+ case 'V':
+ Verbose++;
+ break;
+
default:
usage(argv[0]);
exit(1);
@@ -84,6 +124,12 @@ main(argc, argv)
sm_test_begin(argc, argv, "test ilenx");
+ if (both)
+ {
+ while (fscanf(stdin, "%s\n", line) == 1)
+ chkilen(line);
+ return sm_test_end();
+ }
while (fscanf(stdin, "%d:%s\n", &len, line) == 2)
{
if (x)
diff --git a/contrib/sendmail/libsm/t-notify.c b/contrib/sendmail/libsm/t-notify.c
index f8da3a2fb9bc..c0a090470dc3 100644
--- a/contrib/sendmail/libsm/t-notify.c
+++ b/contrib/sendmail/libsm/t-notify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2020 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -8,7 +8,6 @@
*/
#include <sm/gen.h>
-
#include <stdio.h>
#if _FFR_DMTRIGGER || _FFR_NOTIFY
@@ -20,23 +19,32 @@
# include <sm/test.h>
# include <sm/notify.h>
# include <sm/conf.h>
+# include "notify.h"
+
+static int Verbose = 0;
+#define MAX_CHILDREN 256
+#define MAX_MSGS 1024
+static pid_t pids[MAX_CHILDREN];
+static char msgs[MAX_CHILDREN][MAX_MSGS];
/*
-** NOTIFY_WR -- test of notify feature
+** NOTIFY_WR -- test of notify write feature
**
** Parameters:
** pid -- pid of process
+** nmsgs -- number of messages to write
**
** Returns:
-** 0 on success
+** >=0 on success
** < 0 on failure
*/
static int
-notify_wr(pid)
+notify_wr(pid, nmsgs)
pid_t pid;
+ int nmsgs;
{
- int r;
+ int r, i;
size_t len;
char buf[64];
#define TSTSTR "qf0001"
@@ -48,16 +56,38 @@ notify_wr(pid)
return -1;
}
- len = sm_snprintf(buf, sizeof(buf), "%s-%ld", TSTSTR, (long) pid);
- r = sm_notify_snd(buf, len);
- SM_TEST(r >= 0);
+ for (i = 0; i < nmsgs; i++)
+ {
+ len = sm_snprintf(buf, sizeof(buf), "%s-%ld_%d", TSTSTR,
+ (long) pid, i);
+ r = sm_notify_snd(buf, len);
+ SM_TEST(r >= 0);
+ }
return r;
}
+static int
+validpid(nproc, cpid)
+ int nproc;
+ pid_t cpid;
+{
+ int i;
+
+ for (i = 0; i < nproc; i++)
+ if (cpid == pids[i])
+ return i;
+ if (Verbose > 0)
+ fprintf(stderr, "pid=%ld not found, nproc=%d\n",
+ (long) cpid, nproc);
+ return -1;
+}
+
/*
-** NOTIFY_RD -- test of notify feature
+** NOTIFY_RD -- test of notify read feature
**
** Parameters:
+** nproc -- number of processes started
+** nmsgs -- number of messages to read for each process
**
** Returns:
** 0 on success
@@ -65,11 +95,13 @@ notify_wr(pid)
*/
static int
-notify_rd(nproc)
+notify_rd(nproc, nmsgs)
int nproc;
+ int nmsgs;
{
- int r, i;
- char buf[64];
+ int r, i, pidx;
+ long cpid;
+ char buf[64], *p;
#define TSTSTR "qf0001"
r = sm_notify_start(true, 0);
@@ -79,21 +111,52 @@ notify_rd(nproc)
return -1;
}
- for (i = 0; i < nproc; i++)
+ for (i = 0; i < nmsgs * nproc; i++)
{
- r = sm_notify_rcv(buf, sizeof(buf), 5 * SM_MICROS);
- SM_TEST(r >= 0);
+ do
+ {
+ r = sm_notify_rcv(buf, sizeof(buf), 5 * SM_MICROS);
+ SM_TEST(r >= 0);
+ } while (0 == r);
if (r < 0)
{
- fprintf(stderr, "rcv=%d\n", r);
+ fprintf(stderr, "pid=%ld, rcv=%d, i=%d\n",
+ (long)getpid(), r, i);
return r;
}
if (r > 0 && r < sizeof(buf))
buf[r] = '\0';
buf[sizeof(buf) - 1] = '\0';
+
+ if (Verbose > 0)
+ fprintf(stderr, "pid=%ld, buf=\"%s\", i=%d\n",
+ (long)getpid(), buf, i);
+
SM_TEST(strncmp(buf, TSTSTR, sizeof(TSTSTR) - 1) == 0);
SM_TEST(r > sizeof(TSTSTR));
- fprintf(stderr, "buf=\"%s\"\n", buf);
+
+ r = sscanf(buf + sizeof(TSTSTR), "%ld", &cpid);
+ SM_TEST(1 == r);
+ pidx = validpid(nproc, (pid_t)cpid);
+ SM_TEST(pidx >= 0);
+ SM_TEST(pidx < nproc);
+
+ p = strchr(buf, '_');
+ SM_TEST(NULL != p);
+ if (NULL != p && pidx < nproc && pidx >= 0)
+ {
+ int n;
+
+ r = sscanf(p + 1, "%d", &n);
+ SM_TEST(1 == r);
+ SM_TEST(n >= 0);
+ SM_TEST(n < nmsgs);
+ if (1 == r && n < nmsgs && n >= 0)
+ {
+ SM_TEST('\0' == msgs[pidx][n]);
+ msgs[pidx][n] = 'f';
+ }
+ }
}
return 0;
}
@@ -106,27 +169,53 @@ main(argc, argv)
int i;
int r = 0;
int nproc = 1;
+ int nmsgs = 1;
pid_t pid;
-# define OPTIONS "p:"
+# define OPTIONS "n:p:V"
while ((i = getopt(argc, argv, OPTIONS)) != -1)
{
switch ((char) i)
{
+ case 'n':
+ nmsgs = atoi(optarg);
+ if (nmsgs < 1)
+ {
+ errno = EINVAL;
+ fprintf(stderr, "-%c: must be >0\n", (char) i);
+ return 1;
+ }
+ if (nmsgs >= MAX_MSGS)
+ {
+ errno = EINVAL;
+ fprintf(stderr, "-%c: must be <%d\n", (char) i, MAX_MSGS);
+ return 1;
+ }
+ break;
case 'p':
nproc = atoi(optarg);
if (nproc < 1)
{
errno = EINVAL;
- perror("-p: must be >0\n");
- return r;
+ fprintf(stderr, "-%c: must be >0\n", (char) i);
+ return 1;
}
+ if (nproc >= MAX_CHILDREN)
+ {
+ errno = EINVAL;
+ fprintf(stderr, "-%c: must be <%d\n", (char) i, MAX_CHILDREN);
+ return 1;
+ }
+ break;
+ case 'V':
+ ++Verbose;
break;
default:
break;
}
}
+ memset(msgs, '\0', sizeof(msgs));
sm_test_begin(argc, argv, "test notify");
r = sm_notify_init(0);
SM_TEST(r >= 0);
@@ -149,12 +238,14 @@ main(argc, argv)
{
/* give the parent the chance to set up data */
sleep(1);
- r = notify_wr(getpid());
+ r = notify_wr(getpid(), nmsgs);
break;
}
+ if (pid > 0)
+ pids[i] = pid;
}
if (pid > 0)
- r = notify_rd(nproc);
+ r = notify_rd(nproc, nmsgs);
SM_TEST(r >= 0);
return sm_test_end();
}
@@ -164,7 +255,7 @@ main(argc, argv)
int argc;
char *argv[];
{
- printf("SKIPPED: no _FFR_DMTRIGGER\n");
+ printf("SKIPPED: no _FFR_DMTRIGGER || _FFR_NOTIFY\n");
return 0;
}
-#endif /* _FFR_DMTRIGGER */
+#endif /* _FFR_DMTRIGGER || _FFR_NOTIFY */
diff --git a/contrib/sendmail/libsm/t-qic.c b/contrib/sendmail/libsm/t-qic.c
index fea88c95b43d..d2b73a5cb3d6 100644
--- a/contrib/sendmail/libsm/t-qic.c
+++ b/contrib/sendmail/libsm/t-qic.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2006, 2023 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -19,7 +19,6 @@ SM_IDSTR(id, "@(#)$Id: t-qic.c,v 1.10 2013-11-22 20:51:43 ca Exp $")
extern bool SmTestVerbose;
-
void
show_diff(s1, s2)
const char *s1;
@@ -107,6 +106,8 @@ main(argc, argv)
int i, los, cmp, mode;
sm_qic_T inout[] = {
{ "", "", 0 }
+ , { "\t", "\t", 0 }
+ , { "\tuser", "\tuser", 0 }
, { "abcdef", "abcdef", 0 }
, { "01234567890123456789", "01234567890123456789", 0 }
, { "\\", "\\", 0 }
@@ -242,5 +243,16 @@ main(argc, argv)
}
}
+ los = -1;
+ obp = quote_internal_chars(NULL, NULL, &los, NULL);
+ SM_TEST(NULL == obp);
+ SM_TEST(-1 == los);
+
+ sm_strlcpy(line_in, "nothing", sizeof(line_in));
+ los = -123;
+ obp = quote_internal_chars(line_in, NULL, &los, NULL);
+ SM_TEST(NULL != obp);
+ SM_TEST(los > 0);
+
return sm_test_end();
}
diff --git a/contrib/sendmail/libsm/t-streq.c b/contrib/sendmail/libsm/t-streq.c
index a193eca5f02d..c6f369be0945 100644
--- a/contrib/sendmail/libsm/t-streq.c
+++ b/contrib/sendmail/libsm/t-streq.c
@@ -17,7 +17,6 @@ SM_IDSTR(id, "@(#)$Id: t-qic.c,v 1.10 2013-11-22 20:51:43 ca Exp $")
#include <sm/ixlen.h>
#include <sm/test.h>
-#if _FFR_8BITENVADDR
extern bool SmTestVerbose;
static int
@@ -37,6 +36,32 @@ usage(prg)
fprintf(stderr, "options:\n");
}
+static void
+hack(str)
+ char *str;
+{
+ char c;
+
+ /* replace just one \x char */
+ while ((c = *str++) != '\0')
+ {
+ if (c != '\\')
+ continue;
+ c = *str;
+ switch (c)
+ {
+ case 'n': c ='\n'; break;
+ case 't': c ='\t'; break;
+ case 'r': c ='\r'; break;
+ /* case 'X': c ='\X'; break; */
+ default: c ='\0'; break;
+ }
+ *(str - 1) = c;
+ *str = '\0';
+ break;
+ }
+}
+
int
main(argc, argv)
int argc;
@@ -61,17 +86,14 @@ main(argc, argv)
while (fscanf(stdin, "%d:%s\n", &len, s1) == 2 &&
fscanf(stdin, "%d:%s\n", &o,s2) == 2)
{
+ int r;
+
+ hack(s1);
+ hack(s2);
SM_TEST(tstrncaseeq(s1, s2, len) == o);
+ if ((r = tstrncaseeq(s1, s2, len)) != o)
+ fprintf(stderr, "\"%s\"\n\"%s\"\n%d!=%d\n", s1, s2, o, r);
}
return sm_test_end();
}
-#else /* _FFR_8BITENVADDR */
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
- return 0;
-}
-#endif /* _FFR_8BITENVADDR */
diff --git a/contrib/sendmail/libsm/t-streq.sh b/contrib/sendmail/libsm/t-streq.sh
index 7797e3f848f0..d798cf315010 100755
--- a/contrib/sendmail/libsm/t-streq.sh
+++ b/contrib/sendmail/libsm/t-streq.sh
@@ -12,6 +12,13 @@
PRG=./t-streq
R=0
+# format:
+# two lines:
+# len:string1
+# result:string2
+# result:
+# 1: equal
+# 0: not equal
${PRG} <<EOF
0:a
1:X
@@ -23,6 +30,18 @@ ${PRG} <<EOF
1:AC
2:aB
0:AC
+2:aB\n
+1:AB
+20:xabcez@uabcey.por.az\n
+1:xabcez@uabcey.por.az
+7:ünchen\n
+1:ünchen
+7:ünchen\n
+0:üncheX
+22:iseadmin@somest.sld.br>\n
+1:iseadmin@somest.sld.br
+22:iseadmin@somest.sld.br
+1:iseadmin@somest.sld.br>\n
EOF
R=$?
diff --git a/contrib/sendmail/libsm/test.c b/contrib/sendmail/libsm/test.c
index 0aee5ae4aa6b..d955909c101f 100644
--- a/contrib/sendmail/libsm/test.c
+++ b/contrib/sendmail/libsm/test.c
@@ -96,7 +96,7 @@ sm_test_begin(argc, argv, testname)
** SM_TEST -- single test.
**
** Parameters:
-** success -- did test succeeed?
+** success -- did test succeed?
** expr -- expression that has been evaluated.
** filename -- guess...
** lineno -- line number.
diff --git a/contrib/sendmail/libsm/util.c b/contrib/sendmail/libsm/util.c
index dd8bf88f79e5..2610a3dfe553 100644
--- a/contrib/sendmail/libsm/util.c
+++ b/contrib/sendmail/libsm/util.c
@@ -132,10 +132,11 @@ str2prt(s)
** ibp -- a pointer to the string to translate [x]
** obp -- a pointer to an output buffer [i][m:A]
** bsp -- pointer to the length of the output buffer
+** rpool -- rpool for allocations
**
** Returns:
-** A possibly new bp (if the buffer needed to grow); if
-** it is different, *bsp will updated to the size of
+** A possibly new obp (if the buffer needed to grow);
+** if it is different, *bsp will updated to the size of
** the new buffer and the caller is responsible for
** freeing the memory.
*/
@@ -171,7 +172,12 @@ quote_internal_chars
int bufused, olen;
bool buffer_same, needs_quoting;
+ if (NULL == ibp)
+ return NULL;
buffer_same = ibp == obp;
+ SM_REQUIRE(NULL != bsp);
+ if (NULL == obp)
+ *bsp = 0;
needs_quoting = false;
/* determine length of output string (starts at 1 for trailing '\0') */
diff --git a/contrib/sendmail/libsm/vfprintf.c b/contrib/sendmail/libsm/vfprintf.c
index e4e69edbe419..b335c4b795ed 100644
--- a/contrib/sendmail/libsm/vfprintf.c
+++ b/contrib/sendmail/libsm/vfprintf.c
@@ -74,7 +74,7 @@ sm_print(fp, timeout, uio)
}
/*
-** SM_BPRINTF -- allow formating to an unbuffered file.
+** SM_BPRINTF -- allow formatting to an unbuffered file.
**
** Helper function for `fprintf to unbuffered unix file': creates a
** temporary buffer (via a "fake" file pointer).
@@ -84,11 +84,11 @@ sm_print(fp, timeout, uio)
** Parameters:
** fp -- the file to send the o/p to
** fmt -- format instructions for the o/p
-** ap -- vectors of data units used for formating
+** ap -- vectors of data units used for formatting
**
** Results:
** Failure: SM_IO_EOF and errno set
-** Success: number of data units used in the formating
+** Success: number of data units used in the formatting
**
** Side effects:
** formatted o/p can be SM_IO_BUFSIZ length maximum
@@ -156,13 +156,13 @@ sm_bprintf(fp, fmt, ap)
#define FPT 0x100 /* Floating point number */
/*
-** SM_IO_VFPRINTF -- performs actual formating for o/p
+** SM_IO_VFPRINTF -- performs actual formatting for o/p
**
** Parameters:
** fp -- file pointer for o/p
** timeout -- time to complete the print
-** fmt0 -- formating directives
-** ap -- vectors with data units for formating
+** fmt0 -- formatting directives
+** ap -- vectors with data units for formatting
**
** Results:
** Success: number of data units used for formatting
@@ -816,8 +816,8 @@ error:
** It will be replaced with a malloc-ed one if it overflows.
**
** Parameters:
-** fmt0 -- formating directives
-** ap -- vector list of data unit for formating consumption
+** fmt0 -- formatting directives
+** ap -- vector list of data unit for formatting consumption
** argtable -- an indexable table (returned) of 'ap'
**
** Results:
diff --git a/contrib/sendmail/libsm/vfscanf.c b/contrib/sendmail/libsm/vfscanf.c
index c367f7682e37..e1b7830b49d5 100644
--- a/contrib/sendmail/libsm/vfscanf.c
+++ b/contrib/sendmail/libsm/vfscanf.c
@@ -655,7 +655,7 @@ literal:
c = *fp->f_p;
/*
- ** This code mimicks the integer conversion
+ ** This code mimics the integer conversion
** code, but is much simpler.
*/
diff --git a/contrib/sendmail/libsmdb/smcdb.c b/contrib/sendmail/libsmdb/smcdb.c
index 93b3bdf52323..32b271277c9e 100644
--- a/contrib/sendmail/libsmdb/smcdb.c
+++ b/contrib/sendmail/libsmdb/smcdb.c
@@ -409,7 +409,7 @@ smcdb_cursor(database, cursor, flags)
** Parameters:
** database -- An unallocated database pointer to a pointer.
** db_name -- The name of the database without extension.
-** mode -- File permisions for a created database.
+** mode -- File permissions for a created database.
** mode_mask -- Mode bits that must match on an opened database.
** sff -- Flags for safefile.
** type -- The type of database to open
diff --git a/contrib/sendmail/libsmdb/smdb.c b/contrib/sendmail/libsmdb/smdb.c
index 9091b52520fa..1368a12bc24c 100644
--- a/contrib/sendmail/libsmdb/smdb.c
+++ b/contrib/sendmail/libsmdb/smdb.c
@@ -333,10 +333,9 @@ smdb_lock_file(lock_fd, db_name, mode, sff, extension)
return SMDBE_OK;
}
+
/*
-** SMDB_UNLOCK_FILE -- Unlocks a file
-**
-** Unlocks a file.
+** SMDB_UNLOCK_FILE -- Unlocks a file - via close()
**
** Parameters:
** lock_fd -- The descriptor for the locked file.
@@ -488,7 +487,7 @@ smdb_filechanged(db_name, extension, db_fd, stat_info)
** SMDB_PRINT_AVAILABLE_TYPES -- Prints the names of the available types.
**
** Parameters:
-** None
+** ext - also show extension?
**
** Returns:
** None
diff --git a/contrib/sendmail/libsmdb/smdb1.c b/contrib/sendmail/libsmdb/smdb1.c
index 85dc7fcaf74c..b5d7da3e57c5 100644
--- a/contrib/sendmail/libsmdb/smdb1.c
+++ b/contrib/sendmail/libsmdb/smdb1.c
@@ -423,7 +423,7 @@ smdb1_cursor(database, cursor, flags)
** Parameters:
** database -- An unallocated database pointer to a pointer.
** db_name -- The name of the database without extension.
-** mode -- File permisions on the database if created.
+** mode -- File permissions on the database if created.
** mode_mask -- Mode bits that must match on an existing database.
** sff -- Flags for safefile.
** type -- The type of database to open
diff --git a/contrib/sendmail/libsmdb/smdb2.c b/contrib/sendmail/libsmdb/smdb2.c
index 2e58f167124a..6d50dacfe321 100644
--- a/contrib/sendmail/libsmdb/smdb2.c
+++ b/contrib/sendmail/libsmdb/smdb2.c
@@ -549,7 +549,7 @@ smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
** Parameters:
** database -- An unallocated database pointer to a pointer.
** db_name -- The name of the database without extension.
-** mode -- File permisions for a created database.
+** mode -- File permissions for a created database.
** mode_mask -- Mode bits that must match on an opened database.
** sff -- Flags for safefile.
** type -- The type of database to open
diff --git a/contrib/sendmail/libsmdb/smndbm.c b/contrib/sendmail/libsmdb/smndbm.c
index bd7bce54cf7f..465503bc5cd6 100644
--- a/contrib/sendmail/libsmdb/smndbm.c
+++ b/contrib/sendmail/libsmdb/smndbm.c
@@ -17,7 +17,7 @@ SM_RCSID("@(#)$Id: smndbm.c,v 8.55 2013-11-22 20:51:49 ca Exp $")
#include <sendmail/sendmail.h>
#include <libsmdb/smdb.h>
-#ifdef NDBM
+#if NDBM
# define SMNDB_PAG_FILE_EXTENSION "pag"
@@ -465,7 +465,7 @@ smdbm_cursor(database, cursor, flags)
** Parameters:
** database -- An unallocated database pointer to a pointer.
** db_name -- The name of the database without extension.
-** mode -- File permisions on a created database.
+** mode -- File permissions on a created database.
** mode_mask -- Mode bits that much match on an opened database.
** sff -- Flags to safefile.
** type -- The type of database to open.
diff --git a/contrib/sendmail/libsmutil/t-lockfile.c b/contrib/sendmail/libsmutil/t-lockfile.c
index 27818a990873..29bf679e9c38 100644
--- a/contrib/sendmail/libsmutil/t-lockfile.c
+++ b/contrib/sendmail/libsmutil/t-lockfile.c
@@ -21,7 +21,20 @@ char iobuf[IOBUFSZ];
static int noio, chk;
static pid_t pid;
-int
+/*
+** OPENFILE -- open a file
+**
+** Parameters:
+** owner -- create file?
+** filename -- name of file.
+** flags -- flags for open(2)
+**
+** Returns:
+** >=0 fd
+** <0 on failure.
+*/
+
+static int
openfile(owner, filename, flags)
int owner;
char *filename;
@@ -36,10 +49,21 @@ openfile(owner, filename, flags)
return fd;
fprintf(stderr, "%d: %ld: owner=%d, open(%s) failed\n",
(int) pid, (long) time(NULL), owner, filename);
- return 1;
+ return -1;
}
-int
+/*
+** WRBUF -- write iobuf to fd
+**
+** Parameters:
+** fd -- file descriptor.
+**
+** Returns:
+** ==0 write was ok
+** !=0 on failure.
+*/
+
+static int
wrbuf(fd)
int fd;
{
@@ -55,7 +79,19 @@ wrbuf(fd)
return 1;
}
-int
+/*
+** RDBUF -- read from fd
+**
+** Parameters:
+** fd -- file descriptor.
+** xbuf -- expected content.
+**
+** Returns:
+** ==0 read was ok and content matches
+** !=0 otherwise
+*/
+
+static int
rdbuf(fd, xbuf)
int fd;
const char *xbuf;
@@ -81,7 +117,7 @@ rdbuf(fd, xbuf)
}
/*
-** LOCKTEST -- test of file locking
+** LOCKTESTWR -- test WR/EX file locking
**
** Parameters:
** owner -- create file?
@@ -102,7 +138,7 @@ rdbuf(fd, xbuf)
fprintf(stderr, str, filename, shared ? "RD" : "EX"); \
} while (0)
-int
+static int
locktestwr(filename, flags, delay)
char *filename;
int flags;
@@ -128,7 +164,8 @@ locktestwr(filename, flags, delay)
sm_strlcpy(iobuf, FIRSTLINE, sizeof(iobuf));
if (wrbuf(fd))
return 1;
- sleep(delay);
+ if (delay > 0)
+ sleep(delay);
sm_strlcpy(iobuf, LASTLINE, sizeof(iobuf));
if (wrbuf(fd))
return 1;
@@ -149,7 +186,22 @@ locktestwr(filename, flags, delay)
return 0;
}
-long
+/*
+** CHKLCK -- check whether fd is locked (only for fcntl())
+**
+** Parameters:
+** owner -- create file?
+** filename -- name of file.
+** flags -- flags for open(2)
+** delay -- how long to keep file locked?
+**
+** Returns:
+** 0 if not locked
+** >0 pid of process which holds a WR lock
+** <0 error
+*/
+
+static long
chklck(fd)
int fd;
{
@@ -168,13 +220,27 @@ chklck(fd)
return (long)lfd.l_pid;
return 0L;
#else /* !HASFLOCK */
- fprintf(stderr, "%d: %ld: flock: no lock test\n",
+ fprintf(stderr, "%d: %ld: flock(): no lock test\n",
(int) pid, (long) time(NULL));
return -1L;
#endif /* !HASFLOCK */
}
-int
+/*
+** LOCKTESTRD -- test file locking for reading
+**
+** Parameters:
+** filename -- name of file.
+** flags -- flags for open(2)
+** delay -- how long is file locked by owner?
+** shared -- LOCK_{EX/SH}
+**
+** Returns:
+** 0 on success
+** != 0 on failure.
+*/
+
+static int
locktestrd(filename, flags, delay, shared)
char *filename;
int flags;
@@ -252,6 +318,16 @@ locktestrd(filename, flags, delay, shared)
return 0;
}
+/*
+** USAGE -- show usage
+**
+** Parameters:
+** prg -- name of program
+**
+** Returns:
+** nothing.
+*/
+
static void
usage(prg)
const char *prg;
@@ -264,6 +340,12 @@ usage(prg)
"-r use shared locking for reader\n"
"-s delay sleep delay seconds before unlocking\n"
"-W only start writer process\n"
+#if !HASFLOCK
+ "uses fcntl()\n"
+#else
+ "uses flock()\n"
+#endif
+
, prg);
}
@@ -335,7 +417,7 @@ main(argc, argv)
r = 0;
if (reader || fpid == 0)
{
- /* give the parent the chance to setup data */
+ /* give the parent the chance to set up data */
pid = getpid();
sleep(1);
r = locktestrd(filename, flags, nb ? delay : 0, shared);
diff --git a/contrib/sendmail/mail.local/mail.local.c b/contrib/sendmail/mail.local/mail.local.c
index d62f74eadbf1..193b89dd4f10 100644
--- a/contrib/sendmail/mail.local/mail.local.c
+++ b/contrib/sendmail/mail.local/mail.local.c
@@ -1702,7 +1702,7 @@ hashname(name)
MD5_CTX ctx;
unsigned char md5[18];
# if MAXPATHLEN <= 24
-# ERROR "MAXPATHLEN <= 24"
+# error "MAXPATHLEN <= 24"
# endif
char b64[24];
MD5_LONG bits;
diff --git a/contrib/sendmail/makemap/makemap.8 b/contrib/sendmail/makemap/makemap.8
index fa250109b842..16481ef9de12 100644
--- a/contrib/sendmail/makemap/makemap.8
+++ b/contrib/sendmail/makemap/makemap.8
@@ -26,6 +26,8 @@ makemap
.IR commentchar ]
.RB [ \-e ]
.RB [ \-f ]
+.RB [ \-i
+.IR type ]
.RB [ \-l ]
.RB [ \-o ]
.RB [ \-r ]
@@ -144,6 +146,12 @@ This is intended to mesh with the
line in sendmail.cf.
The value is never case folded.
.TP
+.B \-i
+Use the specified type as fallback
+if the given
+.I maptype
+is not available.
+.TP
.B \-l
List supported map types.
.TP
diff --git a/contrib/sendmail/makemap/makemap.c b/contrib/sendmail/makemap/makemap.c
index f2ed0e39f990..f5e0d30a2700 100644
--- a/contrib/sendmail/makemap/makemap.c
+++ b/contrib/sendmail/makemap/makemap.c
@@ -53,12 +53,17 @@ bool DontInitGroups = false;
uid_t TrustedUid = 0;
BITMAP256 DontBlameSendmail;
+static bool verbose = false;
+static int exitstat;
+
#define BUFSIZE 1024
#define ISASCII(c) isascii((unsigned char)(c))
+#define ISSPACE(c) (ISASCII(c) && isspace(c))
#define ISSEP(c) (sep == '\0' ? ISASCII(c) && isspace(c) : (c) == sep)
static void usage __P((const char *));
static char *readcf __P((const char *, char *, bool));
+static void db_put __P((SMDB_DATABASE *, SMDB_DBENT, SMDB_DBENT, int, const char *, int, const char *));
static void
usage(progname)
@@ -68,7 +73,7 @@ usage(progname)
"Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
progname);
sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
- " %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n",
+ " %*s [-d] [-e] [-f] [-i type] [-l] [-o] [-r] [-s] [-t delimiter]\n",
(int) strlen(progname), "");
#if _FFR_TESTS
sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
@@ -82,6 +87,69 @@ usage(progname)
}
/*
+** DB_PUT -- do the DB insert
+**
+** Parameters:
+** database -- DB to use
+** db_key -- key
+** db_val -- value
+** putflags -- flags for smdb_put()
+** mapname -- name of map (for error reporting)
+** lineno -- line number (for error reporting)
+** progname -- name of program (for error reporting)
+**
+** Returns:
+** none.
+**
+** Side effects:
+** Sets exitstat so makemap exits with error if put fails
+*/
+
+static void
+db_put(database, db_key, db_val, putflags, mapname, lineno, progname)
+ SMDB_DATABASE *database;
+ SMDB_DBENT db_key, db_val;
+ int putflags;
+ const char *mapname;
+ int lineno;
+ const char *progname;
+{
+ int errcode;
+
+ if (verbose)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "key=`%s', val=`%s'\n",
+ (char *) db_key.data,
+ (char *) db_val.data);
+ }
+
+ errcode = database->smdb_put(database, &db_key, &db_val, putflags);
+ if (0 == errcode)
+ return;
+
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s: %s: ",
+ progname, mapname);
+ if (lineno >= 0)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "line %u: ",
+ lineno);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "key %s: ",
+ (char *) db_key.data);
+ if (SMDBE_KEY_EXIST == errcode)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "duplicate key\n");
+ exitstat = EX_DATAERR;
+ }
+ else
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "put error: %s\n", sm_errstring(errcode));
+ exitstat = EX_IOERR;
+ }
+}
+
+/*
** READCF -- read some settings from configuration file.
**
** Parameters:
@@ -106,7 +174,7 @@ readcf(cfile, mapfile, fullpath)
SM_FILE_T *cfp;
char buf[MAXLINE];
static char classbuf[MAXLINE];
- char *classname;
+ char *classname, *mapname;
char *p;
if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile,
@@ -120,13 +188,21 @@ readcf(cfile, mapfile, fullpath)
classname = NULL;
classbuf[0] = '\0';
+ mapname = mapfile;
if (!fullpath && mapfile != NULL)
{
p = strrchr(mapfile, '/');
if (p != NULL)
mapfile = ++p;
- p = strrchr(mapfile, '.');
- if (p != NULL)
+ mapname = strdup(mapfile);
+ if (NULL == mapname)
+ {
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "makemap: strdup(%s) failed: %s\n",
+ mapfile, sm_errstring(errno));
+ exit(EX_OSERR);
+ }
+ if ((p = strchr(mapname, '.')) != NULL)
*p = '\0';
}
@@ -184,18 +260,19 @@ readcf(cfile, mapfile, fullpath)
case 'K': /* Keyfile (map) */
if (classname != NULL) /* found it already */
continue;
- if (mapfile == NULL || *mapfile == '\0')
+ if (mapname == NULL || *mapname == '\0')
continue;
/* cut off trailing spaces */
- for (p = buf + strlen(buf) - 1; ISASCII(*p) && isspace(*p) && p > buf; p--)
+ for (p = buf + strlen(buf) - 1;
+ ISASCII(*p) && isspace(*p) && p > buf; p--)
*p = '\0';
/* find the last argument */
p = strrchr(buf, ' ');
if (p == NULL)
continue;
- b = strstr(p, mapfile);
+ b = strstr(p, mapname);
if (b == NULL)
continue;
if (b <= buf)
@@ -208,7 +285,7 @@ readcf(cfile, mapfile, fullpath)
}
/* allow trailing white space? */
- if (strcmp(mapfile, b) != 0)
+ if (strcmp(mapname, b) != 0)
continue;
/* SM_ASSERT(b > buf); */
--b;
@@ -253,6 +330,12 @@ readcf(cfile, mapfile, fullpath)
}
(void) sm_io_close(cfp, SM_TIME_DEFAULT);
+ /* not really needed because it is just a "one time leak" */
+ if (mapname != mapfile && mapname != NULL)
+ {
+ free(mapname);
+ mapname = NULL;
+ }
return classbuf;
}
@@ -267,19 +350,24 @@ main(argc, argv)
bool notrunc = false;
bool allowreplace = false;
bool allowempty = false;
- bool verbose = false;
bool foldcase = true;
bool unmake = false;
+#if _FFR_MM_ALIASES
+ /*
+ ** NOTE: this does not work properly:
+ ** sendmail does address rewriting which is not done here.
+ */
+
+ bool aliases = false;
+#endif
bool didreadcf = false;
char sep = '\0';
char comment = '#';
- int exitstat;
int opt;
char *typename = NULL;
char *fallback = NULL;
char *mapname = NULL;
unsigned int lineno;
- int st;
int mode;
int smode;
int putflags = 0;
@@ -327,12 +415,17 @@ main(argc, argv)
SMDB_MAX_USER_NAME_LEN);
#define OPTIONS "C:D:Nc:defi:Llorst:uvx"
+#if _FFR_MM_ALIASES
+# define A_OPTIONS "a"
+#else
+# define A_OPTIONS
+#endif
#if _FFR_TESTS
# define X_OPTIONS "S:"
#else
# define X_OPTIONS
#endif
- while ((opt = getopt(argc, argv, OPTIONS X_OPTIONS)) != -1)
+ while ((opt = getopt(argc, argv, A_OPTIONS OPTIONS X_OPTIONS)) != -1)
{
switch (opt)
{
@@ -344,6 +437,14 @@ main(argc, argv)
inclnull = true;
break;
+#if _FFR_MM_ALIASES
+ case 'a':
+ /* Note: this doesn't verify e-mail addresses */
+ sep = ':';
+ aliases = true;
+ break;
+#endif
+
case 'c':
params.smdbp_cache_size = atol(optarg);
break;
@@ -669,6 +770,10 @@ main(argc, argv)
*p++ = '\0';
while (*p != '\0' && ISSEP(*p))
p++;
+#if _FFR_MM_ALIASES
+ while (aliases && *p != '\0' && ISSPACE(*p))
+ p++;
+#endif
if (!allowempty && *p == '\0')
{
(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
@@ -688,50 +793,22 @@ main(argc, argv)
** Do the database insert.
*/
- if (verbose)
- {
- (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
- "key=`%s', val=`%s'\n",
- (char *) db_key.data,
- (char *) db_val.data);
- }
-
- errno = database->smdb_put(database, &db_key, &db_val,
- putflags);
- switch (errno)
- {
- case SMDBE_KEY_EXIST:
- st = 1;
- break;
-
- case 0:
- st = 0;
- break;
-
- default:
- st = -1;
- break;
- }
-
- if (st < 0)
- {
- (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
- "%s: %s: line %u: key %s: put error: %s\n",
- progname, mapname, lineno,
- (char *) db_key.data,
- sm_errstring(errno));
- exitstat = EX_IOERR;
- }
- else if (st > 0)
- {
- (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
- "%s: %s: line %u: key %s: duplicate key\n",
- progname, mapname,
- lineno,
- (char *) db_key.data);
- exitstat = EX_DATAERR;
- }
+ db_put(database, db_key, db_val, putflags, mapname,
+ lineno, progname);
+ }
+#if _FFR_MM_ALIASES
+ if (aliases)
+ {
+ char magic[2] = "@";
+
+ db_key.data = magic;
+ db_val.data = magic;
+ db_key.size = 1;
+ db_val.size = 1;
+ db_put(database, db_key, db_val, putflags, mapname, -1,
+ progname);
}
+#endif /* _FFR_MM_ALIASES */
}
#if _FFR_TESTS
diff --git a/contrib/sendmail/smrsh/README b/contrib/sendmail/smrsh/README
index 7723b3a278e8..006eb819db4f 100644
--- a/contrib/sendmail/smrsh/README
+++ b/contrib/sendmail/smrsh/README
@@ -51,7 +51,7 @@ the bin directory used by smrsh.
path.
-DSMRSH_CMDDIR=\"dir\" \"/usr/adm/sm.bin\" The default smrsh
program directory
-
+
These can be added to the devtools/Site/site.config.m4 file using the
global M4 macro confENVDEF or the smrsh specific M4 macro
conf_smrsh_ENVDEF.
diff --git a/contrib/sendmail/src/Makefile.m4 b/contrib/sendmail/src/Makefile.m4
index e7f185162778..7070ca5cb0df 100644
--- a/contrib/sendmail/src/Makefile.m4
+++ b/contrib/sendmail/src/Makefile.m4
@@ -6,7 +6,7 @@ define(`confREQUIRE_SM_OS_H', `true')
bldPRODUCT_START(`executable', `sendmail')
define(`bldBIN_TYPE', `G')
define(`bldINSTALL_DIR', `')
-define(`bldSOURCES', `main.c alias.c arpadate.c bf.c collect.c conf.c control.c convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c macro.c map.c mci.c milter.c mime.c parseaddr.c queue.c ratectrl.c readcf.c recipient.c sasl.c savemail.c sfsasl.c shmticklib.c sm_resolve.c srvrsmtp.c stab.c stats.c sysexits.c timers.c tlsh.c tls.c trace.c udb.c usersmtp.c util.c version.c ')
+define(`bldSOURCES', `main.c alias.c arpadate.c bf.c collect.c conf.c control.c convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c macro.c map.c mci.c milter.c mime.c parseaddr.c queue.c ratectrl.c readcf.c recipient.c sasl.c savemail.c sched.c sfsasl.c shmticklib.c sm_resolve.c srvrsmtp.c stab.c stats.c sysexits.c timers.c tlsh.c tls.c trace.c udb.c usersmtp.c util.c version.c ')
PREPENDDEF(`confENVDEF', `confMAPDEF')
bldPUSH_SMLIB(`sm')
bldPUSH_SMLIB(`smutil')
diff --git a/contrib/sendmail/src/README b/contrib/sendmail/src/README
index 81f5bfbce147..a933e310c3c2 100644
--- a/contrib/sendmail/src/README
+++ b/contrib/sendmail/src/README
@@ -232,8 +232,8 @@ HASFLOCK Set this if you prefer to use the flock(2) system call
rather than using fcntl-based locking. Fcntl locking
has some semantic gotchas, but many vendor systems
also interface it to lockd(8) to do NFS-style locking.
- Unfortunately, may vendors implementations of fcntl locking
- is just plain broken (e.g., locks are never released,
+ Unfortunately, many vendor implementations of fcntl locking
+ are just plain broken (e.g., locks are never released,
causing your sendmail to deadlock; when the kernel runs
out of locks your system crashes). For this reason, I
recommend always defining this unless you are absolutely
@@ -309,9 +309,9 @@ HASSTRERROR Define this if you have the libc strerror(3) function (which
HASCLOSEFROM Define this if your system has closefrom(3).
HASFDWALK Define this if your system has fdwalk(3).
SM_CONF_GETOPT Define this as 0 if you need a reimplementation of getopt(3).
- On some systems, getopt does very odd things if called
+ On some systems, getopt() does very odd things if called
to scan the arguments twice. This flag will ask sendmail
- to compile in a local version of getopt that works
+ to compile in a local version of getopt() that works
properly. You may also need this if you build with
another library that introduces a non-standard getopt(3).
NEEDSTRTOL Define this if your standard C library does not define
@@ -625,7 +625,7 @@ SHARE_V1 Support for the fair share scheduler, version 1. Setting to
resource limitations. So far as I know, this is only
supported on ConvexOS.
SASL Enables SMTP AUTH (RFC 2554). This requires the Cyrus SASL
- library (ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/). Please
+ library (https://github.com/cyrusimap/cyrus-sasl). Please
install at least version 1.5.13. See below for further
information: SASL COMPILATION AND CONFIGURATION. If your
SASL library is older than 1.5.10, you have to set this
@@ -640,7 +640,9 @@ EGD Define this if your system has EGD installed, see
http://egd.sourceforge.net/ . It should be used to
seed the PRNG for STARTTLS if HASURANDOMDEV is not defined.
STARTTLS Enables SMTP STARTTLS (RFC 2487). This requires OpenSSL
- (http://www.OpenSSL.org/); use OpenSSL 0.9.8zc or later.
+ (http://www.OpenSSL.org/); use an OpenSSL version
+ which is supported by sendmail and preferably your
+ OS distribution or OpenSSL.
See STARTTLS COMPILATION AND CONFIGURATION for further
information.
TLS_EC Enable use of elliptic curve cryptography in STARTTLS.
@@ -765,6 +767,10 @@ From: Garrett Wollman <wollman@lcs.mit.edu>
certificate authentication -- even some of those which already support
SSL/TLS for confidentiality.
+OpenSSL 3 deprecated a lot of functionality which sendmail uses by
+default. However, the code can be disabled via compile time options
+if needed:
+-DNO_DH: related to DH and DSA.
+------------------------------------+
| SASL COMPILATION AND CONFIGURATION |
@@ -1804,6 +1810,7 @@ conf.h Configuration that must be known everywhere.
control.c Routines to implement control socket.
convtime.c A routine to sanely process times.
daemon.c Routines to implement daemon mode.
+daemon.h Header file for daemon.c.
deliver.c Routines to deliver mail.
domain.c Routines that interface with DNS (the Domain Name
System).
@@ -1818,17 +1825,21 @@ main.c The main routine to sendmail. This file also
contains some miscellaneous routines.
makesendmail A convenience for calling ./Build.
map.c Support for database maps.
+map.h Header file for map.c.
mci.c Routines that handle mail connection information caching.
milter.c MTA portions of the mail filter API.
mime.c MIME conversion routines.
newaliases.1 Man page for the newaliases command.
parseaddr.c The routines which do address parsing.
queue.c Routines to implement message queueing.
+ratectrl.c Routines for rate/connnection control.
+ratectrl.h Header file for rate/connnection control.
readcf.c The routine that reads the configuration file and
translates it to internal form.
recipient.c Routines that manipulate the recipient list.
sasl.c Routines to interact with Cyrys-SASL.
savemail.c Routines which save the letter on processing errors.
+sched.c Routines for scheduling queue management.
sendmail.8 Man page for the sendmail command.
sendmail.h Main header file for sendmail.
sfsasl.c I/O interface between SASL/TLS and the MTA.
@@ -1846,6 +1857,8 @@ sysexits.h List of error codes for systems that lack their own.
timers.c Routines to provide microtimers.
timers.h Data structure and function declarations for timers.h.
tls.c Routines for TLS.
+tls.h Header file for tls*.c
+tlsh.c Helper routines for TLS, mostly DANE.
trace.c The trace package. These routines allow setting and
testing of trace flags with a high granularity.
udb.c The user database interface module.
diff --git a/contrib/sendmail/src/SECURITY b/contrib/sendmail/src/SECURITY
index 0e38835ca023..fa35ff7a4920 100644
--- a/contrib/sendmail/src/SECURITY
+++ b/contrib/sendmail/src/SECURITY
@@ -14,12 +14,12 @@ people who are very security conscious (you should be...).
Even though sendmail goes through great lengths to assure that it
can't be compromised even if the system it is running on is
incorrectly or insecurely configured, it can't work around everything.
-This has been demonstrated by recent OS problems which have
-subsequently been used to compromise the root account using sendmail
-as a vector. One way to minimize the possibility of such problems
-is to install sendmail without set-user-ID root, which avoids local
-exploits. This configuration, which is the default starting with
-8.12, is described in the first section of this security guide.
+This has been demonstrated by OS problems which have subsequently
+been used to compromise the root account using sendmail as a vector.
+One way to minimize the possibility of such problems is to install
+sendmail without set-user-ID root, which avoids local exploits.
+This configuration, which is the default starting with 8.12, is
+described in the first section of this security guide.
*****************************************************
@@ -112,6 +112,7 @@ information.) You can start this program as root, it will change
its user id to RunAsUser (smmsp by default, recommended uid: 25).
This way smmsp does not need a valid shell.
+
Summary
-------
@@ -186,6 +187,7 @@ You can use
to install a sendmail program to act as daemon etc under the name
sm-mta.
+
Set-User-Id
-----------
diff --git a/contrib/sendmail/src/TRACEFLAGS b/contrib/sendmail/src/TRACEFLAGS
index 0b9ccd989320..7c9b1c7c6e98 100644
--- a/contrib/sendmail/src/TRACEFLAGS
+++ b/contrib/sendmail/src/TRACEFLAGS
@@ -71,15 +71,14 @@
57 util.c snprintf
58 bf.c bf* routines
59 parseaddr.c cataddr
-60 map.c
+60 parseaddr.c map_lookup
61 conf.c sm_gethostbyname
62 multiple file descriptor checking
63 queue.c runqueue process watching
64 multiple Milter
65 main.c permission checks
#if DANE
-66 domain.c force port=25 for TLSA RR lookups
-67 domain.c TLSA RR lookups
+66,>99 domain.c force port=25 for TLSA RR lookups
#endif
68 unused
#if _FFR_QUEUE_SCHED_DBG
@@ -105,19 +104,26 @@
83 collect.c timeout
84 deliver.c timeout
85 map.c dprintf map
+#if _FFR_TESTS
+86,>99 milter.c macro tests
+#endif
#if _FFR_PROXY
87 srvrsmtp.c proxy mode
#endif
88,>99 tls.c disable the effect of _FFR_VRFY_TRUSTED_FIRST
89 conf.c >=8 use sm_dprintf() instead of syslog()
-90 unused
+#if _FFR_TESTS
+90,>99 tls.c deliver.c Simulate error for OpenSSL functions related to DANE
+#endif
91 mci.c syslogging of MCI cache information
92 EF_LOGSENDER
93,>99 * Prevent daemon connection fork for profiling/debugging
94,>99 srvrsmtp.c cause commands to fail (for protocol testing)
95 srvrsmtp.c AUTH
95 usersmtp.c AUTH
-96 tls.c DHparam info, Activate SSL_CTX_set_info_callback()
+96 tls.c DHparam info, activate SSL_CTX_set_info_callback(), etc
97 srvrsmtp.c Trace automode settings for I/O
+#if _FFR_TIMERS
98 * timers
+#endif
99 main.c avoid backgrounding (no printed output)
diff --git a/contrib/sendmail/src/alias.c b/contrib/sendmail/src/alias.c
index e3ee68f21852..f3d3b45acf90 100644
--- a/contrib/sendmail/src/alias.c
+++ b/contrib/sendmail/src/alias.c
@@ -381,10 +381,11 @@ setalias(spec)
}
}
}
+
/*
** ALIASWAIT -- wait for distinguished @:@ token to appear.
**
-** This can decide to reopen or rebuild the alias file
+** This can decide to reopen the alias file
**
** Parameters:
** map -- a pointer to the map descriptor for this alias file.
@@ -402,7 +403,7 @@ setalias(spec)
bool
aliaswait(map, ext, isopen)
MAP *map;
- char *ext;
+ const char *ext;
bool isopen;
{
bool attimeout = false;
@@ -411,13 +412,14 @@ aliaswait(map, ext, isopen)
char buf[MAXPATHLEN];
if (tTd(27, 3))
- sm_dprintf("aliaswait(%s:%s)\n",
- map->map_class->map_cname, map->map_file);
+ sm_dprintf("aliaswait(%s:%s), open=%d, wait=%d\n",
+ map->map_class->map_cname, map->map_file,
+ isopen, bitset(MF_ALIASWAIT, map->map_mflags));
if (bitset(MF_ALIASWAIT, map->map_mflags))
return isopen;
map->map_mflags |= MF_ALIASWAIT;
- if (SafeAlias > 0)
+ if (isopen && SafeAlias > 0)
{
auto int st;
unsigned int sleeptime = 2;
@@ -448,7 +450,7 @@ aliaswait(map, ext, isopen)
map->map_mflags |= MF_CLOSING;
map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
+ map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING|MF_CHKED_CHGD);
(void) sleep(sleeptime);
sleeptime *= 2;
if (sleeptime > 60)
@@ -456,6 +458,7 @@ aliaswait(map, ext, isopen)
isopen = map->map_class->map_open(map, O_RDONLY);
}
}
+ map->map_mflags &= ~MF_CHKED_CHGD;
/* see if we need to go into auto-rebuild mode */
if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
@@ -499,20 +502,17 @@ aliaswait(map, ext, isopen)
**
** Parameters:
** map -- the database to rebuild.
-** automatic -- set if this was automatically generated.
**
** Returns:
** true if successful; false otherwise.
**
** Side Effects:
-** Reads the text version of the database, builds the
-** DBM or DB version.
+** Reads the text version of the database, builds the map.
*/
bool
-rebuildaliases(map, automatic)
+rebuildaliases(map)
register MAP *map;
- bool automatic;
{
SM_FILE_T *af;
bool nolock = false;
@@ -538,7 +538,7 @@ rebuildaliases(map, automatic)
{
struct stat stb;
- if ((errno != EACCES && errno != EROFS) || automatic ||
+ if ((errno != EACCES && errno != EROFS) ||
(af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL)
{
int saveerr = errno;
@@ -546,7 +546,7 @@ rebuildaliases(map, automatic)
if (tTd(27, 1))
sm_dprintf("Can't open %s: %s\n",
map->map_file, sm_errstring(saveerr));
- if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
message("newaliases: cannot open %s: %s",
map->map_file, sm_errstring(saveerr));
errno = 0;
@@ -590,13 +590,12 @@ rebuildaliases(map, automatic)
if (LogLevel > 7)
{
sm_syslog(LOG_NOTICE, NOQID,
- "alias database %s %srebuilt by %s",
- map->map_file, automatic ? "auto" : "",
- username());
+ "alias database %s rebuilt by %s",
+ map->map_file, username());
}
map->map_mflags |= MF_OPEN|MF_WRITABLE;
map->map_pid = CurrentPid;
- readaliases(map, af, !automatic, true);
+ readaliases(map, af, true, true);
success = true;
}
else
@@ -604,9 +603,8 @@ rebuildaliases(map, automatic)
if (tTd(27, 1))
sm_dprintf("Can't create database for %s: %s\n",
map->map_file, sm_errstring(errno));
- if (!automatic)
- syserr("Cannot create database for alias file %s",
- map->map_file);
+ syserr("Cannot create database for alias file %s",
+ map->map_file);
}
/* close the file, thus releasing locks */
@@ -621,8 +619,10 @@ rebuildaliases(map, automatic)
int sl;
sl = tTdlevel(78) - 100;
- sm_dprintf("rebuildaliases: sleep=%d\n", sl);
+ sm_dprintf("rebuildaliases: sleep=%d, file=%s\n",
+ sl, map->map_file);
sleep(sl);
+ sm_dprintf("rebuildaliases: done\n");
}
#endif
map->map_mflags |= MF_CLOSING;
@@ -638,6 +638,54 @@ rebuildaliases(map, automatic)
#endif
return success;
}
+
+/*
+** CONTLINE -- handle potential continuation line
+**
+** Parameters:
+** fp -- file to read
+** line -- current line
+**
+** Returns:
+** pointer to end of current line if there is a continuation line
+** NULL otherwise
+**
+** Side Effects:
+** Modifies line if it is a continuation line
+*/
+
+static char *contline __P((SM_FILE_T *, char *));
+static char *
+contline(fp, line)
+ SM_FILE_T *fp;
+ char *line;
+{
+ char *p;
+ int c;
+
+ if ((p = strchr(line, '\n')) != NULL && p > line && p[-1] == '\\')
+ {
+ *p = '\0';
+ *--p = '\0';
+ return p;
+ }
+
+ c = sm_io_getc(fp, SM_TIME_DEFAULT);
+ if (!sm_io_eof(fp))
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
+ if (c == ' ' || c == '\t')
+ {
+ char *nlp;
+
+ p = line;
+ nlp = &p[strlen(p)];
+ if (nlp > p && nlp[-1] == '\n')
+ *--nlp = '\0';
+ return nlp;
+ }
+ return NULL;
+}
+
/*
** READALIASES -- read and process the alias file.
**
@@ -688,48 +736,74 @@ readaliases(map, af, announcestats, logstats)
naliases = bytes = longest = 0;
skipping = false;
line = NULL;
+
while (sm_io_fgets(af, SM_TIME_DEFAULT, lbuf, sizeof(lbuf)) >= 0)
{
int lhssize, rhssize;
int c;
+ char *newp;
LineNumber++;
-#if _FFR_8BITENVADDR
- if (line != lbuf)
- SM_FREE(line);
- len = 0;
- line = quote_internal_chars(lbuf, NULL, &len, NULL);
-#else
- line = lbuf;
-#endif
- p = strchr(line, '\n');
/* XXX what if line="a\\" ? */
- while (p != NULL && p > line && p[-1] == '\\')
+ line = lbuf;
+ p = line;
+ while ((newp = contline(af, line)) != NULL)
{
- p--;
- if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
- SPACELEFT(line, p)) < 0)
+ p = newp;
+ if ((c = sm_io_fgets(af, SM_TIME_DEFAULT, p,
+ SPACELEFT(lbuf, p))) < 0)
+ {
break;
+ }
LineNumber++;
- p = strchr(p, '\n');
}
+#if _FFR_8BITENVADDR
+ if (SMTP_UTF8 || EightBitAddrOK)
+ {
+ if (line != lbuf)
+ SM_FREE(line);
+ line = quote_internal_chars(lbuf, NULL, &len, NULL);
+ }
+ else
+#endif
+ /* "else" in #if code above */
+ line = lbuf;
+
+ p = strchr(line, '\n');
if (p != NULL)
*p = '\0';
else if (!sm_io_eof(af))
{
+ int prev;
+ bool cl;
+
errno = 0;
syserr("554 5.3.0 alias line too long");
- /* flush to end of line */
- while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) !=
- SM_IO_EOF && c != '\n')
- continue;
+ prev = '\0';
+ cl = false;
+
+ do {
+ /* flush to end of "virtual" line */
+ while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) !=
+ SM_IO_EOF && c != '\n')
+ {
+ prev = c;
+ }
+ cl = ('\\' == prev && '\n' == c);
+ if (!cl)
+ {
+ c = sm_io_getc(af, SM_TIME_DEFAULT);
+ if (!sm_io_eof(af))
+ (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c);
+ cl = (c == ' ' || c == '\t');
+ }
+ } while (cl);
- /* skip any continuation lines */
- skipping = true;
continue;
}
+
switch (line[0])
{
case '#':
@@ -779,7 +853,6 @@ readaliases(map, af, announcestats, logstats)
while (SM_ISSPACE(*p))
p++;
rhs = p;
- for (;;)
{
register char *nlp;
@@ -810,31 +883,7 @@ readaliases(map, af, announcestats, logstats)
{
p = nlp;
}
-
- /* see if there should be a continuation line */
- c = sm_io_getc(af, SM_TIME_DEFAULT);
- if (!sm_io_eof(af))
- (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c);
- if (c != ' ' && c != '\t')
- break;
-
- /* read continuation line */
- if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
- sizeof(line) - (p-line)) < 0)
- break;
- LineNumber++;
-
- /* check for line overflow */
- if (strchr(p, '\n') == NULL && !sm_io_eof(af))
- {
- usrerr("554 5.3.5 alias too long");
- while ((c = sm_io_getc(af, SM_TIME_DEFAULT))
- != SM_IO_EOF && c != '\n')
- continue;
- skipping = true;
- break;
- }
- }
+ } while (0);
if (skipping)
continue;
@@ -868,17 +917,20 @@ readaliases(map, af, announcestats, logstats)
{
syserr("554 5.3.5 %.40s... missing value for alias",
line);
-
}
else
{
#if _FFR_8BITENVADDR
- dequote_internal_chars(al.q_user, lhsbuf, sizeof(lhsbuf));
- dequote_internal_chars(rhs, rhsbuf, sizeof(rhsbuf));
- map->map_class->map_store(map, lhsbuf, rhsbuf);
-#else
- map->map_class->map_store(map, al.q_user, rhs);
+ if (SMTP_UTF8 || EightBitAddrOK)
+ {
+ dequote_internal_chars(al.q_user, lhsbuf, sizeof(lhsbuf));
+ dequote_internal_chars(rhs, rhsbuf, sizeof(rhsbuf));
+ map->map_class->map_store(map, lhsbuf, rhsbuf);
+ }
+ else
#endif
+ /* "else" in #if code above */
+ map->map_class->map_store(map, al.q_user, rhs);
/* statistics */
naliases++;
@@ -947,7 +999,16 @@ forward(user, sendq, aliaslevel, e)
/* good address -- look for .forward file in home */
macdefine(&e->e_macro, A_PERM, 'z', user->q_home);
macdefine(&e->e_macro, A_PERM, 'u', user->q_user);
- macdefine(&e->e_macro, A_PERM, 'h', user->q_host);
+ pp = user->q_host;
+#if _FFR_8BITENVADDR
+ if (NULL != pp)
+ {
+ int len;
+
+ pp = quote_internal_chars(pp, NULL, &len, NULL);
+ }
+#endif
+ macdefine(&e->e_macro, A_PERM, 'h', pp);
if (ForwardPath == NULL)
ForwardPath = newstr("\201z/.forward");
diff --git a/contrib/sendmail/src/bf.c b/contrib/sendmail/src/bf.c
index 6fb10c9252bd..7156bee9d7c3 100644
--- a/contrib/sendmail/src/bf.c
+++ b/contrib/sendmail/src/bf.c
@@ -61,7 +61,7 @@ struct bf
int bf_buffilled; /* Bytes of buffer actually filled */
char *bf_filename; /* Name of buffered file, if ever committed */
MODE_T bf_filemode; /* Mode of buffered file, if ever committed */
- off_t bf_offset; /* Currect file offset */
+ off_t bf_offset; /* Current file offset */
int bf_size; /* Total current size of file */
};
diff --git a/contrib/sendmail/src/collect.c b/contrib/sendmail/src/collect.c
index 762c60155f9b..418517902233 100644
--- a/contrib/sendmail/src/collect.c
+++ b/contrib/sendmail/src/collect.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2006, 2008 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2006, 2008, 2023, 2024 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -34,7 +34,7 @@ static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int));
** numhdrs -- number of headers
** hdrslen -- length of headers
**
-** Results:
+** Returns:
** NULL, or handle to open data file
**
** Side Effects:
@@ -82,7 +82,7 @@ collect_eoh(e, numhdrs, hdrslen)
** Parameters:
** e -- envelope
**
-** Results:
+** Returns:
** none.
**
** Side Effects:
@@ -179,7 +179,7 @@ collect_doheader(e)
** Parameters:
** e -- envelope
**
-** Results:
+** Returns:
** NULL, or a pointer to an open data file,
** into which the message body will be written by collect().
**
@@ -233,6 +233,70 @@ collect_dfopen(e)
}
/*
+** INCBUFLEN -- increase buflen for the header buffer in collect()
+**
+** Parameters:
+** buflen -- current size of buffer
+**
+** Returns:
+** new buflen
+*/
+
+static int incbuflen __P((int));
+static int
+incbuflen(buflen)
+ int buflen;
+{
+ int newlen;
+
+ /* this also handles the case of MaxMessageSize == 0 */
+ if (MaxMessageSize <= MEMCHUNKSIZE)
+ {
+ if (buflen < MEMCHUNKSIZE)
+ return buflen * 2;
+ else
+ return buflen + MEMCHUNKSIZE;
+ }
+
+ /* MaxMessageSize > MEMCHUNKSIZE */
+ newlen = buflen * 2;
+ if (newlen > 0 && newlen < MaxMessageSize)
+ return newlen;
+ else
+ return MaxMessageSize;
+}
+
+#if _FFR_TESTS
+/* just for testing/debug output */
+static const char *
+makeprint(c)
+ char c;
+{
+ static char prt[6];
+
+ prt[1] = '\0';
+ prt[2] = '\0';
+ if (isprint((unsigned char)c))
+ prt[0] = c;
+ else if ('\n' == c)
+ {
+ prt[0] = 'L';
+ prt[1] = 'F';
+ }
+ else if ('\r' == c)
+ {
+ prt[0] = 'C';
+ prt[1] = 'R';
+ }
+ else
+ snprintf(prt, sizeof(prt), "%o", c);
+ return prt;
+}
+#else /* _FFR_TESTS */
+# define makeprint(c) "X"
+#endif /* _FFR_TESTS */
+
+/*
** COLLECT -- read & parse message header & make temp file.
**
** Creates a temporary file name and copies the standard
@@ -241,10 +305,10 @@ collect_dfopen(e)
**
** Parameters:
** fp -- file to read.
-** smtpmode -- if set, we are running SMTP: give an RFC821
-** style message to say we are ready to collect
-** input, and never ignore a single dot to mean
-** end of message.
+** smtpmode -- if >= SMTPMODE_LAX we are running SMTP:
+** give an RFC821 style message to say we are
+** ready to collect input, and never ignore
+** a single dot to mean end of message.
** hdrp -- the location to stash the header.
** e -- the current envelope.
** rsetsize -- reset e_msgsize?
@@ -267,20 +331,26 @@ collect_dfopen(e)
/* values for input state machine */
#define IS_NORM 0 /* middle of line */
#define IS_BOL 1 /* beginning of line */
-#define IS_DOT 2 /* read a dot at beginning of line */
+#define IS_DOT 2 /* read "." at beginning of line */
#define IS_DOTCR 3 /* read ".\r" at beginning of line */
-#define IS_CR 4 /* read a carriage return */
+#define IS_CR 4 /* read "\r" */
+
+/* hack to enhance readability of debug output */
+static const char *istates[] = { "NORM", "BOL", "DOT", "DOTCR", "CR" };
+#define ISTATE istates[istate]
/* values for message state machine */
#define MS_UFROM 0 /* reading Unix from line */
#define MS_HEADER 1 /* reading message header */
#define MS_BODY 2 /* reading message body */
#define MS_DISCARD 3 /* discarding rest of message */
+#define BARE_LF_MSG "Bare linefeed (LF) not allowed"
+#define BARE_CR_MSG "Bare carriage return (CR) not allowed"
void
collect(fp, smtpmode, hdrp, e, rsetsize)
SM_FILE_T *fp;
- bool smtpmode;
+ int smtpmode;
HDR **hdrp;
register ENVELOPE *e;
bool rsetsize;
@@ -306,12 +376,26 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
#if _FFR_REJECT_NUL_BYTE
bool hasNUL; /* has at least one NUL input byte */
#endif
+ int bare_lf, bare_cr;
+
+#define SMTPMODE (smtpmode >= SMTPMODE_LAX)
+#define SMTPMODE_STRICT ((smtpmode & SMTPMODE_CRLF) != 0)
+#define BARE_LF_421 ((smtpmode & SMTPMODE_LF_421) != 0)
+#define BARE_CR_421 ((smtpmode & SMTPMODE_CR_421) != 0)
+#define BARE_LF_SP ((smtpmode & SMTPMODE_LF_SP) != 0)
+#define BARE_CR_SP ((smtpmode & SMTPMODE_CR_SP) != 0)
+
+/* for bare_{lf,cr} */
+#define BARE_IN_HDR 0x01
+#define BARE_IN_BDY 0x02
+#define BARE_WHERE ((MS_BODY == mstate) ? BARE_IN_BDY : BARE_IN_HDR)
df = NULL;
- ignrdot = smtpmode ? false : IgnrDot;
+ ignrdot = SMTPMODE ? false : IgnrDot;
+ bare_lf = bare_cr = 0;
/* timeout for I/O functions is in milliseconds */
- dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000)
+ dbto = SMTPMODE ? ((int) TimeOuts.to_datablock * 1000)
: SM_TIME_FOREVER;
sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto);
old_rd_tmo = set_tls_rd_tmo(TimeOuts.to_datablock);
@@ -334,15 +418,15 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
** Tell ARPANET to go ahead.
*/
- if (smtpmode)
- message("354 Enter mail, end with \".\" on a line by itself");
+ if (SMTPMODE)
+ message("354 End data with <CR><LF>.<CR><LF>");
/* simulate an I/O timeout when used as sink */
if (tTd(83, 101))
sleep(319);
if (tTd(30, 2))
- sm_dprintf("collect\n");
+ sm_dprintf("collect, smtpmode=%#x\n", smtpmode);
/*
** Read the message.
@@ -358,7 +442,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
for (;;)
{
if (tTd(30, 35))
- sm_dprintf("top, istate=%d, mstate=%d\n", istate,
+ sm_dprintf("top, istate=%s, mstate=%d\n", ISTATE,
mstate);
for (;;)
{
@@ -379,7 +463,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
/* timeout? */
if (c == SM_IO_EOF && errno == EAGAIN
- && smtpmode)
+ && SMTPMODE)
{
/*
** Override e_message in
@@ -417,15 +501,32 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
hasNUL = true;
#endif
if (c == SM_IO_EOF)
- goto readerr;
- if (SevenBitInput)
+ goto readdone;
+ if (SevenBitInput ||
+ bitset(EF_7BITBODY, e->e_flags))
c &= 0x7f;
else
HasEightBits |= bitset(0x80, c);
}
if (tTd(30, 94))
- sm_dprintf("istate=%d, c=%c (0x%x)\n",
- istate, (char) c, c);
+ sm_dprintf("istate=%s, c=%s (0x%x)\n",
+ ISTATE, makeprint((char) c), c);
+ if ('\n' == c && SMTPMODE &&
+ !(IS_CR == istate || IS_DOTCR == istate))
+ {
+ bare_lf |= BARE_WHERE;
+ if (BARE_LF_421)
+ {
+ inputerr = true;
+ goto readabort;
+ }
+ if (BARE_LF_SP)
+ {
+ if (TTD(30, 64))
+ sm_dprintf("LF: c=%s %#x\n", makeprint((char) c), c);
+ c = ' ';
+ }
+ }
switch (istate)
{
case IS_BOL:
@@ -437,8 +538,8 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
break;
case IS_DOT:
- if (c == '\n' && !ignrdot)
- goto readerr;
+ if (c == '\n' && !ignrdot && !SMTPMODE_STRICT)
+ goto readdone;
else if (c == '\r')
{
istate = IS_DOTCR;
@@ -460,7 +561,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
case IS_DOTCR:
if (c == '\n' && !ignrdot)
- goto readerr;
+ goto readdone;
else
{
/* push back the ".\rx" */
@@ -483,12 +584,30 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
case IS_CR:
if (c == '\n')
+ {
+ if (TTD(30, 64))
+ sm_dprintf("state=CR, c=%s %#x -> BOL\n", makeprint((char) c), c);
istate = IS_BOL;
+ }
else
{
+ if (TTD(30, 64))
+ sm_dprintf("state=CR, c=%s %#x -> NORM\n", makeprint((char) c), c);
+ if (SMTPMODE)
+ {
+ bare_cr |= BARE_WHERE;
+ if (BARE_CR_421)
+ {
+ inputerr = true;
+ goto readabort;
+ }
+ }
(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
c);
- c = '\r';
+ if (BARE_CR_SP)
+ c = ' ';
+ else
+ c = '\r';
istate = IS_NORM;
}
goto bufferchar;
@@ -499,7 +618,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
istate = IS_CR;
continue;
}
- else if (c == '\n')
+ else if (c == '\n' && !SMTPMODE_STRICT)
istate = IS_BOL;
else
istate = IS_NORM;
@@ -524,7 +643,8 @@ bufferchar:
if (!bitset(EF_TOOBIG, e->e_flags))
(void) sm_io_putc(df, SM_TIME_DEFAULT,
c);
-
+ if (TTD(30, 64))
+ sm_dprintf("state=%s, put=%s %#x\n", ISTATE, makeprint((char) c), c);
/* FALLTHROUGH */
case MS_DISCARD:
@@ -540,10 +660,9 @@ bufferchar:
/* out of space for header */
obuf = buf;
- if (buflen < MEMCHUNKSIZE)
- buflen *= 2;
- else
- buflen += MEMCHUNKSIZE;
+ buflen = incbuflen(buflen);
+ if (tTd(30, 32))
+ sm_dprintf("buflen=%d, hdrslen=%d\n", buflen, hdrslen);
if (buflen <= 0)
{
sm_syslog(LOG_NOTICE, e->e_id,
@@ -592,8 +711,8 @@ bufferchar:
nextstate:
if (tTd(30, 35))
- sm_dprintf("nextstate, istate=%d, mstate=%d, line=\"%s\"\n",
- istate, mstate, buf);
+ sm_dprintf("nextstate, istate=%s, mstate=%d, line=\"%s\"\n",
+ ISTATE, mstate, buf);
switch (mstate)
{
case MS_UFROM:
@@ -624,7 +743,7 @@ nextstate:
/* timeout? */
if (c == SM_IO_EOF && errno == EAGAIN
- && smtpmode)
+ && SMTPMODE)
{
/*
** Override e_message in
@@ -653,7 +772,7 @@ nextstate:
/* guaranteed by isheader(buf) */
SM_ASSERT(*(bp - 1) != '\n' || bp > buf + 1);
- /* trim off trailing CRLF or NL */
+ /* trim off trailing CRLF or LF */
if (*--bp != '\n' || *--bp != '\r')
bp++;
*bp = '\0';
@@ -673,7 +792,7 @@ nextstate:
sm_dprintf("EOH\n");
if (headeronly)
- goto readerr;
+ goto readdone;
df = collect_eoh(e, numhdrs, hdrslen);
if (df == NULL)
@@ -700,8 +819,8 @@ nextstate:
bp = buf;
}
-readerr:
- if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp))
+readdone:
+ if ((sm_io_eof(fp) && SMTPMODE) || sm_io_error(fp))
{
const char *errmsg;
@@ -741,7 +860,7 @@ readerr:
}
else if (SuperSafe == SAFE_NO ||
SuperSafe == SAFE_INTERACTIVE ||
- (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode))
+ (SuperSafe == SAFE_REALLY_POSTMILTER && SMTPMODE))
{
/* skip next few clauses */
/* EMPTY */
@@ -806,33 +925,43 @@ readerr:
readabort:
if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
{
- char *host;
char *problem;
ADDRESS *q;
- host = RealHostName;
- if (host == NULL)
- host = "localhost";
-
if (sm_io_eof(fp))
problem = "unexpected close";
else if (sm_io_error(fp))
problem = "I/O error";
+ else if (0 != bare_lf)
+ problem = BARE_LF_MSG;
+ else if (0 != bare_cr)
+ problem = BARE_CR_MSG;
else
problem = "read timeout";
- if (LogLevel > 0 && sm_io_eof(fp))
+
+#define LOG_CLT ((NULL != RealHostName) ? RealHostName: "localhost")
+#define CONN_ERR_TXT "collect: relay=%s, from=%s, info=%s%s%s%s"
+#define CONN_ERR_CODE "421 4.4.1 "
+#define CONN_LOG_FROM shortenstring(e->e_from.q_paddr, MAXSHORTSTR)
+#define CONN_ERR_BARE (0 != bare_lf) ? BARE_LF_MSG : ((0 != bare_cr) ? BARE_CR_MSG : "")
+#define CONN_ERR_WHERE(bare_xy) (BARE_IN_HDR==(bare_xy) ? "header" : \
+ (BARE_IN_BDY==(bare_xy) ? "body" : "header+body"))
+
+#define HAS_BARE_XY (0 != (bare_lf | bare_cr))
+#define CONN_ERR_ARGS LOG_CLT, CONN_LOG_FROM, problem, \
+ HAS_BARE_XY ? ", where=" : "", \
+ HAS_BARE_XY ? CONN_ERR_WHERE(bare_lf|bare_cr) : "", \
+ HAS_BARE_XY ? ", status=tempfail" : ""
+
+ if (LogLevel > 0 && (sm_io_eof(fp) || (0 != (bare_lf | bare_cr))))
sm_syslog(LOG_NOTICE, e->e_id,
- "collect: %s on connection from %.100s, sender=%s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
- if (sm_io_eof(fp))
- usrerr("421 4.4.1 collect: %s on connection from %s, from=%s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+ CONN_ERR_TXT, CONN_ERR_ARGS);
+ if (0 != (bare_lf | bare_cr))
+ usrerr("421 4.5.0 %s", CONN_ERR_BARE);
+ else if (sm_io_eof(fp))
+ usrerr(CONN_ERR_CODE CONN_ERR_TXT, CONN_ERR_ARGS);
else
- syserr("421 4.4.1 collect: %s on connection from %s, from=%s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+ syserr(CONN_ERR_CODE CONN_ERR_TXT, CONN_ERR_ARGS);
flush_errors(true);
/* don't return an error indication */
@@ -863,6 +992,21 @@ readerr:
e->e_flags &= ~EF_LOGSENDER;
}
+#define LOG_BARE_XY(bare_xy, bare_xy_sp, bare_xy_msg) \
+ do \
+ { \
+ if ((0 != bare_xy) && LogLevel > 8) \
+ sm_syslog(LOG_NOTICE, e->e_id, \
+ "collect: relay=%s, from=%s, info=%s, where=%s%s" \
+ , LOG_CLT, CONN_LOG_FROM, bare_xy_msg \
+ , CONN_ERR_WHERE(bare_xy) \
+ , bare_xy_sp ? ", status=replaced" : "" \
+ ); \
+ } while (0)
+
+ LOG_BARE_XY(bare_lf, BARE_LF_SP, BARE_LF_MSG);
+ LOG_BARE_XY(bare_cr, BARE_CR_SP, BARE_CR_MSG);
+
/* check for message too large */
if (bitset(EF_TOOBIG, e->e_flags))
{
@@ -947,7 +1091,7 @@ readerr:
/*
** DFERROR -- signal error on writing the data file.
**
-** Called by collect(). Collect() always terminates the process
+** Called by collect(). collect() always terminates the process
** immediately after calling dferror(), which means that the SMTP
** session will be terminated, which means that any error message
** issued by dferror must be a 421 error, as per RFC 821.
diff --git a/contrib/sendmail/src/conf.c b/contrib/sendmail/src/conf.c
index e7a9615c23ab..37c5062eee92 100644
--- a/contrib/sendmail/src/conf.c
+++ b/contrib/sendmail/src/conf.c
@@ -81,7 +81,6 @@ static struct hostent *sm_getipnodebyaddr __P((const void *, size_t, int, int *)
** this file too much, you may be making a mistake!
*/
-
/*
** Header info table
** Final (null) entry contains the flags used for any other field.
@@ -164,14 +163,14 @@ struct prival PrivacyValues[] =
{ "needvrfyhelo", PRIV_NEEDVRFYHELO },
{ "noexpn", PRIV_NOEXPN },
{ "novrfy", PRIV_NOVRFY },
- { "restrictexpand", PRIV_RESTRICTEXPAND },
+ { "authwarnings", PRIV_AUTHWARNINGS },
+ { "noverb", PRIV_NOVERB },
{ "restrictmailq", PRIV_RESTRICTMAILQ },
{ "restrictqrun", PRIV_RESTRICTQRUN },
+ { "restrictexpand", PRIV_RESTRICTEXPAND },
{ "noetrn", PRIV_NOETRN },
- { "noverb", PRIV_NOVERB },
- { "authwarnings", PRIV_AUTHWARNINGS },
- { "noreceipts", PRIV_NORECEIPTS },
{ "nobodyreturn", PRIV_NOBODYRETN },
+ { "noreceipts", PRIV_NORECEIPTS },
{ "goaway", PRIV_GOAWAY },
{ "noactualrecipient", PRIV_NOACTUALRECIPIENT },
#if _FFR_NOREFLECT
@@ -196,7 +195,6 @@ struct dbsval DontBlameSendmailValues[] =
{ "groupwritablealiasfile", DBS_GROUPWRITABLEALIASFILE },
{ "worldwritablealiasfile", DBS_WORLDWRITABLEALIASFILE },
{ "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH },
- { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH },
{ "mapinunsafedirpath", DBS_MAPINUNSAFEDIRPATH },
{ "linkedaliasfileinwritabledir",
DBS_LINKEDALIASFILEINWRITABLEDIR },
@@ -228,6 +226,7 @@ struct dbsval DontBlameSendmailValues[] =
DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE },
{ "runprograminunsafedirpath", DBS_RUNPROGRAMINUNSAFEDIRPATH },
{ "runwritableprogram", DBS_RUNWRITABLEPROGRAM },
+ { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH },
{ "nonrootsafeaddr", DBS_NONROOTSAFEADDR },
{ "truststickybit", DBS_TRUSTSTICKYBIT },
{ "dontwarnforwardfileinunsafedirpath",
@@ -242,6 +241,7 @@ struct dbsval DontBlameSendmailValues[] =
{ "groupreadablekeyfile", DBS_GROUPREADABLEKEYFILE },
{ "groupreadabledefaultauthinfofile",
DBS_GROUPREADABLEAUTHINFOFILE },
+ { "certowner", DBS_CERTOWNER },
{ NULL, 0 }
};
@@ -1409,7 +1409,6 @@ init_md(argc, argv)
# endif /* _SCO_unix_ */
#endif /* SECUREWARE || defined(_SCO_unix_) */
-
#ifdef VENDOR_DEFAULT
VendorCode = VENDOR_DEFAULT;
#else
@@ -2317,7 +2316,6 @@ refuseconnections(e, dn, active)
conncnt[dn] = 0;
}
-
#if _FFR_MEMSTAT
if (RefuseLowMem > 0 &&
sm_memstat_get(MemoryResource, &memfree) >= 0 &&
@@ -2432,7 +2430,6 @@ refuseconnections(e, dn, active)
# define SPT_TYPE SPT_REUSEARGV
#endif
-
#if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
# if SPT_TYPE == SPT_PSTAT
@@ -3057,7 +3054,6 @@ dgux_inet_addr(host)
* specifies the terms and conditions for redistribution.
*/
-
/*
** this version hacked to add `atend' flag to allow state machine
** to reset if invoked by the program to scan args for a 2nd time
@@ -3637,8 +3633,11 @@ lockfile(fd, filename, ext, type)
action = F_SETLKW;
if (tTd(55, 60))
- sm_dprintf("lockfile(%s%s, action=%d, type=%d): ",
- filename, ext, action, lfd.l_type);
+ sm_dprintf("lockfile(%s%s, fd=%d, action=%s, type=%s): ",
+ filename, ext, fd,
+ bitset(LOCK_NB, type) ? "nb" : "block",
+ bitset(LOCK_UN, type) ? "unlock" :
+ (bitset(LOCK_EX, type) ? "wr" : "rd"));
while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
continue;
if (i >= 0)
@@ -3684,7 +3683,9 @@ lockfile(fd, filename, ext, type)
ext = "";
if (tTd(55, 60))
- sm_dprintf("lockfile(%s%s, type=%o): ", filename, ext, type);
+ sm_dprintf("lockfile(%s%s, fd=%d, type=%s): ", filename, ext,
+ fd, bitset(LOCK_UN, type) ? "unlock" :
+ (bitset(LOCK_EX, type) ? "wr" : "rd"));
while ((i = flock(fd, type)) < 0 && errno == EINTR)
continue;
@@ -3981,7 +3982,6 @@ vendor_pre_defaults(e)
#endif /* apollo */
}
-
void
vendor_post_defaults(e)
ENVELOPE *e;
@@ -4701,7 +4701,7 @@ add_hostnames(sa)
char **ha;
char hnb[MAXHOSTNAMELEN];
- /* lookup name with IP address */
+ /* look up name with IP address */
switch (sa->sa.sa_family)
{
#if NETINET
@@ -5290,8 +5290,12 @@ isloopback(sa)
SOCKADDR sa;
{
/* XXX how to correctly extract IN_LOOPBACKNET part? */
-#define SM_IS_IPV4_LOOP(a) (((ntohl(a) & IN_CLASSA_NET) \
+#ifdef IN_LOOPBACK
+# define SM_IS_IPV4_LOOP(a) IN_LOOPBACK(ntohl(a))
+#else /* IN_LOOPBACK */
+# define SM_IS_IPV4_LOOP(a) (((ntohl(a) & IN_CLASSA_NET) \
>> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+# endif /* IN_LOOPBACK */
#if NETINET6
if (sa.sa.sa_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&sa.sin6.sin6_addr) &&
@@ -5524,7 +5528,7 @@ sm_syslog(level, id, fmt, va_alist)
/* clean up buf after it has been expanded with args */
#if _FFR_LOGASIS >= 5
-/* for testing! */
+ /* for testing! maybe make it an -d option (hence runtime)? */
newstring = buf;
#else
newstring = str2prt(buf);
@@ -5850,6 +5854,12 @@ char *CompileOptions[] =
#if DANE
"DANE",
#endif
+#if HAVE_SSL_CTX_dane_enable
+ "HAVE_SSL_CTX_dane_enable",
+#endif
+#if MAX_TLSA_RR
+ "MAX_TLSA_RR=" SM_XSTR(MAX_TLSA_RR),
+#endif
#if NAMED_BIND
# if DNSMAP
"DNSMAP",
@@ -5875,19 +5885,11 @@ char *CompileOptions[] =
"LDAPMAP",
#endif
#if LDAP_NETWORK_TIMEOUT
-# if LDAPMAP
/* set LDAP_OPT_NETWORK_TIMEOUT if available (-c) */
"LDAP_NETWORK_TIMEOUT",
-# else
-# ERROR "LDAP_NETWORK_TIMEOUT requires LDAPMAP"
-# endif
#endif
#if LDAP_REFERRALS
-# if LDAPMAP
"LDAP_REFERRALS",
-# else
-# ERROR "LDAP_REFERRALS requires LDAPMAP"
-# endif
#endif
#if LOG
"LOG",
@@ -5921,6 +5923,10 @@ char *CompileOptions[] =
#endif
#if NAMED_BIND
"NAMED_BIND",
+#else
+# if DANE
+# error "DANE requires NAMED_BIND"
+# endif
#endif
#if NDBM
"NDBM",
@@ -5951,8 +5957,23 @@ char *CompileOptions[] =
#endif
#if NEWDB
# if defined(DB_VERSION_MAJOR) && defined(DB_VERSION_MINOR)
-# if DB_VERSION_MAJOR >= 5 && !HASFLOCK
-# ERROR "Berkeley DB file locking needs flock() for version 5.x (and greater?)"
+# if DB_VERSION_MAJOR >= 5 && !defined(SOLARIS) && !HASFLOCK && !ACCEPT_BROKEN_BDB_LOCKING
+
+/*
+** NOTE: disabling this check by setting ACCEPT_BROKEN_BDB_LOCKING
+** means you are taking full responsibility for any problems
+** which may arise!
+**
+** Map locking will not work, and making a change to a map
+** while sendmail is using it can break mail handling.
+** At least you must stop all sendmail processes when using
+** makemap or newaliases - but there might be other things
+** which could break.
+**
+** You have been warned - use at your own risk!
+*/
+
+# error "Berkeley DB file locking needs flock() for version 5.x (and greater?)"
# endif
"NEWDB=" SM_XSTR(DB_VERSION_MAJOR) "." SM_XSTR(DB_VERSION_MINOR),
# else
@@ -6015,8 +6036,12 @@ char *CompileOptions[] =
"TLS_NO_RSA",
#endif
#if TLS_EC
+# if NO_DH
+# error "NO_DH disables TLS_EC"
+# else
/* elliptic curves */
"TLS_EC",
+# endif
#endif
#if TLS_VRFY_PER_CTX
"TLS_VRFY_PER_CTX",
@@ -6033,10 +6058,10 @@ char *CompileOptions[] =
*/
# if !ALLOW_255
-# ERROR "USE_EAI requires ALLOW_255"
+# error "USE_EAI requires ALLOW_255"
# endif
# if _FFR_EIGHT_BIT_ADDR_OK
-# ERROR "Cannot enable both USE_EAI and _FFR_EIGHT_BIT_ADDR_OK"
+# error "Cannot enable both USE_EAI and _FFR_EIGHT_BIT_ADDR_OK"
# endif
"USE_EAI",
#endif
@@ -6055,7 +6080,6 @@ char *CompileOptions[] =
NULL
};
-
/*
** OS compile options.
*/
@@ -6333,7 +6357,7 @@ char *FFRCompileOptions[] =
#endif
#if _FFR_ALLOW_SASLINFO
/* DefaultAuthInfo can be specified by user. */
- /* DefaultAuthInfo doesn't really work in 8.13 anymore. */
+ /* DefaultAuthInfo doesn't really work in 8.13ff anymore. */
"_FFR_ALLOW_SASLINFO",
#endif
#if _FFR_BADRCPT_SHUTDOWN
@@ -6361,6 +6385,10 @@ char *FFRCompileOptions[] =
/* Stricter checks about queue directory permissions. */
"_FFR_CHK_QUEUE",
#endif
+#if _FFR_CLASS_RM_ENTRY
+ /* WIP: remove entries from a class: C-{name}entry */
+ "_FFR_CLASS_RM_ENTRY",
+#endif
#if _FFR_CLIENTCA
/*
** Allow to set client specific CA values.
@@ -6441,8 +6469,17 @@ char *FFRCompileOptions[] =
"_FFR_DROP_TRUSTUSER_WARNING",
#endif
+#if _FFR_DYN_CLASS
+ /* dynamic classes based on maps */
+ "_FFR_DYN_CLASS",
+#endif
#if _FFR_EIGHT_BIT_ADDR_OK
- /* EightBitAddrOK: allow 8-bit e-mail addresses */
+ /*
+ ** EightBitAddrOK: allow all 8-bit e-mail addresses.
+ ** By default only ((ch & 0340) == 0200) is blocked
+ ** because that range is used for "META" chars.
+ */
+
"_FFR_EIGHT_BIT_ADDR_OK",
#endif
#if _FFR_EXPAND_HELONAME
@@ -6523,6 +6560,10 @@ char *FFRCompileOptions[] =
/* Local daemon mode (-bl) which only accepts loopback connections */
"_FFR_LOCAL_DAEMON",
#endif
+#if _FFR_LOG_FAILOVER
+ /* WIP: log reason why trying another host */
+ "_FFR_LOG_FAILOVER",
+#endif
#if _FFR_LOG_MORE1
/* log some TLS/AUTH info in from= too */
"_FFR_LOG_MORE1=" SM_XSTR(_FFR_LOG_MORE1),
@@ -6531,10 +6572,18 @@ char *FFRCompileOptions[] =
/* log some TLS info in to= too */
"_FFR_LOG_MORE2=" SM_XSTR(_FFR_LOG_MORE2),
#endif
+#if _FFR_LOG_STAGE
+ /* log protocol stage for delivery problems */
+ "_FFR_LOG_STAGE",
+#endif
#if _FFR_MAIL_MACRO
/* make the "real" sender address available in {mail_from} */
"_FFR_MAIL_MACRO",
#endif
+#if _FFR_MAP_CHK_FILE
+ /* check whether the underlying map file was changed */
+ "_FFR_MAP_CHK_FILE=" SM_XSTR(_FFR_MAP_CHK_FILE),
+#endif
#if _FFR_MAXDATASIZE
/*
** It is possible that a header is larger than MILTER_CHUNK_SIZE,
@@ -6564,6 +6613,7 @@ char *FFRCompileOptions[] =
"_FFR_MEMSTAT",
#endif
#if _FFR_MILTER_CHECK
+ /* for (lib)milter testing */
"_FFR_MILTER_CHECK",
#endif
#if _FFR_MILTER_CONNECT_REPLYCODE
@@ -6619,13 +6669,13 @@ char *FFRCompileOptions[] =
#endif
#if _FFR_MTA_STS
# if !MAP_REGEX
-# ERROR "_FFR_MTA_STS requires MAP_REGEX"
+# error "_FFR_MTA_STS requires MAP_REGEX"
# endif
# if !STARTTLS
-# ERROR "_FFR_MTA_STS requires STARTTLS"
+# error "_FFR_MTA_STS requires STARTTLS"
# endif
# if !_FFR_TLS_ALTNAMES
-# ERROR "_FFR_MTA_STS requires _FFR_TLS_ALTNAMES"
+# error "_FFR_MTA_STS requires _FFR_TLS_ALTNAMES"
# endif
/* MTA STS support */
"_FFR_MTA_STS",
@@ -6667,7 +6717,7 @@ char *FFRCompileOptions[] =
/* outgoing connection control (not yet working) */
"_FFR_OCC",
# else
-# ERROR "_FFR_OCC requires SM_CONF_SHM"
+# error "_FFR_OCC requires SM_CONF_SHM"
# endif
#endif
#if _FFR_PROXY
@@ -6741,12 +6791,19 @@ char *FFRCompileOptions[] =
"_FFR_SESSID",
#endif
#if _FFR_SETANYOPT
+ /*
+ ** if _FFR_SETOPT_MAP is used: allow to set any option
+ ** (which probably does not work as expected for many options).
+ */
+
"_FFR_SETANYOPT",
#endif
#if _FFR_SETDEBUG_MAP
+ /* enable setdebug map to set debug levels from rules */
"_FFR_SETDEBUG_MAP",
#endif
#if _FFR_SETOPT_MAP
+ /* enable setopt map to set options from rules */
"_FFR_SETOPT_MAP",
#endif
#if _FFR_SHM_STATUS
@@ -6762,11 +6819,11 @@ char *FFRCompileOptions[] =
"_FFR_SLEEP_USE_SELECT",
#endif
#if _FFR_SM_LDAP_DBG
-# if LDAPMAP && defined(LBER_OPT_LOG_PRINT_FN)
+# if defined(LBER_OPT_LOG_PRINT_FN)
/* LDAP debugging */
"_FFR_SM_LDAP_DBG",
# else
-# ERROR "_FFR_SM_LDAP_DBG requires LDAPMAP and LBER_OPT_LOG_PRINT_FN"
+# error "_FFR_SM_LDAP_DBG requires LBER_OPT_LOG_PRINT_FN"
# endif
#endif
#if _FFR_SPT_ALIGN
@@ -6846,7 +6903,7 @@ char *FFRCompileOptions[] =
# if defined(X509_V_FLAG_TRUSTED_FIRST)
"_FFR_VRFY_TRUSTED_FIRST",
# else
-# ERROR "_FFR_VRFY_TRUSTED_FIRST set but X509_V_FLAG_TRUSTED_FIRST not defined"
+# error "_FFR_VRFY_TRUSTED_FIRST set but X509_V_FLAG_TRUSTED_FIRST not defined"
# endif
#endif
@@ -6863,11 +6920,20 @@ char *FFRCompileOptions[] =
/* X-Connect support */
"_FFR_XCNCT",
#endif
+#if _FFR_HAPROXY
+ /* HAproxy support */
+ "_FFR_HAPROXY",
+#endif
#if _FFR_LOGASIS
+ /* only convert char <= 31 to something printable for logging etc */
"_FFR_LOGASIS=" SM_XSTR(_FFR_LOGASIS),
#endif
+#if _FFR_NAMESERVER
+ /* Allow to override nameserver set by OS */
+ "_FFR_NAMESERVER",
+#endif
#if _FFR_NOREFLECT
- /* Don't forget to update docs for "goaway" to include this */
+ /* Do not include input from a client in a reply of the server */
"_FFR_NOREFLECT",
#endif
#if _FFR_AUTH_PASSING
@@ -6880,8 +6946,8 @@ char *FFRCompileOptions[] =
#endif
#if _FFR_MSP_PARANOIA
/*
- ** Forbid queue groups, multiple queues, and dangerous queue permissions
- ** when operating as an MSP
+ ** Forbid queue groups, multiple queues, and
+ ** dangerous queue permissions when operating as an MSP
*/
"_FFR_MSP_PARANOIA",
@@ -6902,5 +6968,13 @@ char *FFRCompileOptions[] =
"_FFR_MIME_CR_OK",
#endif
+#if _FFR_M_ONLY_IPV4
+ /* mailer flag 4: use only IPv4 for delivery attempts */
+ "_FFR_M_ONLY_IPV4",
+#endif
+#if _FFR_SMTPS_CLIENT
+ /* SMTP over TLS client (defaults to port 465/tcp outbound) */
+ "_FFR_SMTPS_CLIENT",
+#endif
NULL
};
diff --git a/contrib/sendmail/src/conf.h b/contrib/sendmail/src/conf.h
index 122b7614516f..9ebb3c7b9a11 100644
--- a/contrib/sendmail/src/conf.h
+++ b/contrib/sendmail/src/conf.h
@@ -78,7 +78,11 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
#define SMTPLINELIM 990 /* max SMTP line length */
#define MAXUDBKEY 128 /* max size of a database key (udb only) */
#define MAXKEY 1024 /* max size of a database key */
-#define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */
+#define MEMCHUNKSIZE 4096 /* chunk size for memory allocation */
+#if MEMCHUNKSIZE < MAXLINE
+/* see usage in collect.c */
+# error "MEMCHUNKSIZE must be at least MAXLINE"
+#endif
#define MAXUSERENVIRON 100 /* max envars saved, must be >= 3 */
#define MAXMAPSTACK 12 /* max # of stacked or sequenced maps */
#if MILTER
@@ -132,7 +136,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */
/* must be less than BITMAPBITS for DoQueueRun */
#endif
#if MAXQUEUEGROUPS >= BITMAPBITS
-# ERROR "MAXQUEUEGROUPS must be less than BITMAPBITS"
+# error "MAXQUEUEGROUPS must be less than BITMAPBITS"
#endif
#ifndef MAXWORKGROUPS
diff --git a/contrib/sendmail/src/control.c b/contrib/sendmail/src/control.c
index 1af2cf7cfd95..79a8304ce43f 100644
--- a/contrib/sendmail/src/control.c
+++ b/contrib/sendmail/src/control.c
@@ -41,8 +41,6 @@ static struct cmd CmdTab[] =
{ NULL, CMDERROR }
};
-
-
static void controltimeout __P((int));
int ControlSocket = -1;
diff --git a/contrib/sendmail/src/daemon.c b/contrib/sendmail/src/daemon.c
index 5b42e323b1cc..d37c5086e465 100644
--- a/contrib/sendmail/src/daemon.c
+++ b/contrib/sendmail/src/daemon.c
@@ -25,12 +25,7 @@ SM_RCSID("@(#)$Id: daemon.c,v 8.698 2013-11-22 20:51:55 ca Exp $")
# if NETINET || NETINET6
# include <arpa/inet.h>
# endif
-# if NAMED_BIND
-# ifndef NO_DATA
-# define NO_DATA NO_ADDRESS
-# endif
-# endif /* NAMED_BIND */
-#endif /* defined(USE_SOCK_STREAM) */
+#endif
#if STARTTLS
# include <openssl/rand.h>
@@ -170,7 +165,6 @@ getrequests(e)
#endif
extern ENVELOPE BlankEnvelope;
-
/* initialize data for function that generates queue ids */
init_qid_alg();
for (idx = 0; idx < NDaemons; idx++)
@@ -868,7 +862,6 @@ getrequests(e)
}
else
setbitn(t, Daemons[curdaemon].d_flags);
-
#endif /* _FFR_XCNCT */
#if XLA
@@ -1871,12 +1864,18 @@ static struct dflags DaemonFlags[] =
{ "UNQUALOK", D_UNQUALOK },
{ "NOAUTH", D_NOAUTH },
{ "NOCANON", D_NOCANON },
+ { "NODANE", D_NODANE },
{ "NOETRN", D_NOETRN },
+ { "NOSTS", D_NOSTS },
{ "NOTLS", D_NOTLS },
{ "ETRNONLY", D_ETRNONLY },
{ "OPTIONAL", D_OPTIONAL },
{ "DISABLE", D_DISABLE },
{ "ISSET", D_ISSET },
+#if _FFR_XCNCT
+ { "XCNCT", D_XCNCT },
+ { "XCNCT_M", D_XCNCT_M },
+#endif
{ NULL, 0 }
};
@@ -2160,7 +2159,7 @@ makeconnection(host, port, mci, e, enough
#if NETINET6
volatile bool v6found = false;
#endif
- volatile int family = InetMode;
+ volatile int family;
SOCKADDR_LEN_T len;
volatile SOCKADDR_LEN_T socksize = 0;
volatile bool clt_bind;
@@ -2179,8 +2178,14 @@ makeconnection(host, port, mci, e, enough
#if DANE
SM_REQUIRE(ptlsa_flags != NULL);
tlsa_flags = *ptlsa_flags;
- *ptlsa_flags &= ~(TLSAFLALWAYS|TLSAFLSECURE);
+ *ptlsa_flags &= ~TLSAFLADIP;
+#endif
+#if _FFR_M_ONLY_IPV4
+ if (bitnset(M_ONLY_IPV4, mci->mci_mailer->m_flags))
+ family = AF_INET;
+ else
#endif
+ family = InetMode;
/* retranslate {daemon_flags} into bitmap */
clrbitmap(d_flags);
@@ -2385,7 +2390,7 @@ makeconnection(host, port, mci, e, enough
p = &host[strlen(host) - 1];
#if DANE
if (tTd(16, 40))
- sm_dprintf("makeconnection: tlsa_flags=%lX, host=%s\n",
+ sm_dprintf("makeconnection: tlsa_flags=%#lx, host=%s\n",
tlsa_flags, host);
if (DANEMODE(tlsa_flags) == DANE_SECURE
# if DNSSEC_TEST
@@ -2408,13 +2413,16 @@ makeconnection(host, port, mci, e, enough
if (rr != NULL && rr->dns_r_h.ad == 1)
{
- *ptlsa_flags |= DANE_SECURE;
+ *ptlsa_flags |= TLSAFLADIP;
if ((TLSAFLTEMP & *ptlsa_flags) != 0)
{
dns_free_data(rr);
rr = NULL;
return EX_TEMPFAIL;
}
+ }
+ if (rr != NULL)
+ {
hp = dns2he(rr, family);
# if NETINET6
hs = hp;
@@ -2428,7 +2436,7 @@ makeconnection(host, port, mci, e, enough
dns_free_data(rr);
rr = NULL;
}
-#endif
+#endif /* DANE */
if (hp == NULL)
hp = sm_gethostbyname(host, family);
if (hp == NULL && *p == '.')
@@ -2544,21 +2552,21 @@ gothostent:
}
#if _FFR_TESTS
- /*
- ** Hack for testing.
- ** Hardcoded:
- ** 10.1.1.12: see meta1.tns XREF IP address
- ** 8754: see common.sh XREF SNKPORT2
- */
+ /*
+ ** Hack for testing.
+ ** Hardcoded:
+ ** 10.1.1.12: see meta1.tns XREF IP address
+ ** 8754: see common.sh XREF SNKPORT2
+ */
- if (tTd(77, 101) && hp != NULL && hp->h_addrtype == AF_INET &&
- addr.sin.sin_addr.s_addr == inet_addr("10.1.1.12"))
- {
- addr.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
- port = htons(8754);
- sm_dprintf("hack host=%s addr=[%s].%d\n", host,
- anynet_ntoa(&addr), ntohs(port));
- }
+ if (tTd(77, 101) && hp != NULL && hp->h_addrtype == AF_INET &&
+ addr.sin.sin_addr.s_addr == inet_addr("10.1.1.12"))
+ {
+ addr.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+ port = htons(8754);
+ sm_dprintf("hack host=%s addr=[%s].%d\n", host,
+ anynet_ntoa(&addr), ntohs(port));
+ }
#endif
/*
@@ -2568,16 +2576,34 @@ gothostent:
if (port == 0)
{
#ifdef NO_GETSERVBYNAME
- port = htons(25);
+# if _FFR_SMTPS_CLIENT
+ if (bitnset(M_SMTPS_CLIENT, mci->mci_mailer->m_flags))
+ port = htons(465);
+ else
+# endif /* _FFR_SMTPS_CLIENT */
+ port = htons(25);
#else /* NO_GETSERVBYNAME */
- register struct servent *sp = getservbyname("smtp", "tcp");
+ register struct servent *sp;
+
+# if _FFR_SMTPS_CLIENT
+ if (bitnset(M_SMTPS_CLIENT, mci->mci_mailer->m_flags))
+ p = "smtps";
+ else
+# endif /* _FFR_SMTPS_CLIENT */
+ p = "smtp";
+ sp = getservbyname(p, "tcp");
if (sp == NULL)
{
if (LogLevel > 2)
sm_syslog(LOG_ERR, NOQID,
- "makeconnection: service \"smtp\" unknown");
- port = htons(25);
+ "makeconnection: service \"%s\" unknown", p);
+# if _FFR_SMTPS_CLIENT
+ if (bitnset(M_SMTPS_CLIENT, mci->mci_mailer->m_flags))
+ port = htons(465);
+ else
+# endif /* _FFR_SMTPS_CLIENT */
+ port = htons(25);
}
else
port = sp->s_port;
@@ -2787,6 +2813,9 @@ gothostent:
if (setjmp(CtxConnectTimeout) == 0)
{
int i;
+#if _FFR_TESTS
+ int c_errno;
+#endif
if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
ev = sm_setevent(TimeOuts.to_iconnect,
@@ -2796,6 +2825,28 @@ gothostent:
connecttimeout, 0);
else
ev = NULL;
+#if _FFR_TESTS
+ i = 0;
+ c_errno = 0;
+ if (tTd(77, 101)
+ /* && AF_INET == addr.sin.sin_family */
+ && ntohl(addr.sin.sin_addr.s_addr) >=
+ ntohl(inet_addr("255.255.255.1"))
+ && ntohl(addr.sin.sin_addr.s_addr) <=
+ ntohl(inet_addr("255.255.255.255"))
+ )
+ {
+ i = -1;
+ c_errno = ntohl(addr.sin.sin_addr.s_addr) -
+ ntohl(inet_addr("255.255.255.0"));
+ sm_dprintf("hack: fail connection=%d, ip=%#x, lower=%#x\n",
+ c_errno
+ , ntohl(addr.sin.sin_addr.s_addr)
+ , ntohl(inet_addr("255.255.255.0")));
+ }
+ else
+#endif /* _FFR_TESTS */
+ /* "else" in #if code above */
switch (ConnectOnlyTo.sa.sa_family)
{
@@ -2829,24 +2880,11 @@ gothostent:
anynet_ntoa(&addr), ntohs(port));
#if _FFR_TESTS
- if (tTd(77, 101)
- /* && AF_INET == addr.sin.sin_family */
- && addr.sin.sin_addr.s_addr >=
- inet_addr("255.255.255.1")
- && addr.sin.sin_addr.s_addr <=
- inet_addr("255.255.255.255")
- )
- {
- i = -1;
- save_errno = ntohl(addr.sin.sin_addr.s_addr) -
- ntohl(inet_addr("255.255.255.0"));
- sm_dprintf("hack: fail connection=%d\n",
- save_errno);
- errno = save_errno;
- }
+ if (-1 == i)
+ errno = c_errno;
else
- /* Watch out of changes below! */
-#endif /* _FFR_TESTS */
+#endif
+ /* "else" in #if code above */
i = connect(s, (struct sockaddr *) &addr, addrlen);
save_errno = errno;
if (ev != NULL)
@@ -4200,7 +4238,7 @@ host_map_lookup(map, name, av, statp)
#if USE_EAI
bool utf8;
- utf8 = !addr_is_ascii(name);
+ utf8 = !str_is_print(name);
if (utf8)
{
(void) sm_strlcpy(hbuf, hn2alabel(name), sizeof(hbuf));
@@ -4314,7 +4352,6 @@ host_map_lookup(map, name, av, statp)
return cp;
}
-
/* No match found */
s->s_namecanon.nc_errno = errno;
#if NAMED_BIND
diff --git a/contrib/sendmail/src/daemon.h b/contrib/sendmail/src/daemon.h
index fa4e681a10b8..f7cb3c3efeab 100644
--- a/contrib/sendmail/src/daemon.h
+++ b/contrib/sendmail/src/daemon.h
@@ -13,7 +13,7 @@
#define DAEMON_H 1
#if DAEMON_C
-# define EXTERN
+# define EXTERN
#else
# define EXTERN extern
#endif
diff --git a/contrib/sendmail/src/deliver.c b/contrib/sendmail/src/deliver.c
index 7d8008d80ac8..b5027f52ad42 100644
--- a/contrib/sendmail/src/deliver.c
+++ b/contrib/sendmail/src/deliver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2010, 2012 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2010, 2012, 2020-2023 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -31,27 +31,75 @@ SM_RCSID("@(#)$Id: deliver.c,v 8.1030 2013-11-22 20:51:55 ca Exp $")
# include "tls.h"
#endif
+#if !_FFR_DMTRIGGER
static int deliver __P((ENVELOPE *, ADDRESS *));
+#endif
static void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
static void mailfiletimeout __P((int));
static void endwaittimeout __P((int));
-static int parse_hostsignature __P((char *, char **, MAILER *));
+static int parse_hostsignature __P((char *, char **, MAILER *
+#if DANE
+ , BITMAP256
+#endif
+ ));
static void sendenvelope __P((ENVELOPE *, int));
static int coloncmp __P((const char *, const char *));
+
#if STARTTLS
# include <openssl/err.h>
# if DANE
-static int starttls __P((MAILER *, MCI *, ENVELOPE *, dane_vrfy_ctx_P));
-# else
-static int starttls __P((MAILER *, MCI *, ENVELOPE *));
-# endif
+static int starttls __P((MAILER *, MCI *, ENVELOPE *, bool, dane_vrfy_ctx_P));
+
+# define MXADS_ISSET(mxads, i) (0 != bitnset(bitidx(i), mxads))
+# define MXADS_SET(mxads, i) setbitn(bitidx(i), mxads)
+
+/* use "marks" in hostsignature for "had ad"? (WIP) */
+# ifndef HSMARKS
+# define HSMARKS 1
+# endif
+# if HSMARKS
+# define HSM_AD '+' /* mark for hostsignature: ad flag */
+# define DANE_SEC(dane) (DANE_SECURE == DANEMODE((dane)))
+# endif
+# else /* DANE */
+static int starttls __P((MAILER *, MCI *, ENVELOPE *, bool));
+# define MXADS_ISSET(mxads, i) 0
+# endif /* DANE */
static int endtlsclt __P((MCI *));
#endif /* STARTTLS */
#if STARTTLS || SASL
static bool iscltflgset __P((ENVELOPE *, int));
#endif
+#define SEP_MXHOSTS(endp, sep) \
+ if (endp != NULL) \
+ { \
+ sep = *endp; \
+ *endp = '\0'; \
+ }
+
+#if NETINET6
+# define FIX_MXHOSTS(hp, endp, sep) \
+ do { \
+ if (*hp == '[') \
+ { \
+ endp = strchr(hp + 1, ']'); \
+ if (endp != NULL) \
+ endp = strpbrk(endp + 1, ":,"); \
+ } \
+ else \
+ endp = strpbrk(hp, ":,"); \
+ SEP_MXHOSTS(endp, sep); \
+ } while (0)
+#else /* NETINET6 */
+# define FIX_MXHOSTS(hp, endp, sep) \
+ do { \
+ endp = strpbrk(hp, ":,"); \
+ SEP_MXHOSTS(endp, sep); \
+ } while (0)
+#endif /* NETINET6 */
+
#if _FFR_OCC
# include <ratectrl.h>
#endif
@@ -59,6 +107,47 @@ static bool iscltflgset __P((ENVELOPE *, int));
#define ESCNULLMXRCPT "5.1.10"
#define ERRNULLMX "556 Host does not accept mail: MX 0 ."
+#if _FFR_LOG_FAILOVER
+/*
+** These are not very useful to show the protocol stage,
+** but it's better than nothing right now.
+** XXX the actual values must be 0..N, otherwise a lookup
+** table must be used!
+*/
+
+static char *mcis[] =
+{
+ "CLOSED",
+ "GREET",
+ "OPEN",
+ "MAIL",
+ "RCPT",
+ "DATA",
+ "QUITING",
+ "SSD",
+ "ERROR",
+ NULL
+};
+#endif /* _FFR_LOG_FAILOVER */
+
+#if _FFR_LOG_STAGE
+static char *xs_states[] =
+{
+ "none",
+ "STARTTLS",
+ "AUTH",
+ "GREET",
+ "EHLO",
+ "MAIL",
+ "RCPT",
+ "DATA",
+ "EOM",
+ "DATA2",
+ "QUIT",
+ NULL
+};
+#endif /* _FFR_LOG_STAGE */
+
/*
** SENDALL -- actually send all the messages.
**
@@ -1144,6 +1233,7 @@ dofork()
** HS_MATCH_FIRST -- "match" for the first MX preference
** (up to the first colon (':')).
** HS_MATCH_FULL -- match for the entire MX record.
+** HS_MATCH_SKIP -- match but only one of the entries has a "mark"
**
** Side Effects:
** none.
@@ -1152,6 +1242,7 @@ dofork()
#define HS_MATCH_NO 0
#define HS_MATCH_FIRST 1
#define HS_MATCH_FULL 2
+#define HS_MATCH_SKIP 4
static int
coloncmp(a, b)
@@ -1160,7 +1251,21 @@ coloncmp(a, b)
{
int ret = HS_MATCH_NO;
int braclev = 0;
+# if HSMARKS
+ bool a_hsmark = false;
+ bool b_hsmark = false;
+ if (HSM_AD == *a)
+ {
+ a_hsmark = true;
+ ++a;
+ }
+ if (HSM_AD == *b)
+ {
+ b_hsmark = true;
+ ++b;
+ }
+# endif
while (*a == *b++)
{
/* Need to account for IPv6 bracketed addresses */
@@ -1175,7 +1280,14 @@ coloncmp(a, b)
break;
}
else if (*a == '\0')
+ {
+# if HSMARKS
+ /* exactly one mark */
+ if (a_hsmark != b_hsmark)
+ return HS_MATCH_SKIP;
+# endif
return HS_MATCH_FULL; /* a full match */
+ }
a++;
}
if (ret == HS_MATCH_NO &&
@@ -1184,7 +1296,14 @@ coloncmp(a, b)
(*a == ':' && *(b - 1) == '\0')))
return HS_MATCH_FIRST;
if (ret == HS_MATCH_FIRST && strcmp(a, b) == 0)
+ {
+# if HSMARKS
+ /* exactly one mark */
+ if (a_hsmark != b_hsmark)
+ return HS_MATCH_SKIP;
+# endif
return HS_MATCH_FULL;
+ }
return ret;
}
@@ -1235,12 +1354,13 @@ should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status)
return false;
}
+#if STARTTLS || SASL
/*
** CLTFEATURES -- Get features for SMTP client
**
** Parameters:
** e -- envelope
-** clientname -- name of client.
+** servername -- name of server.
**
** Returns:
** EX_OK or EX_TEMPFAIL
@@ -1248,9 +1368,9 @@ should_try_fbsh(e, tried_fallbacksmarthost, hostbuf, hbsz, status)
static int cltfeatures __P((ENVELOPE *, char *));
static int
-cltfeatures(e, clientname)
+cltfeatures(e, servername)
ENVELOPE *e;
- char *clientname;
+ char *servername;
{
int r, i, idx;
char **pvp, c;
@@ -1261,7 +1381,7 @@ cltfeatures(e, clientname)
SM_ASSERT(e->e_mci != NULL);
macdefine(&e->e_mci->mci_macro, A_PERM, macid("{client_flags}"), "");
pvp = NULL;
- r = rscap("clt_features", clientname, "", e, &pvp, pvpbuf,
+ r = rscap("clt_features", servername, NULL, e, &pvp, pvpbuf,
sizeof(pvpbuf));
if (r != EX_OK)
return EX_OK;
@@ -1287,10 +1407,201 @@ cltfeatures(e, clientname)
macdefine(&e->e_mci->mci_macro, A_TEMP, macid("{client_flags}"), flags);
if (tTd(10, 30))
- sm_dprintf("cltfeatures: mci=%p, flags=%s, {client_flags}=%s\n",
- e->e_mci, flags, macvalue(macid("{client_flags}"), e));
+ sm_dprintf("cltfeatures: server=%s, mci=%p, flags=%s, {client_flags}=%s\n",
+ servername, e->e_mci, flags,
+ macvalue(macid("{client_flags}"), e));
return EX_OK;
}
+#endif /* STARTTLS || SASL */
+
+#if _FFR_LOG_FAILOVER
+/*
+** LOGFAILOVER -- log reason why trying another host
+**
+** Parameters:
+** e -- envelope
+** m -- the mailer info for this mailer
+** mci -- mailer connection information
+** rcode -- the code signifying the particular failure
+** rcpt -- current RCPT
+**
+** Returns:
+** none.
+*/
+
+static void logfailover __P((ENVELOPE *, MAILER *, MCI *, int, ADDRESS *));
+static void
+logfailover(e, m, mci, rcode, rcpt)
+ ENVELOPE *e;
+ MAILER *m;
+ MCI *mci;
+ int rcode;
+ ADDRESS *rcpt;
+{
+ char buf[MAXNAME];
+ char cbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];
+
+ buf[0] = '\0';
+ cbuf[0] = '\0';
+ sm_strlcat(cbuf, "deliver: ", sizeof(cbuf));
+ if (m != NULL && m->m_name != NULL)
+ {
+ sm_snprintf(buf, sizeof(buf),
+ "mailer=%s, ", m->m_name);
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ }
+ if (mci != NULL && mci->mci_host != NULL)
+ {
+ extern SOCKADDR CurHostAddr;
+
+ sm_snprintf(buf, sizeof(buf),
+ "relay=%.100s", mci->mci_host);
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ if (CurHostAddr.sa.sa_family != 0)
+ {
+ sm_snprintf(buf, sizeof(buf),
+ " [%.100s]",
+ anynet_ntoa(&CurHostAddr));
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ }
+ sm_strlcat(cbuf, ", ", sizeof(cbuf));
+ }
+ if (mci != NULL)
+ {
+ if (mci->mci_state >= 0 && mci->mci_state < SM_ARRAY_SIZE(mcis))
+ sm_snprintf(buf, sizeof(buf),
+ "state=%s, ", mcis[mci->mci_state]);
+ else
+ sm_snprintf(buf, sizeof(buf),
+ "state=%d, ", mci->mci_state);
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ }
+ if (tTd(11, 64))
+ {
+ sm_snprintf(buf, sizeof(buf),
+ "rcode=%d, okrcpts=%d, retryrcpt=%d, e_rcode=%d, ",
+ rcode, mci->mci_okrcpts, mci->mci_retryrcpt,
+ e->e_rcode);
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ }
+ if (rcode != EX_OK && rcpt != NULL
+ && !SM_IS_EMPTY(rcpt->q_rstatus)
+ && !bitset(QINTREPLY, rcpt->q_flags))
+ {
+ sm_snprintf(buf, sizeof(buf),
+ "q_rstatus=%s, ", rcpt->q_rstatus);
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ }
+ else if (e->e_text != NULL)
+ {
+ sm_snprintf(buf, sizeof(buf),
+ "reply=%d %s%s%s, ",
+ e->e_rcode,
+ e->e_renhsc,
+ (e->e_renhsc[0] != '\0') ? " " : "",
+ e->e_text);
+ sm_strlcat(cbuf, buf, sizeof(cbuf));
+ }
+ sm_strlcat(cbuf,
+ "stat=tempfail: trying next host",
+ sizeof(cbuf));
+ sm_syslog(LOG_INFO, e->e_id, "%s", cbuf);
+}
+#else /* _FFR_LOG_FAILOVER */
+# define logfailover(e, m, mci, rcode, rcpt) ((void) 0)
+#endif /* _FFR_LOG_FAILOVER */
+
+#if STARTTLS || SASL
+# define RM_TRAIL_DOT(name) \
+ do { \
+ dotpos = strlen(name) - 1; \
+ if (dotpos >= 0) \
+ { \
+ if (name[dotpos] == '.') \
+ name[dotpos] = '\0'; \
+ else \
+ dotpos = -1; \
+ } \
+ } while (0)
+
+# define FIX_TRAIL_DOT(name) \
+ do { \
+ if (dotpos >= 0) \
+ name[dotpos] = '.'; \
+ } while (0)
+
+
+/*
+** SETSERVERMACROS -- set ${server_addr} and ${server_name}
+**
+** Parameters:
+** mci -- mailer connection information
+** pdotpos -- return pointer to former dot position in hostname
+**
+** Returns:
+** server name
+*/
+
+static char *setservermacros __P((MCI *, int *));
+
+static char *
+setservermacros(mci, pdotpos)
+ MCI *mci;
+ int *pdotpos;
+{
+ char *srvname;
+ int dotpos;
+ extern SOCKADDR CurHostAddr;
+
+ /* don't use CurHostName, it is changed in many places */
+ if (mci->mci_host != NULL)
+ {
+ srvname = mci->mci_host;
+ RM_TRAIL_DOT(srvname);
+ }
+ else if (mci->mci_mailer != NULL)
+ {
+ srvname = mci->mci_mailer->m_name;
+ dotpos = -1;
+ }
+ else
+ {
+ srvname = "local";
+ dotpos = -1;
+ }
+
+ /* don't set {server_name} to NULL or "": see getauth() */
+ macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"),
+ srvname);
+
+ /* CurHostAddr is set by makeconnection() and mci_get() */
+ if (CurHostAddr.sa.sa_family != 0)
+ {
+ macdefine(&mci->mci_macro, A_TEMP,
+ macid("{server_addr}"),
+ anynet_ntoa(&CurHostAddr));
+ }
+ else if (mci->mci_mailer != NULL)
+ {
+ /* mailer name is unique, use it as address */
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{server_addr}"),
+ mci->mci_mailer->m_name);
+ }
+ else
+ {
+ /* don't set it to NULL or "": see getauth() */
+ macdefine(&mci->mci_macro, A_PERM,
+ macid("{server_addr}"), "0");
+ }
+
+ if (pdotpos != NULL)
+ *pdotpos = dotpos;
+ else
+ FIX_TRAIL_DOT(srvname);
+ return srvname;
+}
+#endif /* STARTTLS || SASL */
/*
** DELIVER -- Deliver a message to a list of addresses.
@@ -1352,7 +1663,10 @@ cltfeatures(e, clientname)
** The standard input is passed off to someone.
*/
-static int
+#if !_FFR_DMTRIGGER
+static
+#endif
+int
deliver(e, firstto)
register ENVELOPE *e;
ADDRESS *firstto;
@@ -1390,35 +1704,44 @@ deliver(e, firstto)
bool ovr;
bool quarantine;
#if STARTTLS
+ bool implicittls = false;
+# if _FFR_SMTPS_CLIENT
+ bool smtptls = false;
+# endif
/* 0: try TLS, 1: try without TLS again, >1: don't try again */
int tlsstate;
# if DANE
dane_vrfy_ctx_T dane_vrfy_ctx;
STAB *ste;
-# endif
-#endif
-#if STARTTLS || SASL
- int dotpos;
+ char *vrfy;
+ int dane_req;
-# define RM_TRAIL_DOT(name) \
- do { \
- dotpos = strlen(name) - 1; \
- if (dotpos >= 0) \
- { \
- if (name[dotpos] == '.') \
- name[dotpos] = '\0'; \
- else \
- dotpos = -1; \
- } \
- } while (0)
+/* should this allow DANE_ALWAYS == DANEMODE(dane)? */
+# define RCPT_MXSECURE(rcpt) (0 != ((rcpt)->q_flags & QMXSECURE))
-# define FIX_TRAIL_DOT(name) \
- do { \
- if (dotpos >= 0) \
- name[dotpos] = '.'; \
- } while (0)
+# define STE_HAS_TLSA(ste) ((ste) != NULL && (ste)->s_tlsa != NULL)
-#endif
+/* NOTE: the following macros use some local variables directly! */
+# define RCPT_HAS_DANE(rcpt) (RCPT_MXSECURE(rcpt) \
+ && !iscltflgset(e, D_NODANE) \
+ && STE_HAS_TLSA(ste) \
+ && (0 == (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLTEMPVRFY)) \
+ && (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLADIP)) \
+ && CHK_DANE(dane_vrfy_ctx.dane_vrfy_chk) \
+ )
+
+# define RCPT_REQ_DANE(rcpt) (RCPT_HAS_DANE(rcpt) \
+ && TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP))
+
+# define RCPT_REQ_TLS(rcpt) (RCPT_HAS_DANE(rcpt) \
+ && TLSA_IS_FL(ste->s_tlsa, TLSAFLUNS))
+
+# define CHK_DANE_RCPT(dane, rcpt) (CHK_DANE(dane) && \
+ (RCPT_MXSECURE(rcpt) || DANE_ALWAYS == DANEMODE(dane)))
+
+ BITMAP256 mxads;
+# endif /* DANE */
+#endif /* STARTTLS */
int strsize;
int rcptcount;
int ret;
@@ -1431,6 +1754,9 @@ deliver(e, firstto)
char *pv[MAXPV + 1];
char buf[MAXNAME + 1]; /* EAI:ok */
char cbuf[MAXPATHLEN];
+#if _FFR_8BITENVADDR
+ char xbuf[SM_MAX(SYSLOG_BUFSIZE, MAXNAME)];
+#endif
errno = 0;
SM_REQUIRE(firstto != NULL); /* same as to */
@@ -1459,6 +1785,7 @@ deliver(e, firstto)
e->e_id, m->m_name, host, to->q_user);
if (tTd(10, 100))
printopenfds(false);
+ maps_reset_chged("deliver");
/*
** Clear {client_*} macros if this is a bounce message to
@@ -1511,6 +1838,9 @@ deliver(e, firstto)
}
rpath = sm_rpool_strdup_x(e->e_rpool, rpath);
macdefine(&e->e_macro, A_PERM, 'g', rpath);
+#if _FFR_8BITENVADDR
+ host = quote_internal_chars(host, NULL, &strsize, NULL);
+#endif
macdefine(&e->e_macro, A_PERM, 'h', host);
Errors = 0;
pvp = pv;
@@ -1556,7 +1886,27 @@ deliver(e, firstto)
/* this entry is safe -- go ahead and process it */
expand(*mvp, buf, sizeof(buf), e);
- *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
+ p = buf;
+#if _FFR_8BITENVADDR
+ /* apply to all args? */
+ if (strcmp(m->m_mailer, "[IPC]") == 0
+ && ((*mvp)[0] & 0377) == MACROEXPAND
+/* for now only apply [i] -> [x] conversion to $h by default */
+# ifndef _FFR_H2X_ONLY
+# define _FFR_H2X_ONLY 1
+# endif
+# if _FFR_H2X_ONLY
+ && 'h' == (*mvp)[1] && '\0' == (*mvp)[2]
+# endif
+ )
+ {
+ (void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
+ p = xbuf;
+ if (tTd(10, 33))
+ sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
+ }
+#endif /* _FFR_8BITENVADDR */
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
if (pvp >= &pv[MAXPV - 3])
{
syserr("554 5.3.5 Too many parameters to %s before $u",
@@ -1602,8 +1952,13 @@ deliver(e, firstto)
if (firstto->q_signature == NULL)
firstto->q_signature = hostsignature(firstto->q_mailer,
firstto->q_host,
- firstto->q_flags & QSECURE);
+ QISSECURE(firstto),
+ &firstto->q_flags);
firstsig = firstto->q_signature;
+#if DANE
+# define NODANEREQYET (-1)
+ dane_req = NODANEREQYET;
+#endif
for (; to != NULL; to = to->q_next)
{
@@ -1627,7 +1982,8 @@ deliver(e, firstto)
if (to->q_signature == NULL) /* for safety */
to->q_signature = hostsignature(to->q_mailer,
to->q_host,
- to->q_flags & QSECURE);
+ QISSECURE(to),
+ &to->q_flags);
/*
** This is for coincidental and tailcoat piggybacking messages
@@ -1646,6 +2002,10 @@ deliver(e, firstto)
skip_back = to;
else if (ret == HS_MATCH_NO)
break;
+# if HSMARKS
+ else if (ret == HS_MATCH_SKIP)
+ continue;
+# endif
if (!clever)
{
@@ -1658,6 +2018,45 @@ deliver(e, firstto)
if (++rcptcount > to->q_mailer->m_maxrcpt)
break;
+#if DANE
+ if (TTD(10, 30))
+ {
+ char sep = ':';
+
+ parse_hostsignature(to->q_signature, mxhosts, m, mxads);
+ FIX_MXHOSTS(mxhosts[0], p, sep);
+# if HSMARKS
+ if (MXADS_ISSET(mxads, 0))
+ to->q_flags |= QMXSECURE;
+ else
+ to->q_flags &= ~QMXSECURE;
+# endif
+
+ gettlsa(mxhosts[0], NULL, &ste, RCPT_MXSECURE(to) ? TLSAFLADMX : 0, 0, m->m_port);
+ sm_dprintf("tochain: to=%s, rcptcount=%d, QSECURE=%d, QMXSECURE=%d, MXADS[0]=%d, ste=%p\n",
+ to->q_user, rcptcount, QISSECURE(to),
+ RCPT_MXSECURE(to), MXADS_ISSET(mxads, 0), ste);
+ sm_dprintf("tochain: hostsig=%s, mx=%s, tlsa_n=%d, tlsa_flags=%#lx, chk_dane=%d, dane_req=%d\n"
+ , to->q_signature, mxhosts[0]
+ , STE_HAS_TLSA(ste) ? ste->s_tlsa->dane_tlsa_n : -1
+ , STE_HAS_TLSA(ste) ? ste->s_tlsa->dane_tlsa_flags : -1
+ , CHK_DANE_RCPT(Dane, to)
+ , dane_req
+ );
+ if (p != NULL)
+ *p = sep;
+ }
+ if (NODANEREQYET == dane_req)
+ dane_req = CHK_DANE_RCPT(Dane, to);
+ else if (dane_req != CHK_DANE_RCPT(Dane, to))
+ {
+ if (tTd(10, 30))
+ sm_dprintf("tochain: to=%s, rcptcount=%d, status=skip\n",
+ to->q_user, rcptcount);
+ continue;
+ }
+#endif /* DANE */
+
/*
** prepare envelope for new session to avoid leakage
** between delivery attempts.
@@ -1907,7 +2306,17 @@ deliver(e, firstto)
if (!clever)
{
expand(*mvp, buf, sizeof(buf), e);
- *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
+ p = buf;
+#if _FFR_8BITENVADDR
+ if (((*mvp)[0] & 0377) == MACROEXPAND)
+ {
+ (void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
+ p = xbuf;
+ if (tTd(10, 33))
+ sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
+ }
+#endif
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
if (pvp >= &pv[MAXPV - 2])
{
/* allow some space for trailing parms */
@@ -1954,7 +2363,18 @@ deliver(e, firstto)
while (*++mvp != NULL)
{
expand(*mvp, buf, sizeof(buf), e);
- *pvp++ = sm_rpool_strdup_x(e->e_rpool, buf);
+ p = buf;
+#if _FFR_8BITENVADDR && 0
+ /* disabled for now - is there a use case for this? */
+ if (((*mvp)[0] & 0377) == MACROEXPAND)
+ {
+ (void) dequote_internal_chars(buf, xbuf, sizeof(xbuf));
+ p = xbuf;
+ if (tTd(10, 33))
+ sm_dprintf("expand(%s), dequoted=%s\n", *mvp, p);
+ }
+#endif
+ *pvp++ = sm_rpool_strdup_x(e->e_rpool, p);
if (pvp >= &pv[MAXPV])
syserr("554 5.3.0 deliver: pv overflow after $u for %s",
pv[0]);
@@ -2092,7 +2512,9 @@ deliver(e, firstto)
{
CurHostName = pv[1];
/* XXX ??? */
- curhost = hostsignature(m, pv[1], firstto->q_flags & QSECURE);
+ curhost = hostsignature(m, pv[1],
+ QISSECURE(firstto),
+ &firstto->q_flags);
}
if (curhost == NULL || curhost[0] == '\0')
@@ -2130,7 +2552,11 @@ deliver(e, firstto)
}
}
- nummxhosts = parse_hostsignature(curhost, mxhosts, m);
+ nummxhosts = parse_hostsignature(curhost, mxhosts, m
+#if DANE
+ , mxads
+#endif
+ );
if (TimeOuts.to_aconnect > 0)
enough = curtime() + TimeOuts.to_aconnect;
tryhost:
@@ -2142,27 +2568,17 @@ tryhost:
bool tried_fallbacksmarthost = false;
#if DANE
unsigned long tlsa_flags;
+# if HSMARKS
+ bool mxsecure;
+# endif
ste = NULL;
tlsa_flags = 0;
-#endif
-#if NETINET6
- if (*mxhosts[hostnum] == '[')
- {
- endp = strchr(mxhosts[hostnum] + 1, ']');
- if (endp != NULL)
- endp = strpbrk(endp + 1, ":,");
- }
- else
- endp = strpbrk(mxhosts[hostnum], ":,");
-#else /* NETINET6 */
- endp = strpbrk(mxhosts[hostnum], ":,");
-#endif /* NETINET6 */
- if (endp != NULL)
- {
- sep = *endp;
- *endp = '\0';
- }
+# if HSMARKS
+ mxsecure = MXADS_ISSET(mxads, hostnum);
+# endif
+#endif /* DANE */
+ FIX_MXHOSTS(mxhosts[hostnum], endp, sep);
if (hostnum == 1 && skip_back != NULL)
{
@@ -2203,6 +2619,106 @@ tryhost:
/* see if we already know that this host is fried */
CurHostName = hostbuf;
mci = mci_get(hostbuf, m);
+
+#if DANE
+ tlsa_flags = 0;
+# if HSMARKS
+ if (mxsecure)
+ firstto->q_flags |= QMXSECURE;
+ else
+ firstto->q_flags &= ~QMXSECURE;
+# endif
+ if (TTD(90, 30))
+ sm_dprintf("deliver: mci_get: 1: mci=%p, host=%s, mx=%s, ste=%p, dane=%#x, mci_state=%d, QMXSECURE=%d, reqdane=%d, chk_dane_rcpt=%d, firstto=%s, to=%s\n",
+ mci, host, hostbuf, ste, Dane,
+ mci->mci_state, RCPT_MXSECURE(firstto),
+ RCPT_REQ_DANE(firstto),
+ CHK_DANE_RCPT(Dane, firstto),
+ firstto->q_user, e->e_to);
+
+ if (CHK_DANE_RCPT(Dane, firstto))
+ {
+ (void) gettlsa(hostbuf, NULL, &ste,
+ RCPT_MXSECURE(firstto) ? TLSAFLADMX : 0,
+ 0, m->m_port);
+ }
+ if (TTD(90, 30))
+ sm_dprintf("deliver: host=%s, mx=%s, ste=%p, chk_dane=%d\n",
+ host, hostbuf, ste,
+ CHK_DANE_RCPT(Dane, firstto));
+
+ /* XXX: check expiration! */
+ if (ste != NULL && TLSA_RR_TEMPFAIL(ste->s_tlsa))
+ {
+ if (tTd(11, 1))
+ sm_dprintf("skip: host=%s, TLSA_RR_lookup=%d\n"
+ , hostbuf
+ , ste->s_tlsa->dane_tlsa_dnsrc);
+
+ tlsa_flags |= TLSAFLTEMP;
+ }
+ else if (ste != NULL && TTD(90, 30))
+ {
+ if (ste->s_tlsa != NULL)
+ sm_dprintf("deliver: host=%s, mx=%s, tlsa_n=%d, tlsa_flags=%#lx, ssl=%p, chk=%#x, res=%d\n"
+ , host, hostbuf
+ , ste->s_tlsa->dane_tlsa_n
+ , ste->s_tlsa->dane_tlsa_flags
+ , mci->mci_ssl
+ , mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk
+ , mci->mci_tlsi.tlsi_dvc.dane_vrfy_res
+ );
+ else
+ sm_dprintf("deliver: host=%s, mx=%s, notlsa\n", host, hostbuf);
+ }
+
+ if (mci->mci_state != MCIS_CLOSED)
+ {
+ bool dane_old, dane_new, new_session;
+
+ /* CHK_DANE(Dane): implicit via ste != NULL */
+ dane_new = !iscltflgset(e, D_NODANE) &&
+ ste != NULL && ste->s_tlsa != NULL &&
+ TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP);
+ dane_old = CHK_DANE(mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk);
+ new_session = (dane_old != dane_new);
+ vrfy = "";
+ if (dane_old && new_session)
+ {
+ vrfy = macget(&mci->mci_macro, macid("{verify}"));
+ new_session = NULL == vrfy || strcmp("TRUSTED", vrfy) != 0;
+ }
+ if (TTD(11, 32))
+ sm_dprintf("deliver: host=%s, mx=%s, dane_old=%d, dane_new=%d, new_session=%d, vrfy=%s\n",
+ host, hostbuf, dane_old,
+ dane_new, new_session, vrfy);
+ if (new_session)
+ {
+ if (TTD(11, 34))
+ sm_dprintf("deliver: host=%s, mx=%s, old_mci=%p, state=%d\n",
+ host, hostbuf,
+ mci, mci->mci_state);
+ smtpquit(mci->mci_mailer, mci, e);
+ if (TTD(11, 34))
+ sm_dprintf("deliver: host=%s, mx=%s, new_mci=%p, state=%d\n",
+ host, hostbuf,
+ mci, mci->mci_state);
+ }
+ else
+ {
+ /* are tlsa_flags the same as dane_vrfy_chk? */
+ tlsa_flags = mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk;
+ memcpy(&dane_vrfy_ctx,
+ &mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk,
+ sizeof(dane_vrfy_ctx));
+ dane_vrfy_ctx.dane_vrfy_host = NULL;
+ dane_vrfy_ctx.dane_vrfy_sni = NULL;
+ if (TTD(90, 40))
+ sm_dprintf("deliver: host=%s, mx=%s, state=reuse, chk=%#x\n",
+ host, hostbuf, mci->mci_tlsi.tlsi_dvc.dane_vrfy_chk);
+ }
+ }
+#endif /* DANE */
if (mci->mci_state != MCIS_CLOSED)
{
char *type;
@@ -2225,22 +2741,6 @@ tryhost:
break;
}
mci->mci_mailer = m;
-#if DANE
- tlsa_flags = 0;
- if (CHK_DANE(Dane))
- (void) GETTLSA(hostbuf, &ste, m->m_port);
-
- /* XXX: check expiration! */
- if (ste != NULL && TLSA_RR_TEMPFAIL(ste->s_tlsa))
- {
- if (tTd(11, 1))
- sm_dprintf("skip: host=%s, TLSA_RR_lookup=%d\n"
- , hostbuf
- , ste->s_tlsa->dane_tlsa_dnsrc);
-
- tlsa_flags |= TLSAFLTEMP;
- }
-#endif /* DANE */
if (mci->mci_exitstat != EX_OK)
{
@@ -2267,12 +2767,52 @@ tryhost:
sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e),
hostbuf, "user open");
+
+ i = EX_OK;
+ e->e_mci = mci;
+#if STARTTLS || SASL
+ if ((i = cltfeatures(e, hostbuf)) != EX_OK)
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_WARNING, e->e_id,
+ "clt_features=TEMPFAIL, host=%s, status=skipped"
+ , hostbuf);
+ /* XXX handle error! */
+ (void) sm_strlcpy(SmtpError,
+ "clt_features=TEMPFAIL",
+ sizeof(SmtpError));
+# if DANE
+ tlsa_flags &= ~TLSAFLTEMP;
+# endif
+ }
+# if DANE
+ /* hack: disable DANE if requested */
+ if (iscltflgset(e, D_NODANE))
+ ste = NULL;
+ tlsa_flags |= ste != NULL ? Dane : DANE_NEVER;
+ dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
+ dane_vrfy_ctx.dane_vrfy_port = m->m_port;
+ if (TTD(11, 11))
+ sm_dprintf("deliver: makeconnection=before, chk=%#x, tlsa_flags=%#lx, {client_flags}=%s, stat=%d, dane_enabled=%d\n",
+ dane_vrfy_ctx.dane_vrfy_chk,
+ tlsa_flags,
+ macvalue(macid("{client_flags}"), e),
+ i, dane_vrfy_ctx.dane_vrfy_dane_enabled);
+# endif /* DANE */
+#endif /* STARTTLS || SASL */
#if NETUNIX
if (mux_path != NULL)
{
message("Connecting to %s via %s...",
mux_path, m->m_name);
- i = makeconnection_ds((char *) mux_path, mci);
+ if (EX_OK == i)
+ {
+ i = makeconnection_ds((char *) mux_path, mci);
+#if DANE
+ /* fake it: "IP is secure" */
+ tlsa_flags |= TLSAFLADIP;
+#endif
+ }
}
else
#endif /* NETUNIX */
@@ -2287,36 +2827,10 @@ tryhost:
m->m_name);
/*
- ** XXX OK to do this here already?
- ** set the current connection information
+ ** set the current connection information,
** required to set {client_flags} in e->e_mci
*/
- e->e_mci = mci;
- if ((i = cltfeatures(e, hostbuf)) != EX_OK)
- {
- if (LogLevel > 8)
- sm_syslog(LOG_WARNING, e->e_id,
- "clt_features=TEMPFAIL, host=%s, status=skipped"
- , hostbuf);
- /* XXX handle error! */
- (void) sm_strlcpy(SmtpError,
- "clt_features=TEMPFAIL",
- sizeof(SmtpError));
-#if DANE
- tlsa_flags &= ~TLSAFLTEMP;
-#endif
- }
-#if DANE
- /* hack: disable DANE if requested */
- if (iscltflgset(e, D_NODANE))
- ste = NULL;
- tlsa_flags |= ste != NULL ? Dane : DANE_NEVER;
- dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
- dane_vrfy_ctx.dane_vrfy_port = m->m_port;
- if (tTd(11, 11))
- sm_dprintf("makeconnection: before: chk=%d, tlsa_flags=%lX, {client_flags}=%s\n", dane_vrfy_ctx.dane_vrfy_chk, tlsa_flags, macvalue(macid("{client_flags}"), e));
-#endif
if (EX_OK == i)
i = makeconnection(hostbuf, port, mci,
e, enough
@@ -2324,24 +2838,30 @@ tryhost:
, &tlsa_flags
#endif
);
+ }
#if DANE
- if (tTd(11, 11))
- sm_dprintf("makeconnection: after: chk=%d, tlsa_flags=%lX\n", dane_vrfy_ctx.dane_vrfy_chk, tlsa_flags);
- if (dane_vrfy_ctx.dane_vrfy_chk != DANE_ALWAYS)
- dane_vrfy_ctx.dane_vrfy_chk = DANEMODE(tlsa_flags);
- if (EX_TEMPFAIL == i &&
- ((tlsa_flags & (TLSAFLTEMP|DANE_SECURE)) ==
- (TLSAFLTEMP|DANE_SECURE)))
- {
- (void) sm_strlcpy(SmtpError,
- " for TLSA RR",
- sizeof(SmtpError));
+ if (TTD(11, 11))
+ sm_dprintf("deliver: makeconnection=after, chk=%#x, tlsa_flags=%#lx, stat=%d\n",
+ dane_vrfy_ctx.dane_vrfy_chk,
+ tlsa_flags, i);
+#if OLD_WAY_TLSA_FLAGS
+ if (dane_vrfy_ctx.dane_vrfy_chk != DANE_ALWAYS)
+ dane_vrfy_ctx.dane_vrfy_chk = DANEMODE(tlsa_flags);
+#else
+ dane_vrfy_ctx.dane_vrfy_chk = tlsa_flags;
+#endif
+ if (EX_TEMPFAIL == i &&
+ ((tlsa_flags & (TLSAFLTEMP|DANE_SECURE)) ==
+ (TLSAFLTEMP|DANE_SECURE)))
+ {
+ (void) sm_strlcpy(SmtpError,
+ " for TLSA RR",
+ sizeof(SmtpError));
# if NAMED_BIND
- SM_SET_H_ERRNO(TRY_AGAIN);
+ SM_SET_H_ERRNO(TRY_AGAIN);
# endif
- }
-#endif
}
+#endif /* DANE */
mci->mci_errno = errno;
mci->mci_lastuse = curtime();
mci->mci_deliveries = 0;
@@ -2401,8 +2921,8 @@ tryhost:
goto one_last_try;
if (tTd(11, 1))
- sm_dprintf("openmailer: makeconnection => stat=%d, errno=%d\n",
- i, errno);
+ sm_dprintf("openmailer: makeconnection(%s) => stat=%d, errno=%d\n",
+ hostbuf, i, errno);
if (i == EX_TEMPFAIL)
goodmxfound = true;
mci_unlock_host(mci);
@@ -2462,9 +2982,7 @@ tryhost:
"\n");
}
-#if XDEBUG
checkfd012("before creating mail pipe");
-#endif
/* create a pipe to shove the mail through */
if (pipe(mpvect) < 0)
@@ -2527,10 +3045,8 @@ tryhost:
rcode = EX_OSERR;
goto give_up;
}
-#if XDEBUG
checkfdopen(rpvect[0], "rpvect[0]");
checkfdopen(rpvect[1], "rpvect[1]");
-#endif
/*
** Actually fork the mailer process.
@@ -3033,73 +3549,24 @@ tryhost:
{
#if STARTTLS || SASL
char *srvname;
- extern SOCKADDR CurHostAddr;
-#endif
-
-#if SASL
-# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
-#endif
-#if STARTTLS
-# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
-#endif
-#define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f)
-#define SET_HELO(f) f |= MCIF_ONLY_EHLO
-#define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
-
-#if STARTTLS || SASL
- /* don't use CurHostName, it is changed in many places */
- if (mci->mci_host != NULL)
- {
- srvname = mci->mci_host;
- RM_TRAIL_DOT(srvname);
- }
- else if (mci->mci_mailer != NULL)
- {
- srvname = mci->mci_mailer->m_name;
- dotpos = -1;
- }
- else
- {
- srvname = "local";
- dotpos = -1;
- }
-
- /* don't set {server_name} to NULL or "": see getauth() */
- macdefine(&mci->mci_macro, A_TEMP, macid("{server_name}"),
- srvname);
-
- /* CurHostAddr is set by makeconnection() and mci_get() */
- if (CurHostAddr.sa.sa_family != 0)
- {
- macdefine(&mci->mci_macro, A_TEMP,
- macid("{server_addr}"),
- anynet_ntoa(&CurHostAddr));
- }
- else if (mci->mci_mailer != NULL)
- {
- /* mailer name is unique, use it as address */
- macdefine(&mci->mci_macro, A_PERM,
- macid("{server_addr}"),
- mci->mci_mailer->m_name);
- }
- else
- {
- /* don't set it to NULL or "": see getauth() */
- macdefine(&mci->mci_macro, A_PERM,
- macid("{server_addr}"), "0");
- }
+ int dotpos;
+# if SASL
+# define DONE_AUTH(f) bitset(MCIF_AUTHACT, f)
+# endif
+# if STARTTLS
+# define DONE_STARTTLS(f) bitset(MCIF_TLSACT, f)
+# endif
+ srvname = setservermacros(mci, &dotpos);
# if DANE
SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
- if (ste != NULL && ste->s_tlsa != NULL &&
- ste->s_tlsa->dane_tlsa_sni != NULL)
+ if (STE_HAS_TLSA(ste) && ste->s_tlsa->dane_tlsa_sni != NULL)
dane_vrfy_ctx.dane_vrfy_sni = sm_strdup(ste->s_tlsa->dane_tlsa_sni);
dane_vrfy_ctx.dane_vrfy_host = sm_strdup(srvname);
-# endif
-
- /* undo change of srvname (mci->mci_host) */
+# endif /* DANE */
+ /* undo change of srvname (== mci->mci_host) */
FIX_TRAIL_DOT(srvname);
reconnect: /* after switching to an encrypted connection */
@@ -3107,10 +3574,16 @@ reconnect: /* after switching to an encrypted connection */
if (DONE_STARTTLS(mci->mci_flags))
{
/* use a "reset" function? */
+ /* when is it required to "reset" this data? */
SM_FREE(dane_vrfy_ctx.dane_vrfy_host);
SM_FREE(dane_vrfy_ctx.dane_vrfy_sni);
dane_vrfy_ctx.dane_vrfy_fp[0] = '\0';
- dane_vrfy_ctx.dane_vrfy_res = 0;
+ dane_vrfy_ctx.dane_vrfy_res = DANE_VRFY_NONE;
+ dane_vrfy_ctx.dane_vrfy_dane_enabled = false;
+ if (TTD(90, 40))
+ sm_dprintf("deliver: reset: chk=%#x, dane_enabled=%d\n",
+ dane_vrfy_ctx.dane_vrfy_chk,
+ dane_vrfy_ctx.dane_vrfy_dane_enabled);
}
# endif /* DANE */
@@ -3142,7 +3615,7 @@ reconnect: /* after switching to an encrypted connection */
macdefine(&e->e_macro, A_PERM, macid("{rcpt_addr}"), "");
# if DANE
- if (MTASTS && (ste != NULL && ste->s_tlsa != NULL))
+ if (MTASTS && STE_HAS_TLSA(ste))
macdefine(&e->e_macro, A_PERM, macid("{sts_sni}"), "DANE");
else
# endif
@@ -3190,6 +3663,22 @@ reconnect: /* after switching to an encrypted connection */
/* XXX reset e_smtputf8 to original state at the end? */
#endif /* USE_EAI */
+#define ONLY_HELO(f) bitset(MCIF_ONLY_EHLO, f)
+#define SET_HELO(f) f |= MCIF_ONLY_EHLO
+#define CLR_HELO(f) f &= ~MCIF_ONLY_EHLO
+
+#if _FFR_SMTPS_CLIENT && STARTTLS
+ /*
+ ** For M_SMTPS_CLIENT, we do the STARTTLS code first,
+ ** then jump back and start the SMTP conversation.
+ */
+
+ implicittls = bitnset(M_SMTPS_CLIENT, mci->mci_mailer->m_flags);
+ if (implicittls)
+ goto dotls;
+backtosmtp:
+#endif /* _FFR_SMTPS_CLIENT && STARTTLS */
+
smtpinit(m, mci, e, ONLY_HELO(mci->mci_flags));
CLR_HELO(mci->mci_flags);
@@ -3224,6 +3713,9 @@ reconnect: /* after switching to an encrypted connection */
}
#if STARTTLS
+# if _FFR_SMTPS_CLIENT
+dotls:
+# endif
/* first TLS then AUTH to provide a security layer */
if (mci->mci_state != MCIS_CLOSED &&
!DONE_STARTTLS(mci->mci_flags))
@@ -3232,24 +3724,24 @@ reconnect: /* after switching to an encrypted connection */
bool usetls;
bool saveQuickAbort = QuickAbort;
bool saveSuprErrs = SuprErrs;
- char *host = NULL;
+ char *srvname = NULL;
rcode = EX_OK;
- usetls = bitset(MCIF_TLS, mci->mci_flags);
+ usetls = bitset(MCIF_TLS, mci->mci_flags) || implicittls;
if (usetls)
usetls = !iscltflgset(e, D_NOTLS);
if (usetls)
usetls = tlsstate == 0;
- host = macvalue(macid("{server_name}"), e);
+ srvname = macvalue(macid("{server_name}"), e);
if (usetls)
{
olderrors = Errors;
QuickAbort = false;
SuprErrs = true;
- if (rscheck("try_tls", host, NULL, e,
- RSF_RMCOMM, 7, host, NOQID, NULL,
- NULL) != EX_OK
+ if (rscheck("try_tls", srvname, NULL, e,
+ RSF_RMCOMM|RSF_STATUS, 7, srvname,
+ NOQID, NULL, NULL) != EX_OK
|| Errors > olderrors)
{
usetls = false;
@@ -3260,7 +3752,7 @@ reconnect: /* after switching to an encrypted connection */
if (usetls)
{
- if ((rcode = starttls(m, mci, e
+ if ((rcode = starttls(m, mci, e, implicittls
# if DANE
, &dane_vrfy_ctx
# endif
@@ -3271,7 +3763,7 @@ reconnect: /* after switching to an encrypted connection */
# if DANE && _FFR_MTA_STS
/* if DANE is used (and STS should be used): disable STS */
/* also check MTASTS and NOSTS flag? */
- if (ste != NULL && ste->s_tlsa != NULL &&
+ if (STE_HAS_TLSA(ste) &&
!SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
macdefine(&e->e_macro, A_PERM, macid("{rcpt_addr}"), "");
# endif
@@ -3293,9 +3785,12 @@ reconnect: /* after switching to an encrypted connection */
case EX_TEMPFAIL:
s = "TEMP";
break;
+#if 0
+ /* see starttls() */
case EX_USAGE:
s = "USAGE";
break;
+#endif
case EX_PROTOCOL:
s = "PROTOCOL";
break;
@@ -3305,6 +3800,13 @@ reconnect: /* after switching to an encrypted connection */
case EX_UNAVAILABLE:
s = "NONE";
break;
+
+ /*
+ ** Possible return from ruleset
+ ** tls_clt_features via
+ ** get_tls_se_features().
+ */
+
case EX_CONFIG:
s = "CONFIG";
break;
@@ -3314,6 +3816,38 @@ reconnect: /* after switching to an encrypted connection */
s = "FAILURE";
rcode = EX_TEMPFAIL;
}
+# if DANE
+ /*
+ ** TLSA found but STARTTLS "failed"?
+ ** What is the best way to "fail"?
+ ** XXX: check expiration!
+ */
+
+ if (!iscltflgset(e, D_NODANE) &&
+ STE_HAS_TLSA(ste) &&
+ TLSA_HAS_RRs(ste->s_tlsa))
+ {
+ if (LogLevel > 8)
+ sm_syslog(LOG_NOTICE, NOQID,
+ "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but STARTTLS failed",
+ srvname);
+ /* XXX include TLSA RR from DNS? */
+
+ /*
+ ** Only override codes which
+ ** do not cause a failure
+ ** in the default rules.
+ */
+
+ if (EX_PROTOCOL != rcode &&
+ EX_SOFTWARE != rcode &&
+ EX_CONFIG != rcode)
+ {
+ /* s = "DANE_TEMP"; */
+ dane_vrfy_ctx.dane_vrfy_chk |= TLSAFLNOTLS;
+ }
+ }
+# endif /* DANE */
macdefine(&e->e_macro, A_PERM,
macid("{verify}"), s);
}
@@ -3330,17 +3864,14 @@ reconnect: /* after switching to an encrypted connection */
if (!bitset(MCIF_TLS, mci->mci_flags) &&
!iscltflgset(e, D_NODANE) &&
- ste != NULL &&
- ste->s_tlsa != NULL &&
- ste->s_tlsa->dane_tlsa_n > 0)
+ STE_HAS_TLSA(ste) &&
+ TLSA_HAS_RRs(ste->s_tlsa))
{
if (LogLevel > 8)
sm_syslog(LOG_NOTICE, NOQID,
- "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but no STARTTLS available",
- host);
+ "STARTTLS=client, relay=%.100s, warning=DANE configured in DNS but STARTTLS not offered",
+ srvname);
/* XXX include TLSA RR from DNS? */
-
- p = "DANE_FAIL";
}
# endif /* DANE */
macdefine(&e->e_macro, A_PERM,
@@ -3362,7 +3893,7 @@ reconnect: /* after switching to an encrypted connection */
if (rscheck("tls_server",
macvalue(macid("{verify}"), e),
NULL, e, RSF_RMCOMM|RSF_COUNT, 5,
- host, NOQID, NULL, NULL) != EX_OK ||
+ srvname, NOQID, NULL, NULL) != EX_OK ||
Errors > olderrors ||
rcode == EX_SOFTWARE)
{
@@ -3387,7 +3918,7 @@ reconnect: /* after switching to an encrypted connection */
if (rcode == EX_SOFTWARE)
{
/* drop the connection */
- mci->mci_state = MCIS_QUITING;
+ mci->mci_state = MCIS_ERROR;
SM_CLOSE_FP(mci->mci_out);
mci->mci_flags &= ~MCIF_TLSACT;
(void) endmailer(mci, e, pv);
@@ -3445,7 +3976,11 @@ reconnect: /* after switching to an encrypted connection */
QuickAbort = saveQuickAbort;
SuprErrs = saveSuprErrs;
if (DONE_STARTTLS(mci->mci_flags) &&
- mci->mci_state != MCIS_CLOSED)
+ mci->mci_state != MCIS_CLOSED
+# if _FFR_SMTPS_CLIENT
+ && !implicittls && !smtptls
+# endif
+ )
{
SET_HELO(mci->mci_flags);
mci_clr_extensions(mci);
@@ -3474,6 +4009,33 @@ reconnect: /* after switching to an encrypted connection */
goto one_last_try;
}
}
+
+# if _FFR_SMTPS_CLIENT
+ /*
+ ** For M_SMTPS_CLIENT, we do the STARTTLS code first,
+ ** then jump back and start the SMTP conversation.
+ */
+
+ if (implicittls && !smtptls)
+ {
+ smtptls = true;
+ if (!DONE_STARTTLS(mci->mci_flags))
+ {
+ if (rcode == EX_TEMPFAIL)
+ {
+ e->e_status = "4.3.3";
+ usrerrenh(e->e_status, "454 TLS session initiation failed");
+ }
+ else
+ {
+ e->e_status = "5.3.3";
+ usrerrenh(e->e_status, "554 TLS session initiation failed");
+ }
+ goto give_up;
+ }
+ goto backtosmtp;
+ }
+# endif /* _FFR_SMTPS_CLIENT */
#endif /* STARTTLS */
#if SASL
/* if other server supports authentication let's authenticate */
@@ -3639,6 +4201,7 @@ do_transfer:
}
else if (nummxhosts > hostnum)
{
+ logfailover(e, m, mci, rcode, NULL);
/* try next MX site */
goto tryhost;
}
@@ -3702,6 +4265,9 @@ do_transfer:
#if PIPELINING
ADDRESS *volatile pchain;
#endif
+#if STARTTLS
+ ADDRESS addr;
+#endif
/* send the recipient list */
rc = EX_OK;
@@ -3730,14 +4296,103 @@ do_transfer:
macid("{rcpt_addr}"), "");
#endif /* _FFR_MTA_STS */
#if STARTTLS
+# if DANE
+ vrfy = macvalue(macid("{verify}"), e);
+ if (NULL == vrfy)
+ vrfy = "NONE";
+ vrfy = sm_strdup(vrfy);
+ if (TTD(10, 32))
+ sm_dprintf("deliver: 0: vrfy=%s, to=%s, mx=%s, QMXSECURE=%d, secure=%d, ste=%p, dane=%#x\n",
+ vrfy, to->q_user, CurHostName, RCPT_MXSECURE(to),
+ RCPT_REQ_DANE(to), ste, Dane);
+ if (NULL == ste && CHK_DANE_RCPT(Dane, to))
+ {
+ (void) gettlsa(CurHostName, NULL, &ste,
+ RCPT_MXSECURE(to) ? TLSAFLADMX : 0,
+ 0, m->m_port);
+ }
+ if (TTD(10, 32))
+ sm_dprintf("deliver: 2: vrfy=%s, to=%s, QMXSECURE=%d, secure=%d, ste=%p, dane=%#x, SUP=%#x, !TEMP=%d, ADIP=%d, chk_dane=%d, vrfy_chk=%#x, mcif=%#lx\n",
+ vrfy, to->q_user,
+ RCPT_MXSECURE(to), RCPT_REQ_DANE(to), ste, Dane,
+ STE_HAS_TLSA(ste) ? TLSA_IS_FL(ste->s_tlsa, TLSAFLSUP) : -1,
+ (0 == (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLTEMPVRFY)),
+ (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLADIP)),
+ CHK_DANE(dane_vrfy_ctx.dane_vrfy_chk),
+ dane_vrfy_ctx.dane_vrfy_chk,
+ mci->mci_flags
+ );
+
+ if (strcmp("DANE_FAIL", vrfy) == 0)
+ {
+ if (!RCPT_REQ_DANE(to))
+ macdefine(&mci->mci_macro, A_PERM, macid("{verify}"), "FAIL");
+ else
+ SM_FREE(vrfy);
+ }
+
+ /*
+ ** Note: MCIF_TLS should be reset when
+ ** when starttls was successful because
+ ** the server should not offer it anymore.
+ */
+
+ else if (strcmp("TRUSTED", vrfy) != 0 &&
+ RCPT_REQ_DANE(to))
+ {
+ macdefine(&mci->mci_macro, A_PERM, macid("{verify}"),
+ (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS)) ?
+ "DANE_TEMP" :
+ (bitset(MCIF_TLS|MCIF_TLSACT, mci->mci_flags) ?
+ "DANE_FAIL" : "DANE_NOTLS"));
+ }
+ /* DANE: unsupported types: require TLS but not available? */
+ else if (strcmp("TRUSTED", vrfy) != 0 &&
+ RCPT_REQ_TLS(to)
+ && (!bitset(MCIF_TLS|MCIF_TLSACT, mci->mci_flags)
+ || (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS))))
+ {
+ macdefine(&mci->mci_macro, A_PERM, macid("{verify}"),
+ (0 != (dane_vrfy_ctx.dane_vrfy_chk & TLSAFLNOTLS)) ?
+ "DANE_TEMP" : "DANE_NOTLS");
+ }
+ else
+ SM_FREE(vrfy);
+ if (TTD(10, 32))
+ sm_dprintf("deliver: 7: verify=%s, secure=%d\n",
+ macvalue(macid("{verify}"), e),
+ RCPT_REQ_DANE(to));
+# endif /* DANE */
+
rc = rscheck("tls_rcpt", to->q_user, NULL, e,
RSF_RMCOMM|RSF_COUNT, 3,
- mci->mci_host, e->e_id, NULL, NULL);
+ mci->mci_host, e->e_id, &addr, NULL);
+
+# if DANE
+ if (vrfy != NULL)
+ {
+ macdefine(&mci->mci_macro, A_PERM, macid("{verify}"), vrfy);
+ SM_FREE(vrfy);
+ }
+# endif
+
+ if (TTD(10, 32))
+ sm_dprintf("deliver: 9: verify=%s, to=%s, tls_rcpt=%d\n",
+ macvalue(macid("{verify}"), e),
+ to->q_user, rc);
+
if (rc != EX_OK)
{
+ char *dsn;
+
to->q_flags |= QINTREPLY;
markfailure(e, to, mci, rc, false);
- giveresponse(rc, to->q_status, m, mci,
+ if (addr.q_host != NULL &&
+ isenhsc(addr.q_host, ' ') > 0)
+ dsn = addr.q_host;
+ else
+ dsn = NULL;
+ giveresponse(rc, dsn, m, mci,
ctladdr, xstart, e, to);
if (rc == EX_TEMPFAIL)
{
@@ -3804,6 +4459,7 @@ do_transfer:
&& (mci->mci_retryrcpt || mci->mci_okrcpts > 0)
)
{
+ logfailover(e, m, mci, rcode, to);
/* try next MX site */
goto tryhost;
}
@@ -4015,6 +4671,7 @@ do_transfer:
/* Some recipients were tempfailed, try them on the next host */
if (mci != NULL && mci->mci_retryrcpt && nummxhosts > hostnum)
{
+ logfailover(e, m, mci, rcode, to);
/* try next MX site */
goto tryhost;
}
@@ -4060,6 +4717,67 @@ cleanup: ;
}
/*
+** EX2ENHSC -- return proper enhanced status code for an EX_ code
+**
+** Parameters:
+** xcode -- EX_* code
+**
+** Returns:
+** enhanced status code if appropriate
+** NULL otherwise
+*/
+
+static char *ex2enhsc __P((int));
+
+static char *
+ex2enhsc(xcode)
+ int xcode;
+{
+ switch (xcode)
+ {
+ case EX_USAGE:
+ return "5.5.4";
+ break;
+
+ case EX_DATAERR:
+ return "5.5.2";
+ break;
+
+ case EX_NOUSER:
+ return "5.1.1";
+ break;
+
+ case EX_NOHOST:
+ return "5.1.2";
+ break;
+
+ case EX_NOINPUT:
+ case EX_CANTCREAT:
+ case EX_NOPERM:
+ return "5.3.0";
+ break;
+
+ case EX_UNAVAILABLE:
+ case EX_SOFTWARE:
+ case EX_OSFILE:
+ case EX_PROTOCOL:
+ case EX_CONFIG:
+ return "5.5.0";
+ break;
+
+ case EX_OSERR:
+ case EX_IOERR:
+ return "4.5.0";
+ break;
+
+ case EX_TEMPFAIL:
+ return "4.2.0";
+ break;
+ }
+ return NULL;
+}
+
+/*
** MARKFAILURE -- mark a failure on a specific address.
**
** Parameters:
@@ -4115,53 +4833,9 @@ markfailure(e, q, mci, rcode, ovr)
mci->mci_rstatus);
}
else if (e->e_status != NULL)
- {
status = e->e_status;
- }
else
- {
- switch (rcode)
- {
- case EX_USAGE:
- status = "5.5.4";
- break;
-
- case EX_DATAERR:
- status = "5.5.2";
- break;
-
- case EX_NOUSER:
- status = "5.1.1";
- break;
-
- case EX_NOHOST:
- status = "5.1.2";
- break;
-
- case EX_NOINPUT:
- case EX_CANTCREAT:
- case EX_NOPERM:
- status = "5.3.0";
- break;
-
- case EX_UNAVAILABLE:
- case EX_SOFTWARE:
- case EX_OSFILE:
- case EX_PROTOCOL:
- case EX_CONFIG:
- status = "5.5.0";
- break;
-
- case EX_OSERR:
- case EX_IOERR:
- status = "4.5.0";
- break;
-
- case EX_TEMPFAIL:
- status = "4.2.0";
- break;
- }
- }
+ status = ex2enhsc(rcode);
/* new status? */
if (status != NULL && *status != '\0' && (ovr || q->q_status == NULL ||
@@ -4383,8 +5057,8 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
}
if (tTd(11, 4))
- sm_dprintf("giveresponse: status=%d, e->e_message=%s, SmtpError=%s\n",
- status, e->e_message, SmtpError);
+ sm_dprintf("giveresponse: status=%d, e->e_message=%s, dsn=%s, SmtpError=%s\n",
+ status, e->e_message, dsn, SmtpError);
/*
** Compute status message from code.
@@ -4614,6 +5288,15 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
errno = 0;
SM_SET_H_ERRNO(0);
}
+
+#if _FFR_8BITENVADDR
+# define GET_HOST_VALUE \
+ (void) dequote_internal_chars(p, xbuf, sizeof(xbuf)); \
+ p = xbuf;
+#else
+# define GET_HOST_VALUE
+#endif
+
/*
** LOGDELIVERY -- log the delivery in the system log
**
@@ -4632,7 +5315,7 @@ giveresponse(status, dsn, m, mci, ctladdr, xstart, e, to)
** computing transaction delay.
** e -- the current envelope.
** to -- the current recipient (NULL if none).
-** rcode -- status code
+** rcode -- status code.
**
** Returns:
** none
@@ -4664,6 +5347,8 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
char *xstr;
#if (SYSLOG_BUFSIZE) >= 256
+ int xtype, rtype;
+
/* ctladdr: max 106 bytes */
bp = buf;
if (ctladdr != NULL)
@@ -4736,18 +5421,34 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
p = macvalue('h', e);
if (p != NULL && p[0] != '\0')
{
+ GET_HOST_VALUE;
(void) sm_snprintf(bp, SPACELEFT(buf, bp),
", relay=%s", shortenstring(p, 40));
}
}
bp += strlen(bp);
+ p = ex2enhsc(rcode);
+ if (p != NULL)
+ xtype = p[0] - '0';
+ else
+ xtype = 0;
+
+#ifndef WHERE2REPORT
+# define WHERE2REPORT "please see <https://sendmail.org/Report>, "
+#endif
+
/* dsn */
if (dsn != NULL && *dsn != '\0')
{
(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, ", dsn=",
shortenstring(dsn, ENHSCLEN));
bp += strlen(bp);
+ if (xtype > 0 && ISSMTPCODE(dsn) &&
+ (rtype = dsn[0] - '0') > 0 && rtype != xtype)
+ sm_syslog(LOG_ERR, e->e_id,
+ "ERROR: inconsistent dsn, %srcode=%d, dsn=%s",
+ WHERE2REPORT, rcode, dsn);
}
# if _FFR_LOG_NTRIES
@@ -4770,6 +5471,20 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
# define STATLEN 203
# endif
+# if _FFR_LOG_STAGE
+ /* only do this when reply= is logged? */
+ if (rcode != EX_OK && e->e_estate >= 0)
+ {
+ if (e->e_estate >= 0 && e->e_estate < SM_ARRAY_SIZE(xs_states))
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", stage=%s", xs_states[e->e_estate]);
+ else
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", stage=%d", e->e_estate);
+ bp += strlen(bp);
+ }
+# endif /* _FFR_LOG_STAGE */
+
/*
** Notes:
** per-rcpt status: to->q_rstatus
@@ -4780,43 +5495,53 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
** stat=Deferred: ...
** has sometimes the same text?
**
- ** Note: this doesn't show the stage at which the error happened.
- ** can/should we log that?
- ** XS_* in reply() basically encodes the state.
- **
** Note: in some case the normal logging might show the same server
** reply - how to avoid that?
*/
/* only show errors from server */
- if (rcode != EX_OK && to != NULL && !SM_IS_EMPTY(to->q_rstatus)
- && !bitset(QINTREPLY, to->q_flags))
- {
- (void) sm_snprintf(bp, SPACELEFT(buf, bp),
- ", reply=%s",
- shortenstring(to->q_rstatus, STATLEN));
- bp += strlen(bp);
- }
- else if (rcode != EX_OK && e->e_text != NULL)
+ if (rcode != EX_OK && (NULL == to || !bitset(QINTREPLY, to->q_flags)))
{
- (void) sm_snprintf(bp, SPACELEFT(buf, bp),
- ", reply=%d %s%s%s",
- e->e_rcode,
- e->e_renhsc,
- (e->e_renhsc[0] != '\0') ? " " : "",
- shortenstring(e->e_text, STATLEN));
- bp += strlen(bp);
- }
+ if (to != NULL && !SM_IS_EMPTY(to->q_rstatus))
+ {
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", reply=%s",
+ shortenstring(to->q_rstatus, STATLEN));
+ bp += strlen(bp);
+ if (ISSMTPCODE(to->q_rstatus) &&
+ (rtype = to->q_rstatus[0] - '0') > 0 &&
+ ((xtype > 0 && rtype != xtype) || rtype < 4))
+ sm_syslog(LOG_ERR, e->e_id,
+ "ERROR: inconsistent reply, %srcode=%d, q_rstatus=%s",
+ WHERE2REPORT, rcode, to->q_rstatus);
+ }
+ else if (e->e_text != NULL)
+ {
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", reply=%d %s%s%s",
+ e->e_rcode,
+ e->e_renhsc,
+ (e->e_renhsc[0] != '\0') ? " " : "",
+ shortenstring(e->e_text, STATLEN));
+ bp += strlen(bp);
+ rtype = REPLYTYPE(e->e_rcode);
+ if (rtype > 0 &&
+ ((xtype > 0 && rtype != xtype) || rtype < 4))
+ sm_syslog(LOG_ERR, e->e_id,
+ "ERROR: inconsistent reply, %srcode=%d, e_rcode=%d, e_text=%s",
+ WHERE2REPORT, rcode, e->e_rcode, e->e_text);
+ }
#if _FFR_NULLMX_STATUS
- /* Hack for MX 0 . : how to make this general? */
- else if (rcode != EX_OK && NULL == to && dsn != NULL &&
- strcmp(dsn, ESCNULLMXRCPT) == 0)
- {
- (void) sm_snprintf(bp, SPACELEFT(buf, bp),
- ", status=%s", ERRNULLMX);
- bp += strlen(bp);
- }
+ /* Hack for MX 0 . : how to make this general? */
+ else if (NULL == to && dsn != NULL &&
+ strcmp(dsn, ESCNULLMXRCPT) == 0)
+ {
+ (void) sm_snprintf(bp, SPACELEFT(buf, bp),
+ ", status=%s", ERRNULLMX);
+ bp += strlen(bp);
+ }
#endif
+ }
/* stat: max 210 bytes */
if ((bp - buf) > (sizeof(buf) - ((STATLEN) + 20)))
@@ -4952,7 +5677,10 @@ logdelivery(m, mci, dsn, status, ctladdr, xstart, e, to, rcode)
{
p = macvalue('h', e);
if (p != NULL && p[0] != '\0')
+ {
+ GET_HOST_VALUE;
(void) sm_snprintf(buf, sizeof(buf), "relay=%.100s", p);
+ }
}
if (buf[0] != '\0')
sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
@@ -6216,7 +6944,7 @@ getmport(m)
#endif /* DANE */
/*
-** HOSTSIGNATURE -- return the "signature" for a host.
+** HOSTSIGNATURE -- return the "signature" for a host (list).
**
** The signature describes how we are going to send this -- it
** can be just the hostname (for non-Internet hosts) or can be
@@ -6224,8 +6952,9 @@ getmport(m)
**
** Parameters:
** m -- the mailer describing this host.
-** host -- the host name.
-** ad -- DNSSEC: ad
+** host -- the host name (can be a list).
+** ad -- DNSSEC: ad flag for lookup of host.
+** pqflags -- (pointer to) q_flags (can be NULL)
**
** Returns:
** The signature for this host.
@@ -6237,10 +6966,11 @@ getmport(m)
#define MAXHOSTSIGNATURE 8192 /* max len of hostsignature */
char *
-hostsignature(m, host, ad)
+hostsignature(m, host, ad, pqflags)
register MAILER *m;
char *host;
bool ad;
+ unsigned long *pqflags;
{
register char *p;
register STAB *s;
@@ -6259,9 +6989,12 @@ hostsignature(m, host, ad)
char *mxhosts[MAXMXHOSTS + 1];
unsigned short mxprefs[MAXMXHOSTS + 1];
#endif /* NAMED_BIND */
+ int admx;
if (tTd(17, 3))
- sm_dprintf("hostsignature(%s), ad=%d\n", host, ad);
+ sm_dprintf("hostsignature: host=%s, ad=%d\n", host, ad);
+ if (pqflags != NULL && !ad)
+ *pqflags &= ~QMXSECURE;
/*
** If local delivery (and not remote), just return a constant.
@@ -6306,7 +7039,7 @@ hostsignature(m, host, ad)
if (s->s_hostsig.hs_exp >= now)
{
if (tTd(17, 3))
- sm_dprintf("hostsignature(): stab(%s) found %s\n", host,
+ sm_dprintf("hostsignature: stab(%s) found %s\n", host,
s->s_hostsig.hs_sig);
return s->s_hostsig.hs_sig;
}
@@ -6358,9 +7091,11 @@ hostsignature(m, host, ad)
auto int rcode;
int ttl;
+ admx = 0;
nmx = getmxrr(hp, mxhosts, mxprefs,
- DROPLOCALHOST|TRYFALLBACK|(ad ? ISAD :0),
- &rcode, &ttl, GETMPORT(m));
+ DROPLOCALHOST|(ad ? ISAD :0)|
+ ((NULL == endp) ? TRYFALLBACK : 0),
+ &rcode, &ttl, GETMPORT(m), &admx);
if (nmx <= 0)
{
int save_errno;
@@ -6385,9 +7120,17 @@ hostsignature(m, host, ad)
nmx = 1;
mxhosts[0] = hp;
}
+
+ /*
+ ** NOTE: this sets QMXSECURE if the ad flags is set
+ ** for at least one host in the host list. XXX
+ */
+
+ if (pqflags != NULL && admx)
+ *pqflags |= QMXSECURE;
if (tTd(17, 3))
- sm_dprintf("hostsignature(): getmxrr() returned %d, mxhosts[0]=%s\n",
- nmx, mxhosts[0]);
+ sm_dprintf("hostsignature: host=%s, getmxrr=%d, mxhosts[0]=%s, admx=%d\n",
+ hp, nmx, mxhosts[0], admx);
/*
** Set new TTL: we use only one!
@@ -6402,6 +7145,10 @@ hostsignature(m, host, ad)
len += strlen(mxhosts[i]) + 1;
if (s->s_hostsig.hs_sig != NULL)
len += strlen(s->s_hostsig.hs_sig) + 1;
+# if DANE && HSMARKS
+ if (admx && DANE_SEC(Dane))
+ len += nmx;
+# endif
if (len < 0 || len >= MAXHOSTSIGNATURE)
{
sm_syslog(LOG_WARNING, NOQID, "hostsignature for host '%s' exceeds maxlen (%d): %d",
@@ -6424,7 +7171,13 @@ hostsignature(m, host, ad)
for (i = 0; i < nmx; i++)
{
hl = strlen(mxhosts[i]);
- if (len - 1 < hl || len <= 1)
+ if (len <= 1 ||
+# if DANE && HSMARKS
+ len - 1 < (hl + ((admx && DANE_SEC(Dane)) ? 1 : 0))
+# else
+ len - 1 < hl
+# endif
+ )
{
/* force to drop out of outer loop */
len = -1;
@@ -6438,6 +7191,13 @@ hostsignature(m, host, ad)
*p++ = ':';
len--;
}
+# if DANE && HSMARKS
+ if (admx && DANE_SEC(Dane))
+ {
+ *p++ = HSM_AD;
+ len--;
+ }
+# endif
(void) sm_strlcpy(p, mxhosts[i], len);
p += hl;
len -= hl;
@@ -6468,9 +7228,10 @@ hostsignature(m, host, ad)
s->s_hostsig.hs_sig = sm_pstrdup_x(host);
#endif /* NAMED_BIND */
if (tTd(17, 1))
- sm_dprintf("hostsignature(%s) = %s\n", host, s->s_hostsig.hs_sig);
+ sm_dprintf("hostsignature: host=%s, result=%s\n", host, s->s_hostsig.hs_sig);
return s->s_hostsig.hs_sig;
}
+
/*
** PARSE_HOSTSIGNATURE -- parse the "signature" and return MX host array.
**
@@ -6487,15 +7248,27 @@ hostsignature(m, host, ad)
** Returns:
** The number of hosts inserted into mxhosts array.
**
+** NOTES:
+** mxhosts must have at least MAXMXHOSTS entries
+** mxhosts[] will point to elements in sig --
+** hence any changes to mxhosts[] will modify sig!
+**
** Side Effects:
** Randomizes equal MX preference hosts in mxhosts.
*/
static int
-parse_hostsignature(sig, mxhosts, mailer)
+parse_hostsignature(sig, mxhosts, mailer
+#if DANE
+ , mxads
+#endif
+ )
char *sig;
char **mxhosts;
MAILER *mailer;
+#if DANE
+ BITMAP256 mxads;
+#endif
{
unsigned short curpref = 0;
int nmx = 0, i, j; /* NOTE: i, j, and nmx must have same type */
@@ -6503,28 +7276,22 @@ parse_hostsignature(sig, mxhosts, mailer)
unsigned short prefer[MAXMXHOSTS];
long rndm[MAXMXHOSTS];
+#if DANE
+ clrbitmap(mxads);
+#endif
for (hp = sig; hp != NULL; hp = endp)
{
char sep = ':';
-#if NETINET6
- if (*hp == '[')
+ FIX_MXHOSTS(hp, endp, sep);
+#if HSMARKS
+ if (HSM_AD == *hp)
{
- endp = strchr(hp + 1, ']');
- if (endp != NULL)
- endp = strpbrk(endp + 1, ":,");
+ MXADS_SET(mxads, nmx);
+ mxhosts[nmx] = hp + 1;
}
else
- endp = strpbrk(hp, ":,");
-#else /* NETINET6 */
- endp = strpbrk(hp, ":,");
-#endif /* NETINET6 */
- if (endp != NULL)
- {
- sep = *endp;
- *endp = '\0';
- }
-
+#endif
mxhosts[nmx] = hp;
prefer[nmx] = curpref;
if (mci_match(hp, mailer))
@@ -6588,6 +7355,9 @@ parse_hostsignature(sig, mxhosts, mailer)
#if STARTTLS
static SSL_CTX *clt_ctx = NULL;
static bool tls_ok_clt = true;
+# if DANE
+static bool ctx_dane_enabled = false;
+# endif
/*
** SETCLTTLS -- client side TLS: allow/disallow.
@@ -6609,17 +7379,19 @@ setclttls(tls_ok)
tls_ok_clt = tls_ok;
return;
}
+
/*
** INITCLTTLS -- initialize client side TLS
**
** Parameters:
-** tls_ok -- should tls initialization be done?
+** tls_ok -- should TLS initialization be done?
**
** Returns:
** succeeded?
**
** Side Effects:
-** sets tls_ok_clt (static variable in this module)
+** sets tls_ok_clt, ctx_dane_enabled (static variables
+** in this module)
*/
bool
@@ -6644,6 +7416,49 @@ initclttls(tls_ok)
# endif
CACertFile,
DHParams);
+# if _FFR_TESTS
+ if (tls_ok_clt && tTd(90, 104))
+ {
+ sm_dprintf("test=simulate initclttls error\n");
+ tls_ok_clt = false;
+ }
+# endif /* _FFR_TESTS */
+# if DANE
+ if (tls_ok_clt && CHK_DANE(Dane))
+ {
+# if HAVE_SSL_CTX_dane_enable
+ int r;
+
+ r = SSL_CTX_dane_enable(clt_ctx);
+# if _FFR_TESTS
+ if (tTd(90, 103))
+ {
+ sm_dprintf("test=simulate SSL_CTX_dane_enable error\n");
+# if defined(SSL_F_DANE_CTX_ENABLE)
+ SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE);
+# endif
+ r = -1;
+ }
+# endif /* _FFR_TESTS */
+ ctx_dane_enabled = (r > 0);
+ if (r <= 0)
+ {
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "SSL_CTX_dane_enable=%d", r);
+ tlslogerr(LOG_ERR, 7, "init_client");
+ }
+ else if (LogLevel > 13)
+ sm_syslog(LOG_DEBUG, NOQID,
+ "SSL_CTX_dane_enable=%d", r);
+# else
+ ctx_dane_enabled = false;
+# endif /* HAVE_SSL_CTX_dane_enable */
+ }
+ if (tTd(90, 90))
+ sm_dprintf("func=initclttls, ctx_dane_enabled=%d\n", ctx_dane_enabled);
+# endif /* DANE */
+
return tls_ok_clt;
}
@@ -6654,6 +7469,7 @@ initclttls(tls_ok)
** m -- the mailer.
** mci -- the mailer connection info.
** e -- the envelope.
+** implicit -- implicit TLS (SMTP over TLS, no STARTTLS command)
**
** Returns:
** success?
@@ -6662,7 +7478,7 @@ initclttls(tls_ok)
*/
static int
-starttls(m, mci, e
+starttls(m, mci, e, implicit
# if DANE
, dane_vrfy_ctx
# endif
@@ -6670,6 +7486,7 @@ starttls(m, mci, e
MAILER *m;
MCI *mci;
ENVELOPE *e;
+ bool implicit;
# if DANE
dane_vrfy_ctx_P dane_vrfy_ctx;
# endif
@@ -6682,6 +7499,11 @@ starttls(m, mci, e
time_t tlsstart;
extern int TLSsslidx;
+# if DANE
+ if (TTD(90, 60))
+ sm_dprintf("starttls=client: Dane=%d, dane_vrfy_chk=%#x\n",
+ Dane,dane_vrfy_ctx->dane_vrfy_chk);
+# endif
if (clt_ctx == NULL && !initclttls(true))
return EX_TEMPFAIL;
@@ -6702,7 +7524,7 @@ starttls(m, mci, e
"STARTTLS=client, error: SSL_new failed");
tlslogerr(LOG_WARNING, 9, "client");
}
- return EX_SOFTWARE;
+ return EX_TEMPFAIL;
}
ret = get_tls_se_features(e, clt_ssl, &mci->mci_tlsi, false);
@@ -6710,43 +7532,56 @@ starttls(m, mci, e
{
sm_syslog(LOG_ERR, NOQID,
"STARTTLS=client, get_tls_se_features=failed, ret=%d",
- ret);
+ ret);
goto fail;
}
- smtpmessage("STARTTLS", m, mci);
+ if (!implicit)
+ {
+ smtpmessage("STARTTLS", m, mci);
- /* get the reply */
- smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL,
- XS_STARTTLS);
+ /* get the reply */
+ smtpresult = reply(m, mci, e, TimeOuts.to_starttls, NULL, NULL,
+ XS_STARTTLS, NULL);
- /* check return code from server */
- if (REPLYTYPE(smtpresult) == 4)
- {
- ret = EX_TEMPFAIL;
- goto fail;
- }
- if (smtpresult == 501)
- {
- ret = EX_USAGE;
- goto fail;
- }
- if (smtpresult == -1)
- {
- ret = smtpresult;
- goto fail;
- }
+ /* check return code from server */
+ if (REPLYTYPE(smtpresult) == 4)
+ {
+ ret = EX_TEMPFAIL;
+ goto fail;
+ }
+#if 0
+ /*
+ ** RFC 3207 says
+ ** 501 Syntax error (no parameters allowed)
+ ** since sendmail does not use arguments, that's basically
+ ** a "cannot happen", hence treat it as any other 5xy,
+ ** which means it is also properly handled by the rules.
+ */
- /* not an expected reply but we have to deal with it */
- if (REPLYTYPE(smtpresult) == 5)
- {
- ret = EX_UNAVAILABLE;
- goto fail;
- }
- if (smtpresult != 220)
- {
- ret = EX_PROTOCOL;
- goto fail;
+ if (smtpresult == 501)
+ {
+ ret = EX_USAGE;
+ goto fail;
+ }
+#endif /* 0 */
+ if (smtpresult == -1)
+ {
+ ret = smtpresult;
+ goto fail;
+ }
+
+ /* not an expected reply but we have to deal with it */
+ if (REPLYTYPE(smtpresult) == 5)
+ {
+ ret = EX_UNAVAILABLE;
+ goto fail;
+ }
+ if (smtpresult != 220)
+ {
+ ret = EX_PROTOCOL;
+ goto fail;
+ }
}
if (LogLevel > 13)
@@ -6768,11 +7603,22 @@ starttls(m, mci, e
# if DANE
if (SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE))
dane_vrfy_ctx->dane_vrfy_chk = DANE_NEVER;
- else
+ if (TTD(90, 60))
+ sm_dprintf("starttls=client: 2: dane_vrfy_chk=%#x CHK_DANE=%d\n",
+ dane_vrfy_ctx->dane_vrfy_chk,
+ CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk));
+ if (CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk))
{
int r;
/* set SNI only if there is a TLSA RR */
+ if (tTd(90, 40))
+ sm_dprintf("dane_get_tlsa=%p, dane_vrfy_host=%s, dane_vrfy_sni=%s, ctx_dane_enabled=%d, dane_enabled=%d\n",
+ dane_get_tlsa(dane_vrfy_ctx),
+ dane_vrfy_ctx->dane_vrfy_host,
+ dane_vrfy_ctx->dane_vrfy_sni,
+ ctx_dane_enabled,
+ dane_vrfy_ctx->dane_vrfy_dane_enabled);
if (dane_get_tlsa(dane_vrfy_ctx) != NULL &&
!(SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_host) &&
SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)))
@@ -6780,6 +7626,23 @@ starttls(m, mci, e
# if _FFR_MTA_STS
SM_FREE(STS_SNI);
# endif
+ dane_vrfy_ctx->dane_vrfy_dane_enabled = ctx_dane_enabled;
+ if ((r = ssl_dane_enable(dane_vrfy_ctx, clt_ssl)) < 0)
+ {
+ dane_vrfy_ctx->dane_vrfy_dane_enabled = false;
+ if (LogLevel > 5)
+ {
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, host=%s, ssl_dane_enable=%d",
+ dane_vrfy_ctx->dane_vrfy_host, r);
+ }
+ }
+ if (SM_NOTDONE == r)
+ dane_vrfy_ctx->dane_vrfy_dane_enabled = false;
+ if (tTd(90, 40))
+ sm_dprintf("ssl_dane_enable=%d, chk=%#x, dane_enabled=%d\n",
+ r, dane_vrfy_ctx->dane_vrfy_chk,
+ dane_vrfy_ctx->dane_vrfy_dane_enabled);
if ((r = SSL_set_tlsext_host_name(clt_ssl,
(!SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)
? dane_vrfy_ctx->dane_vrfy_sni
@@ -6932,3 +7795,51 @@ iscltflgset(e, flag)
return false;
}
#endif /* STARTTLS || SASL */
+
+#if _FFR_TESTS
+void
+t_parsehostsig(hs, mailer)
+ char *hs;
+ MAILER *mailer;
+{
+ int nummxhosts, i;
+ char *mxhosts[MAXMXHOSTS + 1];
+#if DANE
+ BITMAP256 mxads;
+#endif
+
+ if (NULL == mailer)
+ mailer = LocalMailer;
+ nummxhosts = parse_hostsignature(hs, mxhosts, mailer
+#if DANE
+ , mxads
+#endif
+ );
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "nummxhosts=%d\n", nummxhosts);
+ for (i = 0; i < nummxhosts; i++)
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "mx[%d]=%s, ad=%d\n", i, mxhosts[i], MXADS_ISSET(mxads, 0));
+}
+
+void
+t_hostsig(a, hs, mailer)
+ ADDRESS *a;
+ char *hs;
+ MAILER *mailer;
+{
+ char *q;
+
+ if (NULL != a)
+ q = hostsignature(a->q_mailer, a->q_host, true, &a->q_flags);
+ else if (NULL != hs)
+ {
+ SM_REQUIRE(NULL != mailer);
+ q = hostsignature(mailer, hs, true, NULL);
+ }
+ else
+ SM_REQUIRE(NULL != hs);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "hostsig %s\n", q);
+ t_parsehostsig(q, (NULL != a) ? a->q_mailer : mailer);
+}
+#endif /* _FFR_TESTS */
diff --git a/contrib/sendmail/src/domain.c b/contrib/sendmail/src/domain.c
index 027038e283db..501af2ad4238 100644
--- a/contrib/sendmail/src/domain.c
+++ b/contrib/sendmail/src/domain.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2004, 2006, 2010, 2020-2023 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -13,9 +13,6 @@
#include <sendmail.h>
#include "map.h"
-#if USE_EAI
-#include <unicode/uidna.h>
-#endif
#if NAMED_BIND
SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
@@ -27,7 +24,7 @@ SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name s
#if NAMED_BIND
# include <arpa/inet.h>
-# include <sm_resolve.h>
+# include "sm_resolve.h"
# if DANE
# include <tls.h>
# ifndef SM_NEG_TTL
@@ -35,6 +32,10 @@ SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name s
# endif
# endif
+#if USE_EAI
+#include <unicode/uidna.h>
+#endif
+
# ifndef MXHOSTBUFSIZE
# define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
@@ -53,10 +54,6 @@ static char MXHostBuf[MXHOSTBUFSIZE];
# define RES_DNSRCH_VARIABLE _res.dnsrch
# endif
-# ifndef NO_DATA
-# define NO_DATA NO_ADDRESS
-# endif
-
# ifndef HFIXEDSZ
# define HFIXEDSZ 12 /* sizeof(HEADER) */
# endif
@@ -74,6 +71,230 @@ static int fallbackmxrr __P((int, unsigned short *, char **));
# if DANE
+static void tlsa_rr_print __P((const unsigned char *, unsigned int));
+
+static void
+tlsa_rr_print(rr, len)
+ const unsigned char *rr;
+ unsigned int len;
+{
+ unsigned int i, l;
+
+ if (!tTd(8, 2))
+ return;
+
+ sm_dprintf("len=%u, %02x-%02x-%02x",
+ len, (int)rr[0], (int)rr[1], (int)rr[2]);
+ l = tTd(8, 8) ? len : 4;
+ for (i = 3; i < l; i++)
+ sm_dprintf(":%02X", (int)rr[i]);
+ sm_dprintf("\n");
+}
+
+/*
+** TLSA_RR_CMP -- Compare two TLSA RRs
+**
+** Parameters:
+** rr1 -- TLSA RR (entry to be added)
+** l1 -- length of rr1
+** rr2 -- TLSA RR
+** l2 -- length of rr2
+**
+** Returns:
+** 0: rr1 == rr2
+** 1: rr1 is unsupported
+*/
+
+static int tlsa_rr_cmp __P((unsigned char *, int, unsigned char *, int));
+
+static int
+tlsa_rr_cmp(rr1, l1, rr2, l2)
+ unsigned char *rr1;
+ int l1;
+ unsigned char *rr2;
+ int l2;
+{
+/* temporary #if while investigating the implications of the alternative */
+#if FULL_COMPARE
+ unsigned char r1, r2;
+ int cmp;
+#endif /* FULL_COMPARE */
+
+ SM_REQUIRE(NULL != rr1);
+ SM_REQUIRE(NULL != rr2);
+ SM_REQUIRE(l1 > 3);
+ SM_REQUIRE(l2 > 3);
+
+#if FULL_COMPARE
+ /*
+ ** certificate usage
+ ** 3: cert/fp must match
+ ** 2: cert/fp must be trust anchor
+ */
+
+ /* preference[]: lower value: higher preference */
+ r1 = rr1[0];
+ r2 = rr2[0];
+ if (r1 != r2)
+ {
+ int preference[] = { 3, 2, 1, 0 };
+
+ SM_ASSERT(r1 <= SM_ARRAY_SIZE(preference));
+ SM_ASSERT(r2 <= SM_ARRAY_SIZE(preference));
+ return preference[r1] - preference[r2];
+ }
+
+ /*
+ ** selector:
+ ** 0: full cert
+ ** 1: fp
+ */
+
+ r1 = rr1[1];
+ r2 = rr2[1];
+ if (r1 != r2)
+ {
+ int preference[] = { 1, 0 };
+
+ SM_ASSERT(r1 <= SM_ARRAY_SIZE(preference));
+ SM_ASSERT(r2 <= SM_ARRAY_SIZE(preference));
+ return preference[r1] - preference[r2];
+ }
+
+ /*
+ ** matching type:
+ ** 0 -- Exact match
+ ** 1 -- SHA-256 hash
+ ** 2 -- SHA-512 hash
+ */
+
+ r1 = rr1[2];
+ r2 = rr2[2];
+ if (r1 != r2)
+ {
+ int preference[] = { 2, 0, 1 };
+
+ SM_ASSERT(r1 <= SM_ARRAY_SIZE(preference));
+ SM_ASSERT(r2 <= SM_ARRAY_SIZE(preference));
+ return preference[r1] - preference[r2];
+ }
+
+ /* not the same length despite the same type? */
+ if (l1 != l2)
+ return 1;
+ cmp = memcmp(rr1, rr2, l1);
+ if (0 == cmp)
+ return 0;
+ return 1;
+#else /* FULL_COMPARE */
+ /* identical? */
+ if (l1 == l2 && 0 == memcmp(rr1, rr2, l1))
+ return 0;
+
+ /* new entry is unsupported? -> append */
+ if (TLSA_UNSUPP == dane_tlsa_chk(rr1, l1, "", false))
+ return 1;
+ /* current entry is unsupported? -> insert new one */
+ if (TLSA_UNSUPP == dane_tlsa_chk(rr2, l2, "", false))
+ return -1;
+
+ /* default: preserve order */
+ return 1;
+#endif /* FULL_COMPARE */
+}
+
+/*
+** TLSAINSERT -- Insert a TLSA RR
+**
+** Parameters:
+** dane_tlsa -- dane_tlsa entry
+** rr -- TLSA RR
+** pn -- (point to) number of entries
+**
+** Returns:
+** SM_SUCCESS: rr inserted
+** SM_NOTDONE: rr not inserted: exists
+** SM_FULL: rr not inserted: no space left
+*/
+
+static int tlsainsert __P((dane_tlsa_P, RESOURCE_RECORD_T *, int *));
+
+static int
+tlsainsert(dane_tlsa, rr, pn)
+ dane_tlsa_P dane_tlsa;
+ RESOURCE_RECORD_T *rr;
+ int *pn;
+{
+ int i, l1, ret;
+ unsigned char *r1;
+
+ SM_ASSERT(pn != NULL);
+ SM_ASSERT(*pn <= MAX_TLSA_RR);
+ r1 = rr->rr_u.rr_data;
+ l1 = rr->rr_size;
+
+ ret = SM_SUCCESS;
+ for (i = 0; i < *pn; i++)
+ {
+ int r, j;
+
+ r = tlsa_rr_cmp(r1, l1, dane_tlsa->dane_tlsa_rr[i],
+ dane_tlsa->dane_tlsa_len[i]);
+
+ if (0 == r)
+ {
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, i=%d, n=%d, status=exists\n", i, *pn);
+ ret = SM_NOTDONE;
+ goto done;
+ }
+ if (r > 0)
+ continue;
+
+ if (*pn + 1 >= MAX_TLSA_RR)
+ {
+ j = MAX_TLSA_RR - 1;
+ SM_FREE(dane_tlsa->dane_tlsa_rr[j]);
+ dane_tlsa->dane_tlsa_len[j] = 0;
+ }
+ else
+ (*pn)++;
+
+ for (j = MAX_TLSA_RR - 2; j >= i; j--)
+ {
+ dane_tlsa->dane_tlsa_rr[j + 1] = dane_tlsa->dane_tlsa_rr[j];
+ dane_tlsa->dane_tlsa_len[j + 1] = dane_tlsa->dane_tlsa_len[j];
+ }
+ SM_ASSERT(i < MAX_TLSA_RR);
+ dane_tlsa->dane_tlsa_rr[i] = r1;
+ dane_tlsa->dane_tlsa_len[i] = l1;
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, i=%d, n=%d, status=inserted\n", i, *pn);
+ goto added;
+ }
+
+ if (*pn + 1 <= MAX_TLSA_RR)
+ {
+ dane_tlsa->dane_tlsa_rr[*pn] = r1;
+ dane_tlsa->dane_tlsa_len[*pn] = l1;
+ (*pn)++;
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, n=%d, status=appended\n", *pn);
+ }
+ else
+ {
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, n=%d, status=full\n", *pn);
+ return SM_FULL;
+ }
+
+ added:
+ /* hack: instead of copying the data, just "take it over" */
+ rr->rr_u.rr_data = NULL;
+ done:
+ return ret;
+}
+
/*
** TLSAADD -- add TLSA records to dane_tlsa entry
**
@@ -82,24 +303,27 @@ static int fallbackmxrr __P((int, unsigned short *, char **));
** dr -- DNS reply
** dane_tlsa -- dane_tlsa entry
** dnsrc -- DNS lookup return code (h_errno)
-** n -- current number of TLSA records in dane_tlsa entry
+** nr -- current number of TLSA records in dane_tlsa entry
** pttl -- (pointer to) TTL (in/out)
** level -- recursion level (CNAMEs)
**
** Returns:
** new number of TLSA records
+**
+** NOTE: the array for TLSA RRs could be "full" which is not
+** handled well (yet).
*/
static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
unsigned int *, int));
static int
-tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
+tlsaadd(name, dr, dane_tlsa, dnsrc, nr, pttl, level)
const char *name;
DNS_REPLY_T *dr;
dane_tlsa_P dane_tlsa;
int dnsrc;
- int n;
+ int nr;
unsigned int *pttl;
int level;
{
@@ -110,7 +334,7 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
if (dnsrc != 0)
{
if (tTd(8, 2))
- sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
+ sm_dprintf("tlsaadd, name=%s, prev=%d, dnsrc=%d\n",
name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
/* check previous error and keep the "most important" one? */
@@ -122,61 +346,79 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
# endif
/* "else" in #if code above */
*pttl = SM_NEG_TTL;
- return n;
+ return nr;
}
if (dr == NULL)
- return n;
+ return nr;
if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE) /* not secure? */
- return n;
+ return nr;
ttl = *pttl;
/* first: try to find TLSA records */
- nprev = n;
- for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
- rr = rr->rr_next)
+ nprev = nr;
+ for (rr = dr->dns_r_head; rr != NULL; rr = rr->rr_next)
{
- int tlsa_chk;
+ int tlsa_chk, r;
if (rr->rr_type != T_TLSA)
{
if (rr->rr_type != T_CNAME && tTd(8, 8))
- sm_dprintf("tlsaadd(%s), type=%s\n", name,
+ sm_dprintf("tlsaadd: name=%s, type=%s\n", name,
dns_type_to_string(rr->rr_type));
continue;
}
tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
true);
+ if (TLSA_UNSUPP == tlsa_chk)
+ TLSA_SET_FL(dane_tlsa, TLSAFLUNS);
if (!TLSA_IS_VALID(tlsa_chk))
continue;
+ if (TLSA_IS_SUPPORTED(tlsa_chk))
+ TLSA_SET_FL(dane_tlsa, TLSAFLSUP);
/*
- ** To do: the RRs should be sorted (by "complexity") --
- ** when more than one type is supported.
+ ** Note: rr_u.rr_data might be NULL after tlsainsert()
+ ** for nice debug output: print the data into a string
+ ** and then use it after tlsainsert().
*/
- dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
- dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
if (tTd(8, 2))
{
- unsigned char *p;
-
- p = rr->rr_u.rr_data;
- sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
- n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+ sm_dprintf("tlsaadd: name=%s, nr=%d, ", name, nr);
+ tlsa_rr_print(rr->rr_u.rr_data, rr->rr_size);
}
+ r = tlsainsert(dane_tlsa, rr, &nr);
+ if (SM_FULL == r)
+ TLSA_SET_FL(dane_tlsa, TLSAFL2MANY);
+ if (tTd(8, 2))
+ sm_dprintf("tlsainsert=%d, nr=%d\n", r, nr);
/* require some minimum TTL? */
if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
ttl = rr->rr_ttl;
+ }
- /* hack: instead of copying the data, just "take it over" */
- rr->rr_u.rr_data = NULL;
- ++n;
+ if (tTd(8, 2))
+ {
+ unsigned int ui;
+
+ SM_ASSERT(nr <= MAX_TLSA_RR);
+ for (ui = 0; ui < (unsigned int)nr; ui++)
+ {
+ sm_dprintf("tlsaadd: name=%s, ui=%u, ", name, ui);
+ tlsa_rr_print(dane_tlsa->dane_tlsa_rr[ui],
+ dane_tlsa->dane_tlsa_len[ui]);
+ }
+ }
+
+ if (TLSA_IS_FL(dane_tlsa, TLSAFL2MANY))
+ {
+ if (tTd(8, 20))
+ sm_dprintf("tlsaadd: name=%s, rr=%p, nr=%d, toomany=%d\n", name, rr, nr, TLSA_IS_FL(dane_tlsa, TLSAFL2MANY));
}
/* second: check for CNAME records, but only if no TLSA RR was added */
- for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
- rr = rr->rr_next)
+ for (rr = dr->dns_r_head; rr != NULL && nprev == nr; rr = rr->rr_next)
{
DNS_REPLY_T *drc;
int err, herr;
@@ -186,30 +428,35 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
if (level > 1)
{
if (tTd(8, 2))
- sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
+ sm_dprintf("tlsaadd: name=%s, CNAME=%s, level=%d\n",
name, rr->rr_u.rr_txt, level);
continue;
}
drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
- (Dane == DANE_SECURE &&
- !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
- ? SM_RES_DNSSEC : 0,
+ Dane == DANE_SECURE ? SM_RES_DNSSEC : 0,
RR_RAW, &err, &herr);
if (tTd(8, 2))
- sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
+ sm_dprintf("tlsaadd: name=%s, CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
name, rr->rr_u.rr_txt, level,
(void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
err, herr);
- nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
+ nprev = nr = tlsaadd(name, drc, dane_tlsa, herr, nr, pttl,
level + 1);
dns_free_data(drc);
drc = NULL;
}
+ if (TLSA_IS_FL(dane_tlsa, TLSAFLUNS) &&
+ !TLSA_IS_FL(dane_tlsa, TLSAFLSUP) && LogLevel > 9)
+ {
+ sm_syslog(LOG_NOTICE, NOQID,
+ "TLSA=%s, records=%d%s",
+ name, nr, ONLYUNSUPTLSARR);
+ }
*pttl = ttl;
- return n;
+ return nr;
}
/*
@@ -221,7 +468,7 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
** pste -- (pointer to) stab entry (output)
** flags -- TLSAFL*
** mxttl -- TTL of MX (or host)
-** port -- port
+** port -- port number used in TLSA queries (_PORT._tcp.)
**
** Returns:
** The number of TLSA records found.
@@ -248,7 +495,7 @@ gettlsa(host, name, pste, flags, mxttl, port)
time_t now;
unsigned int ttl;
int n_rrs, len, err, herr;
- bool isrname;
+ bool isrname, expired;
char nbuf[MAXDNAME];
char key[MAXDNAME];
@@ -258,9 +505,26 @@ gettlsa(host, name, pste, flags, mxttl, port)
if ('\0' == *host)
return 0;
+ expired = false;
isrname = NULL == name;
if (isrname)
name = host;
+
+ /*
+ ** If host->MX lookup was not secure then do not look up TLSA RRs.
+ ** Note: this is currently a hack: TLSAFLADMX is used as input flag,
+ ** it is (SHOULD!) NOT stored in dane_tlsa->dane_tlsa_flags
+ */
+
+ if (DANE_SECURE == Dane && 0 == (TLSAFLADMX & flags) &&
+ 0 != (TLSAFLNEW & flags))
+ {
+ if (tTd(8, 2))
+ sm_dprintf("gettlsa: host=%s, flags=%#lx, no ad but Dane=Secure\n",
+ host, flags);
+ return 0;
+ }
+
now = 0;
n_rrs = 0;
dr = NULL;
@@ -273,35 +537,37 @@ gettlsa(host, name, pste, flags, mxttl, port)
}
else
len = -1;
- if (0 == port || tTd(66, 10))
+ if (0 == port || tTd(66, 101))
port = 25;
- (void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
+ (void) sm_snprintf(key, sizeof(key), "_%u.%s", port, name);
ste = stab(key, ST_TLSA_RR, ST_FIND);
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
+ sm_dprintf("gettlsa: host=%s, %s, ste=%p, pste=%p, flags=%#lx, port=%d\n",
host, isrname ? "" : name, (void *)ste, (void *)pste,
flags, port);
if (ste != NULL)
- {
dane_tlsa = ste->s_tlsa;
- if ((TLSAFLADMX & flags) != 0)
- TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
- }
-
- /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
- if (pste != NULL
- && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
- && DANE_SECURE == Dane)
- goto end;
+#if 0
+// /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
+// if (pste != NULL
+// && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
+// && DANE_SECURE == Dane)
+// goto end;
+#endif
if (ste != NULL)
{
SM_ASSERT(dane_tlsa != NULL);
now = curtime();
+ if (tTd(8, 20))
+ sm_dprintf("gettlsa: host=%s, found-ste=%p, ste_flags=%#lx, expired=%d\n", host, ste, ste->s_tlsa->dane_tlsa_flags, dane_tlsa->dane_tlsa_exp <= now);
if (dane_tlsa->dane_tlsa_exp <= now
&& 0 == (TLSAFLNOEXP & flags))
+ {
dane_tlsa_clr(dane_tlsa);
+ expired = true;
+ }
else
{
n_rrs = dane_tlsa->dane_tlsa_n;
@@ -309,6 +575,10 @@ gettlsa(host, name, pste, flags, mxttl, port)
}
}
+ /* get entries if none exist yet? */
+ if ((0 == (TLSAFLNEW & flags)) && !expired)
+ goto end;
+
if (dane_tlsa == NULL)
{
dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
@@ -330,11 +600,38 @@ gettlsa(host, name, pste, flags, mxttl, port)
(void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
- TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
+ (TLSAFLADMX & flags) ? SM_RES_DNSSEC : 0,
RR_RAW, &err, &herr);
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
- (void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
+ {
+#if 0
+/* disabled -- what to do with these two counters? log them "somewhere"? */
+// if (NULL != dr && tTd(8, 12))
+// {
+// RESOURCE_RECORD_T *rr;
+// unsigned int ntlsarrs, usable;
+//
+// ntlsarrs = usable = 0;
+// for (rr = dr->dns_r_head; rr != NULL; rr = rr->rr_next)
+// {
+// int tlsa_chk;
+//
+// if (rr->rr_type != T_TLSA)
+// continue;
+// ++ntlsarrs;
+// tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data,
+// rr->rr_size, name, false);
+// if (TLSA_IS_SUPPORTED(tlsa_chk))
+// ++usable;
+//
+// }
+// sm_dprintf("gettlsa: host=%s, ntlsarrs=%u, usable\%u\n", host, ntlsarrs, usable);
+// }
+#endif /* 0 */
+ sm_dprintf("gettlsa: host=%s, dr=%p, ad=%d, err=%d, herr=%d\n",
+ host, (void *)dr,
+ dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
+ }
ttl = UINT_MAX;
n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
@@ -342,7 +639,7 @@ gettlsa(host, name, pste, flags, mxttl, port)
if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
{
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
+ sm_dprintf("gettlsa: host=%s, n_rrs=%d, herr=%d, status=NOT_ADDED\n",
host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
goto cleanup;
}
@@ -370,7 +667,7 @@ gettlsa(host, name, pste, flags, mxttl, port)
error:
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
+ sm_dprintf("gettlsa: host=%s, key=%s, status=error\n", host, key);
n_rrs = -1;
cleanup:
if (NULL == ste)
@@ -426,15 +723,18 @@ getfallbackmxrr(host)
if (NumFallbackMXHosts > 0 && renew > curtime())
return NumFallbackMXHosts;
- /* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
-# if !DANE
- if (host[0] == '[')
+ /*
+ ** For DANE we need to invoke getmxrr() to get the TLSA RRs.
+ ** Hack: don't do that if its not a FQHN (e.g., [localhost])
+ ** This also triggers for IPv4 addresses, but not IPv6!
+ */
+
+ if (host[0] == '[' && (!Dane || strchr(host, '.') == NULL))
{
fbhosts[0] = host;
NumFallbackMXHosts = 1;
}
else
-# endif
{
/* free old data */
for (i = 0; i < NumFallbackMXHosts; i++)
@@ -448,10 +748,9 @@ getfallbackmxrr(host)
NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
# if DANE
- (DANE_SECURE == Dane) ? ISAD :
+ (DANE_SECURE == Dane) ? ISAD :
# endif
- 0,
- &rcode, &ttl, 0);
+ 0, &rcode, &ttl, 0, NULL);
renew = curtime() + ttl;
for (i = 0; i < NumFallbackMXHosts; i++)
fbhosts[i] = newstr(fbhosts[i]);
@@ -518,7 +817,7 @@ hn2alabel(hostname)
UIDNA *idna;
static char buf[MAXNAME_I]; /* XXX ??? */
- if (addr_is_ascii(hostname))
+ if (str_is_print(hostname))
return hostname;
idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
(void) uidna_nameToASCII_UTF8(idna, hostname, strlen(hostname),
@@ -538,13 +837,15 @@ hn2alabel(hostname)
** mxprefs -- a pointer to a return buffer of MX preferences.
** If NULL, don't try to populate.
** flags -- flags:
-** DROPLOCALHOSt -- If true, all MX records less preferred
+** DROPLOCALHOST -- If true, all MX records less preferred
** than the local host (as determined by $=w) will
** be discarded.
** TRYFALLBACK -- add also fallback MX host?
** ISAD -- host lookup was secure?
** rcode -- a pointer to an EX_ status code.
** pttl -- pointer to return TTL (can be NULL).
+** port -- port number used in TLSA queries (_PORT._tcp.)
+** pad -- (output parameter, pointer to) AD flag (can be NULL)
**
** Returns:
** The number of MX records found.
@@ -559,7 +860,7 @@ hn2alabel(hostname)
*/
int
-getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
+getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port, pad)
char *host;
char **mxhosts;
unsigned short *mxprefs;
@@ -567,6 +868,7 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
int *rcode;
int *pttl;
int port;
+ int *pad;
{
register unsigned char *eom, *cp;
register int i, j, n;
@@ -640,7 +942,7 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
# endif /* DANE */
# if USE_EAI
- if (!addr_is_ascii(host))
+ if (!str_is_print(host))
{
/* XXX memory leak? */
host = sm_rpool_strdup_x(CurEnv->e_rpool, hn2alabel(host));
@@ -727,6 +1029,8 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
ad = ad && hp->ad;
if (tTd(8, 2))
sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
+ if (pad != NULL)
+ *pad = ad;
/* avoid problems after truncation in tcp packets */
if (n > sizeof(answer))
@@ -813,14 +1117,22 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
int nrr;
unsigned long flags;
- flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
+ flags = TLSAFLNEW;
+ if (pad != NULL && *pad)
+ flags |= TLSAFLADMX;
+ if (tTd(8, 20))
+ sm_dprintf("getmxrr: 1: host=%s, mx=%s, flags=%#lx\n", host, bp, flags);
nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
/* Only check qname if no TLSA RRs were found */
if (0 == nrr && cname2mx && '\0' != qname[0] &&
strcmp(qname, bp))
+ {
+ if (tTd(8, 20))
+ sm_dprintf("getmxrr: 2: host=%s, qname=%s, flags=%#lx\n", host, qname, flags);
gettlsa(qname, bp, NULL, flags, ttl, port);
/* XXX is this the right ad flag? */
+ }
}
# endif
@@ -1009,7 +1321,7 @@ punt:
char *hn;
hn = MXHostBuf + 1;
- if (!addr_is_ascii(hn))
+ if (!str_is_print(hn))
{
const char *ahn;
@@ -1058,8 +1370,16 @@ punt:
else
cttl = SM_DEFAULT_TTL;
- flags = (ad && n == HOST_SECURE)
- ? TLSAFLADMX : TLSAFLNOADMX;
+ flags = TLSAFLNEW;
+ if (ad && HOST_SECURE == n)
+ {
+ flags |= TLSAFLADMX;
+ if (pad != NULL)
+ *pad = ad;
+ }
+ if (TTD(8, 20))
+ sm_dprintf("getmxrr: 3: host=%s, mx=%s, flags=%#lx, ad=%d\n",
+ host, mxhosts[0], flags, ad);
nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
cttl, port);
@@ -1070,9 +1390,13 @@ punt:
if (0 == nrr && '\0' != qname[0] &&
strcmp(qname, mxhosts[0]))
+ {
gettlsa(qname, mxhosts[0], NULL, flags,
cttl, port);
+ if (tTd(8, 20))
+ sm_dprintf("getmxrr: 4: host=%s, qname=%s, flags=%#lx\n", host, qname, flags);
/* XXX is this the right ad flag? */
+ }
}
# endif
}
@@ -1081,7 +1405,7 @@ punt:
/* if we have a default lowest preference, include that */
if (fallbackMX != NULL && !seenlocal)
{
- /* TODO: DNSsec status of fallbacks */
+ /* TODO: DNSSEC status of fallbacks */
nmx = fallbackmxrr(nmx, prefs, mxhosts);
}
done:
@@ -1175,7 +1499,7 @@ bestmx_map_lookup(map, name, av, statp)
# endif
_res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
- nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
+ nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1, NULL);
_res.options = saveopts;
if (nmx <= 0)
return NULL;
diff --git a/contrib/sendmail/src/err.c b/contrib/sendmail/src/err.c
index c76fb7714066..3a5dc0fdec67 100644
--- a/contrib/sendmail/src/err.c
+++ b/contrib/sendmail/src/err.c
@@ -114,10 +114,6 @@ fatal_error(exc)
char MsgBuf[BUFSIZ*2]; /* text of most recent message */
static char HeldMessageBuf[sizeof(MsgBuf)]; /* for held messages */
-#if NAMED_BIND && !defined(NO_DATA)
-# define NO_DATA NO_ADDRESS
-#endif
-
void
/*VARARGS1*/
#ifdef __STDC__
diff --git a/contrib/sendmail/src/headers.c b/contrib/sendmail/src/headers.c
index a7896f420d97..bd0ce3450f58 100644
--- a/contrib/sendmail/src/headers.c
+++ b/contrib/sendmail/src/headers.c
@@ -331,6 +331,12 @@ hse:
case '\015': /* cr */
qval[l++] = ' ';
break;
+ case '\\':
+ qval[l++] = fvalue[k];
+ ++k;
+ XLEN(fvalue[k]);
+ qval[l++] = fvalue[k];
+ break;
case '"':
XLEN('\\');
qval[l++] = '\\';
@@ -344,14 +350,22 @@ hse:
XLEN('"');
qval[l++] = '"';
qval[l] = '\0';
- k += strlen(fvalue + k);
- if (k >= sizeof(qval))
+ l = strlen(fvalue + k);
+
+ /*
+ ** If there is something left in fvalue
+ ** then it has been truncated.
+ ** Note: the log entry might not be correct
+ ** in the EAI case: to get the "real" length
+ ** ilenx() would have to be applied to fvalue.
+ */
+
+ if (l > 0)
{
if (LogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
"Warning: truncated header '%s' before check with '%s' len=%d max=%d",
- fname, rs, k,
- (int) (sizeof(qval) - 1));
+ fname, rs, xlen + l, MAXNAME);
}
macdefine(&e->e_macro, A_TEMP,
macid("{currHeader}"), qval);
@@ -498,7 +512,6 @@ hse:
** Contents of 'line' are destroyed.
*/
-
unsigned long
chompheader(line, pflag, hdrp, e)
char *line;
@@ -1122,7 +1135,6 @@ eatheader(e, full, log)
** none
*/
-
#define XBUFLEN MAXNAME
#if (SYSLOG_BUFSIZE) >= 256
# ifndef MSGIDLOGLEN
@@ -1130,11 +1142,11 @@ eatheader(e, full, log)
# define FIRSTLOGLEN 850
# else
# if MSGIDLOGLEN < 100
-# ERROR "MSGIDLOGLEN too short"
+# error "MSGIDLOGLEN too short"
# endif
/* XREF: this is "sizeof(sbuf)", see above */
# if MSGIDLOGLEN >= MAXLINE / 2
-# ERROR "MSGIDLOGLEN too long"
+# error "MSGIDLOGLEN too long"
# endif
/* 850 - 100 for original MSGIDLOGLEN */
@@ -1142,7 +1154,7 @@ eatheader(e, full, log)
/* check that total length is ok */
# if FIRSTLOGLEN + 200 >= MAXLINE
-# ERROR "MSGIDLOGLEN too long"
+# error "MSGIDLOGLEN too long"
# endif
# if MSGIDLOGLEN > MAXNAME
# undef XBUFLEN
@@ -1371,7 +1383,7 @@ priencode(p)
} while (0)
#if MAXNAME < 10
-# ERROR "MAXNAME must be at least 10"
+# error "MAXNAME must be at least 10"
#endif
char *
diff --git a/contrib/sendmail/src/helpfile b/contrib/sendmail/src/helpfile
index d17deb384f16..315cb0b2dfc8 100644
--- a/contrib/sendmail/src/helpfile
+++ b/contrib/sendmail/src/helpfile
@@ -11,8 +11,6 @@ cpyr By using this file, you agree to the terms and conditions set
cpyr forth in the LICENSE file which can be found at the top level of
cpyr the sendmail distribution.
cpyr
-cpyr $$Id: helpfile,v 8.49 2013-11-22 20:51:55 ca Exp $$
-cpyr
smtp This is sendmail version $v
smtp Topics:
smtp HELO EHLO MAIL RCPT DATA
@@ -39,7 +37,6 @@ ehlo TURN Turn the operation around [RFC821]
ehlo 8BITMIME Use 8-bit data [RFC1652]
ehlo SIZE Message size declaration [RFC1870]
ehlo VERB Verbose [Allman]
-ehlo CHUNKING Chunking [RFC1830]
ehlo BINARYMIME Binary MIME [RFC1830]
ehlo PIPELINING Command Pipelining [RFC1854]
ehlo DSN Delivery Status Notification [RFC1891]
@@ -48,6 +45,7 @@ ehlo STARTTLS Secure SMTP [RFC2487]
ehlo AUTH Authentication [RFC2554]
ehlo ENHANCEDSTATUSCODES Enhanced status codes [RFC2034]
ehlo DELIVERBY Deliver By [RFC2852]
+ehlo SMTPUTF8 Internationalized Email [RFC6530]
mail MAIL From:<sender> [ <parameters> ]
mail Specifies the sender. Parameters are ESMTP extensions.
mail See "HELP DSN" for details.
@@ -56,7 +54,7 @@ rcpt Specifies the recipient. Can be used any number of times.
rcpt Parameters are ESMTP extensions. See "HELP DSN" for details.
data DATA
data Following text is collected as the message.
-data End with a single dot.
+data End with a single dot on a line by itself.
rset RSET
rset Resets the system.
quit QUIT
diff --git a/contrib/sendmail/src/macro.c b/contrib/sendmail/src/macro.c
index 23012f4a414f..8dcf9565b55b 100644
--- a/contrib/sendmail/src/macro.c
+++ b/contrib/sendmail/src/macro.c
@@ -83,7 +83,6 @@ int NextMacroId = 0240; /* codes for long named macros */
#define NEXTMACROID(mid) ((mid) + 1)
#endif /* _FFR_MORE_MACROS */
-
/*
** INITMACROS -- initialize the macro system
**
@@ -411,6 +410,9 @@ mactabclear(mac)
** id -- Macro id. This is a single character macro name
** such as 'g', or a value returned by macid().
** value -- Macro value: either NULL, or a string.
+**
+** Returns:
+** none.
*/
void
@@ -442,8 +444,8 @@ macdefine(mac, vclass, id, value)
sm_dprintf(")\n");
}
#if USE_EAI && 0
- if (('j' == id || 'm' == id) && !addr_is_ascii(value))
- return an error/warning to caller and let them handle it.
+// if (('j' == id || 'm' == id) && !addr_is_ascii(value))
+// return an error/warning to caller and let them handle it.
#endif
if (mac->mac_rpool == NULL)
@@ -504,6 +506,9 @@ macdefine(mac, vclass, id, value)
** mac -- Macro table.
** i -- Macro name, specified as an integer offset.
** value -- Macro value: either NULL, or a string.
+**
+** Returns:
+** none.
*/
void
@@ -758,7 +763,51 @@ wordinclass(str, cl)
int cl;
{
STAB *s;
+#if _FFR_DYN_CLASS
+ MAP *map;
+ int status;
+ char *p;
+ char key[MAXLINE];
- s = stab(str, ST_CLASS, ST_FIND);
- return s != NULL && bitnset(bitidx(cl), s->s_class);
+ p = macname(cl);
+ s = stab(p, ST_DYNMAP, ST_FIND);
+ if (NULL == s)
+ {
+#endif
+ s = stab(str, ST_CLASS, ST_FIND);
+ return s != NULL && bitnset(bitidx(cl), s->s_class);
+#if _FFR_DYN_CLASS
+ }
+ map = &s->s_dynclass;
+ SM_REQUIRE(NULL != map);
+ SM_REQUIRE(!SM_IS_EMPTY(str));
+ if (bitset(MF_OPENBOGUS, map->map_mflags))
+ {
+ /* need to set some error! */
+ return false;
+ }
+
+ key[0] = '\0';
+ if (!SM_IS_EMPTY(map->map_tag))
+ {
+ sm_strlcpy(key, map->map_tag, sizeof(key));
+ sm_strlcat(key, ":", sizeof(key));
+ }
+ sm_strlcat(key, str, sizeof(key));
+ status = EX_OK;
+ p = (map->map_class->map_lookup)(map, key, NULL, &status);
+ if (NULL != p)
+ return true;
+ if ((EX_OK == status && NULL == p) || EX_NOTFOUND == status)
+ return false;
+
+ sm_syslog(LOG_WARNING, CurEnv->e_id,
+ "dynamic class: A{%s}: map lookup failed: key=%s, status=%d",
+ map->map_mname, key, status);
+
+ /* Note: this error is shown to the client, so do not "leak" info */
+ usrerr("451 4.3.1 temporary error");
+
+ return false;
+#endif
}
diff --git a/contrib/sendmail/src/main.c b/contrib/sendmail/src/main.c
index d1fd89954d48..849266659391 100644
--- a/contrib/sendmail/src/main.c
+++ b/contrib/sendmail/src/main.c
@@ -326,9 +326,7 @@ main(argc, argv, envp)
V6LoopbackAddrFound = false;
# endif
#endif
-#if XDEBUG
checkfd012("after openlog");
-#endif
tTsetup(tTdvect, sizeof(tTdvect), "0-99.1,*_trace_*.1");
@@ -672,6 +670,11 @@ main(argc, argv, envp)
sm_dprintf(" OpenSSL: linked 0x%08x\n",
(uint) TLS_version_num());
}
+# if defined(LIBRESSL_VERSION_NUMBER)
+ if (tTd(0, 15))
+ sm_dprintf(" LibreSSL: compiled 0x%08x\n",
+ (uint) LIBRESSL_VERSION_NUMBER);
+# endif
#endif /* STARTTLS */
/* clear sendmail's environment */
@@ -1276,9 +1279,7 @@ main(argc, argv, envp)
** Extract special fields for local use.
*/
-#if XDEBUG
checkfd012("before readcf");
-#endif
vendor_pre_defaults(&BlankEnvelope);
readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
@@ -1377,7 +1378,7 @@ main(argc, argv, envp)
makeworkgroups();
#if USE_EAI
- if (!SMTPUTF8 && MainEnvelope.e_smtputf8)
+ if (!SMTP_UTF8 && MainEnvelope.e_smtputf8)
{
usrerr("-U requires SMTPUTF8");
finis(false, true, EX_USAGE);
@@ -1507,8 +1508,8 @@ main(argc, argv, envp)
usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);
BlankEnvelope.e_bodytype = NULL;
}
- else if (i != BODYTYPE_NONE)
- SevenBitInput = (i == BODYTYPE_7BIT);
+ else if (BODYTYPE_7BIT == i)
+ BlankEnvelope.e_flags |= EF_7BITBODY;
/* tweak default DSN notifications */
if (DefaultNotify == 0)
@@ -2014,9 +2015,7 @@ main(argc, argv, envp)
sm_sasl_init();
#endif
-#if XDEBUG
checkfd012("before main() initmaps");
-#endif
/*
** Do operation-mode-dependent initialization.
@@ -2625,7 +2624,6 @@ main(argc, argv, envp)
/* init TLS for server, ignore result for now */
(void) initsrvtls(tls_ok);
#endif
-
nextreq:
p_flags = getrequests(&MainEnvelope);
@@ -2663,8 +2661,8 @@ main(argc, argv, envp)
authinfo = buf;
if (tTd(75, 9))
sm_syslog(LOG_INFO, NOQID,
- "main: where=not_calling_getauthinfo, RealHostAddr=%s",
- anynet_ntoa(&RealHostAddr));
+ "main: where=not_calling_getauthinfo, RealHostAddr=%s, RealHostName=%s",
+ anynet_ntoa(&RealHostAddr), RealHostName);
}
else
/* WARNING: "non-braced" else */
@@ -2818,7 +2816,7 @@ main(argc, argv, envp)
(MainEnvelope.e_smtputf8 = !asciistr(fromaddr))))
{
/* not very efficient: asciistr() may be called above already */
- if (!SMTPUTF8 && !asciistr(fromaddr))
+ if (!SMTP_UTF8 && !asciistr(fromaddr))
{
usrerr("non-ASCII sender address %s requires SMTPUTF8",
fromaddr);
@@ -2879,7 +2877,8 @@ main(argc, argv, envp)
/* collect body for UUCP return */
if (OpMode != MD_VERIFY)
- collect(InChannel, false, NULL, &MainEnvelope, true);
+ collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope,
+ true);
finis(true, true, EX_USAGE);
/* NOTREACHED */
}
@@ -2922,24 +2921,13 @@ main(argc, argv, envp)
int savederrors;
unsigned long savedflags;
- /*
- ** workaround for compiler warning on Irix:
- ** do not initialize variable in the definition, but
- ** later on:
- ** warning(1548): transfer of control bypasses
- ** initialization of:
- ** variable "savederrors" (declared at line 2570)
- ** variable "savedflags" (declared at line 2571)
- ** goto giveup;
- */
-
savederrors = Errors;
savedflags = MainEnvelope.e_flags & EF_FATALERRS;
MainEnvelope.e_flags |= EF_GLOBALERRS;
MainEnvelope.e_flags &= ~EF_FATALERRS;
Errors = 0;
buffer_errors();
- collect(InChannel, false, NULL, &MainEnvelope, true);
+ collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope, true);
/* header checks failed */
if (Errors > 0)
@@ -3285,6 +3273,10 @@ sigterm(sig)
FIX_SYSV_SIGNAL(sig, sigterm);
ShutdownRequest = "signal";
errno = save_errno;
+#if _FFR_DMTRIGGER
+ /* temporary? */
+ proc_list_signal(PROC_QM, sig);
+#endif
return SIGFUNC_RETURN;
}
/*
@@ -3427,7 +3419,7 @@ intsig(sig)
** none
**
** Side Effects:
-** Trys to insure that we are immune to vagaries of
+** Try to insure that we are immune to vagaries of
** the controlling tty.
*/
@@ -3530,9 +3522,7 @@ disconnect(droplev, e)
errno = 0;
}
-#if XDEBUG
checkfd012("disconnect");
-#endif
if (LogLevel > 71)
sm_syslog(LOG_DEBUG, LOGID(e), "in background, pid=%d",
@@ -4219,6 +4209,10 @@ testmodeline(line, e)
#if _FFR_8BITENVADDR
int len = sizeof(exbuf);
#endif
+#if _FFR_TESTS
+ extern void t_hostsig __P((ADDRESS *, char *, MAILER *));
+ extern void t_parsehostsig __P((char *, MAILER *));
+#endif
/* skip leading spaces */
while (*line == ' ')
@@ -4226,6 +4220,7 @@ testmodeline(line, e)
lbp = NULL;
eightbit = false;
+ maps_reset_chged("testmodeline");
switch (line[0])
{
case '#':
@@ -4376,7 +4371,36 @@ testmodeline(line, e)
case '$':
if (line[1] == '=')
{
+#if _FFR_DYN_CLASS
+ MAP *dynmap;
+ STAB *st;
+#endif
+
mid = macid(&line[2]);
+#if _FFR_DYN_CLASS
+ if (mid != 0 &&
+ (st = stab(macname(mid), ST_DYNMAP, ST_FIND)) != NULL)
+ {
+ dynmap = &st->s_dynclass;
+ q = dynmap->map_class->map_cname;
+ if (SM_IS_EMPTY(q))
+ q = "implicit";
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "$=%s not possible for a dynamic class, use\n",
+ line + 2);
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "makemap -u %s %s",
+ q, dynmap->map_file);
+ if (!SM_IS_EMPTY(dynmap->map_tag))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ " | grep -i '^%s:'",
+ dynmap->map_tag);
+ }
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n");
+ return;
+ }
+#endif
if (mid != 0)
stabapply(dump_class, mid);
return;
@@ -4435,7 +4459,7 @@ testmodeline(line, e)
return;
}
nmx = getmxrr(p, mxhosts, NULL, TRYFALLBACK, &rcode,
- NULL, -1);
+ NULL, -1, NULL);
if (nmx == NULLMX)
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
"getmxrr(%s) returns null MX (See RFC7505)\n",
@@ -4626,7 +4650,11 @@ testmodeline(line, e)
macdefine(&e->e_macro, A_TEMP,
macid("{addr_type}"), exbuf);
}
- else if (SM_STRCASEEQ(&line[1], "parse"))
+ else if (SM_STRCASEEQ(&line[1], "parse")
+#if _FFR_TESTS
+ || SM_STRCASEEQ(&line[1], "hostsig")
+#endif
+ )
{
if (*p == '\0')
{
@@ -4653,11 +4681,20 @@ testmodeline(line, e)
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
"Cannot parse\n");
else if (a.q_host != NULL && a.q_host[0] != '\0')
- (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ {
+#if _FFR_TESTS
+ if (SM_STRCASEEQ(&line[1], "hostsig"))
+ t_hostsig(&a, NULL, NULL);
+ else
+#endif /* _FFR_TESTS */
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
"mailer %s, host %s, user %s\n",
a.q_mailer->m_name,
a.q_host,
a.q_user);
+ }
+ }
else
(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
"mailer %s, user %s\n",
@@ -4743,6 +4780,31 @@ testmodeline(line, e)
r = NULL;
}
}
+# if _FFR_TESTS
+ else if (SM_STRCASEEQ(&line[1], "hostsignature"))
+ {
+ STAB *st;
+ MAILER *m;
+
+ st = stab("esmtp", ST_MAILER, ST_FIND);
+ if (NULL == st)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown mailer esmtp\n");
+ return;
+ }
+ m = st->s_mailer;
+ if (NULL == m)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "Unknown mailer esmtp\n");
+ return;
+ }
+ t_hostsig(NULL, p, m);
+ }
+ else if (SM_STRCASEEQ(&line[1], "parsesig"))
+ t_parsehostsig(p, NULL);
+# endif /* _FFR_TESTS */
#endif /* DANE */
else
{
diff --git a/contrib/sendmail/src/map.c b/contrib/sendmail/src/map.c
index 85589a1b4e99..ef655dc4e3cb 100644
--- a/contrib/sendmail/src/map.c
+++ b/contrib/sendmail/src/map.c
@@ -60,7 +60,7 @@ static bool extract_canonname __P((char *, char *, char *, char[], int));
static void map_close __P((STAB *, int));
static void map_init __P((STAB *, int));
#ifdef LDAPMAP
-static STAB * ldapmap_findconn __P((SM_LDAP_STRUCT *));
+static STAB *ldapmap_findconn __P((SM_LDAP_STRUCT *));
#endif
#if NISPLUS
static bool nisplus_getcanonname __P((char *, int, int *));
@@ -91,6 +91,176 @@ static STAB *socket_map_findconn __P((const char*));
#endif /* ENOSYS */
/*
+** MAP_HAS_CHGED -- check whether fd was updated or fn refers to a different file
+**
+** Parameters:
+** map -- map being checked
+** fn -- (full) file name of map.
+** fd -- fd of map.
+**
+** Returns:
+** true iff file referenced by fd was updated
+** or fn refers to a different file.
+*/
+
+static bool map_has_chged __P((MAP *, const char *, int));
+
+static bool
+map_has_chged(map, fn, fd)
+ MAP *map;
+ const char *fn;
+ int fd;
+{
+ struct stat stbuf;
+#if _FFR_MAP_CHK_FILE
+ struct stat nstbuf;
+#endif
+
+#if _FFR_MAP_CHK_FILE > 1
+ if (tTd(38, 8))
+ sm_dprintf("map_has_chged: fn=%s, fd=%d, checked=%d\n",
+ fn, fd, bitset(MF_CHKED_CHGD, map->map_mflags));
+ if (fd < 0)
+ return true;
+
+ /* XXX check can be disabled via -d38.101 for testing */
+ if (bitset(MF_CHKED_CHGD, map->map_mflags) && !tTd(38, 101))
+ return false;
+ map->map_mflags |= MF_CHKED_CHGD;
+#endif
+ if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
+ {
+ if (tTd(38, 4))
+ sm_dprintf("reopen map: name=%s, fd=%d\n", map->map_mname, fd);
+ return true;
+ }
+#if _FFR_MAP_CHK_FILE
+ if (stat(fn, &nstbuf) == 0 &&
+ (nstbuf.st_dev != stbuf.st_dev || nstbuf.st_ino != stbuf.st_ino))
+ {
+ if (tTd(38, 4) && stat(fn, &nstbuf) == 0)
+ sm_dprintf("reopen map: fn=%s, ndev=%d, dev=%d, nino=%d, ino=%d\n",
+ fn, (int) nstbuf.st_dev, (int) stbuf.st_dev,
+ (int) nstbuf.st_ino, (int) stbuf.st_ino);
+ return true;
+ }
+#endif
+ return false;
+}
+
+#if _FFR_MAP_CHK_FILE > 1
+
+/*
+** MAP_RESET_CHGD -- reset MF_CHKED_CHGD in a map
+**
+** Parameters:
+** s -- STAB entry: if map: reset MF_CHKED_CHGD
+** unused -- unused variable
+**
+** Returns:
+** none.
+*/
+
+static void map_reset_chged __P((STAB *, int));
+
+/* ARGSUSED1 */
+static void
+map_reset_chged(s, unused)
+ STAB *s;
+ int unused;
+{
+ MAP *map;
+
+ /* has to be a map */
+ if (ST_MAP != s->s_symtype
+#if _FFR_DYN_CLASS
+ && ST_DYNMAP != s->s_symtype
+#endif
+ )
+ return;
+ map = &s->s_map;
+ if (!bitset(MF_VALID, map->map_mflags))
+ return;
+ if (tTd(38, 8))
+ sm_dprintf("map_reset_chged: name=%s, checked=%d\n",
+ map->map_mname, bitset(MF_CHKED_CHGD, map->map_mflags));
+ map->map_mflags &= ~MF_CHKED_CHGD;
+}
+
+/*
+** MAPS_RESET_CHGD -- reset MF_CHKED_CHGD in all maps
+**
+** Parameters:
+** msg - caller (for debugging)
+**
+** Returns:
+** none.
+*/
+
+void
+maps_reset_chged(msg)
+ const char *msg;
+{
+ if (tTd(38, 16))
+ sm_dprintf("maps_reset_chged: msg=%s\n", msg);
+ stabapply(map_reset_chged, 0);
+}
+#endif /* _FFR_MAP_CHK_FILE > 1 */
+
+
+#if NEWDB || CDB || (NDBM && _FFR_MAP_CHK_FILE)
+static bool smdb_add_extension __P((char *, int, char *, char *));
+
+/*
+** SMDB_ADD_EXTENSION -- Adds an extension to a file name.
+**
+** Just adds a . followed by a string to a db_name if there
+** is room and the db_name does not already have that extension.
+**
+** Parameters:
+** full_name -- The final file name.
+** max_full_name_len -- The max length for full_name.
+** db_name -- The name of the db.
+** extension -- The extension to add.
+**
+** Returns:
+** SMDBE_OK -- Success.
+** Anything else is an error. Look up more info about the
+** error in the comments for the specific open() used.
+*/
+
+static bool
+smdb_add_extension(full_name, max_full_name_len, db_name, extension)
+ char *full_name;
+ int max_full_name_len;
+ char *db_name;
+ char *extension;
+{
+ int extension_len;
+ int db_name_len;
+
+ if (full_name == NULL || db_name == NULL || extension == NULL)
+ return false; /* SMDBE_INVALID_PARAMETER; */
+
+ extension_len = strlen(extension);
+ db_name_len = strlen(db_name);
+
+ if (extension_len + db_name_len + 2 > max_full_name_len)
+ return false; /* SMDBE_DB_NAME_TOO_LONG; */
+
+ if (db_name_len < extension_len + 1 ||
+ db_name[db_name_len - extension_len - 1] != '.' ||
+ strcmp(&db_name[db_name_len - extension_len], extension) != 0)
+ (void) sm_snprintf(full_name, max_full_name_len, "%s.%s",
+ db_name, extension);
+ else
+ (void) sm_strlcpy(full_name, db_name, max_full_name_len);
+
+ return true;
+}
+#endif /* NEWDB || CDB || (NDBM && _FFR_MAP_CHK_FILE) */
+
+/*
** MAP.C -- implementations for various map classes.
**
** Each map class implements a series of functions:
@@ -130,6 +300,7 @@ static STAB *socket_map_findconn __P((const char*));
** to be more properly integrated into the map structure.
*/
+/* XREF: conf.c must use the same expression */
#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
# define LOCK_ON_OPEN 1 /* we can open/create a locked file */
#else
@@ -459,6 +630,52 @@ map_rewrite(map, s, slen, av)
sm_dprintf("map_rewrite => %s\n", buf);
return buf;
}
+
+/*
+** MAPCHOWN -- if available fchown() the fds to TrustedUid
+**
+** Parameters:
+** mapname - name of map (for error reporting)
+** fd0 - first fd (must be valid)
+** fd1 - second fd (<0: do not use)
+** filename - name of file (for error reporting)
+**
+** Returns:
+** none.
+*/
+
+static void mapchown __P((const char *, int, int, const char *));
+
+static void
+mapchown(mapname, fd0, fd1, filename)
+ const char *mapname;
+ int fd0;
+ int fd1;
+ const char *filename;
+{
+ if (!(geteuid() == 0 && TrustedUid != 0))
+ return;
+#if HASFCHOWN
+ if (fchown(fd0, TrustedUid, -1) < 0 ||
+ (fd1 >= 0 && fchown(fd1, TrustedUid, -1) < 0))
+ {
+ int err = errno;
+
+ sm_syslog(LOG_ALERT, NOQID,
+ "ownership change on %s failed: %s",
+ filename, sm_errstring(err));
+ message("050 ownership change on %s failed: %s",
+ filename, sm_errstring(err));
+ }
+#else /* HASFCHOWN */
+ sm_syslog(LOG_ALERT, NOQID,
+ "no fchown(): cannot change ownership on %s",
+ mapname);
+ message("050 no fchown(): cannot change ownership on %s",
+ mapname);
+#endif /* HASFCHOWN */
+}
+
/*
** INITMAPS -- rebuild alias maps
**
@@ -472,14 +689,11 @@ map_rewrite(map, s, slen, av)
void
initmaps()
{
-#if XDEBUG
checkfd012("entering initmaps");
-#endif
stabapply(map_init, 0);
-#if XDEBUG
checkfd012("exiting initmaps");
-#endif
}
+
/*
** MAP_INIT -- rebuild a map
**
@@ -533,7 +747,7 @@ map_init(s, unused)
map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
}
- (void) rebuildaliases(map, false);
+ (void) rebuildaliases(map);
return;
}
/*
@@ -692,7 +906,7 @@ map_close(s, bogus)
map->map_mflags |= MF_CLOSING;
map->map_class->map_close(map);
}
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
+ map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING|MF_CHKED_CHGD);
}
#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
@@ -1072,14 +1286,14 @@ dns_map_parseargs(map,args)
break;
switch (*++p)
{
-# if DNSSEC_TEST
+# if DNSSEC_TEST || _FFR_NAMESERVER
case '@':
++p;
if (nsportip(p) < 0)
syserr("dns map %s: nsportip(%s)=failed",
map->map_mname, p);
break;
-# endif /* DNSSEC_TEST */
+# endif /* DNSSEC_TEST || _FFR_NAMESERVER */
case 'A':
map->map_mflags |= MF_APPEND;
@@ -1243,7 +1457,7 @@ dns_map_parseargs(map,args)
**
** Parameters:
** map -- pointer to MAP
-** name -- name to lookup
+** name -- name to look up
** av -- arguments to interpolate into buf.
** statp -- pointer to status (EX_)
**
@@ -1694,28 +1908,7 @@ ndbm_map_open(map, mode)
else
{
map->map_mflags |= MF_LOCKED;
- if (geteuid() == 0 && TrustedUid != 0)
- {
-# if HASFCHOWN
- if (fchown(dfd, TrustedUid, -1) < 0 ||
- fchown(pfd, TrustedUid, -1) < 0)
- {
- int err = errno;
-
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- map->map_file, sm_errstring(err));
- message("050 ownership change on %s failed: %s",
- map->map_file, sm_errstring(err));
- }
-# else /* HASFCHOWN */
- sm_syslog(LOG_ALERT, NOQID,
- "no fchown(): cannot change ownership on %s",
- map->map_file);
- message("050 no fchown(): cannot change ownership on %s",
- map->map_file);
-# endif /* HASFCHOWN */
- }
+ mapchown(map->map_file, dfd, pfd, map->map_file);
}
return true;
}
@@ -1735,7 +1928,10 @@ ndbm_map_lookup(map, name, av, statp)
datum key, val;
int dfd, pfd;
char keybuf[MAXNAME + 1]; /* EAI:ok */
- struct stat stbuf;
+# if _FFR_MAP_CHK_FILE
+ char buf[MAXPATHLEN];
+# endif
+ const char *fn = NULL;
if (tTd(38, 20))
sm_dprintf("ndbm_map_lookup(%s, %s)\n",
@@ -1752,13 +1948,24 @@ ndbm_map_lookup(map, name, av, statp)
makelower_buf(keybuf, keybuf, sizeof(keybuf));
key.dptr = keybuf;
}
+# if _FFR_MAP_CHK_FILE
+ if (!smdb_add_extension(buf, sizeof(buf), map->map_file, "pag"))
+ {
+ errno = 0;
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("ndbm map \"%s\": map file %s name too long",
+ map->map_mname, map->map_file);
+ return NULL;
+ }
+ fn = buf;
+# endif
lockdbm:
dfd = dbm_dirfno((DBM *) map->map_db1);
if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
(void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
pfd = dbm_pagfno((DBM *) map->map_db1);
- if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
- stbuf.st_mtime > map->map_mtime)
+
+ if (map_has_chged(map, fn, pfd))
{
/* Reopen the database to sync the cache */
int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
@@ -2070,26 +2277,14 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
char buf[MAXPATHLEN];
/* do initial file and directory checks */
- if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
+ if (!smdb_add_extension(buf, sizeof(buf), map->map_file, "db"))
{
errno = 0;
if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("map \"%s\": map file %s name too long",
+ syserr("db map \"%s\": map file %s name too long",
map->map_mname, map->map_file);
return false;
}
- i = strlen(buf);
- if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
- {
- if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf))
- {
- errno = 0;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("map \"%s\": map file %s name too long",
- map->map_mname, map->map_file);
- return false;
- }
- }
mode &= O_ACCMODE;
omode = mode;
@@ -2121,7 +2316,7 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
if (i == ENOENT)
prob = "missing";
if (tTd(38, 2))
- sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
+ sm_dprintf("\t%s map file %s: %s\n", prob, buf, sm_errstring(i));
errno = i;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("%s map \"%s\": %s map file %s",
@@ -2299,36 +2494,14 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
map->map_mflags |= MF_LOCKED;
# if LOCK_ON_OPEN
if (fd >= 0 && mode == O_RDONLY)
- {
(void) lockfile(fd, buf, NULL, LOCK_UN);
- }
-# endif /* LOCK_ON_OPEN */
+# endif
/* try to make sure that at least the database header is on disk */
if (mode == O_RDWR)
{
(void) db->sync(db, 0);
- if (geteuid() == 0 && TrustedUid != 0)
- {
-# if HASFCHOWN
- if (fchown(fd, TrustedUid, -1) < 0)
- {
- int err = errno;
-
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- buf, sm_errstring(err));
- message("050 ownership change on %s failed: %s",
- buf, sm_errstring(err));
- }
-# else /* HASFCHOWN */
- sm_syslog(LOG_ALERT, NOQID,
- "no fchown(): cannot change ownership on %s",
- map->map_file);
- message("050 no fchown(): cannot change ownership on %s",
- map->map_file);
-# endif /* HASFCHOWN */
- }
+ mapchown(map->map_file, fd, -1, buf);
}
map->map_db2 = (ARBPTR_T) db;
@@ -2342,6 +2515,18 @@ db_map_open(map, mode, mapclassname, dbtype, openinfo)
if (fd >= 0 && fstat(fd, &st) >= 0)
map->map_mtime = st.st_mtime;
+# if _FFR_TESTS
+ if (tTd(68, 101) && fd >= 0 && mode == O_RDONLY)
+ {
+ int sl;
+
+ sl = tTdlevel(68) - 100;
+ /* XXX test checks for map type!!! */
+ sm_dprintf("hash_map_open: sleep=%d\n", sl);
+ sleep(sl);
+ }
+# endif
+
if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
!aliaswait(map, ".db", true))
return false;
@@ -2362,11 +2547,9 @@ db_map_lookup(map, name, av, statp)
{
DBT key, val;
register DB *db = (DB *) map->map_db2;
- int i;
int st;
int save_errno;
int fd;
- struct stat stbuf;
char keybuf[MAXNAME + 1]; /* EAI:ok */
char buf[MAXPATHLEN];
@@ -2376,18 +2559,14 @@ db_map_lookup(map, name, av, statp)
if (tTd(38, 20))
sm_dprintf("db_map_lookup(%s, %s)\n",
map->map_mname, name);
-
- if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
+ if (!smdb_add_extension(buf, sizeof(buf), map->map_file, "db"))
{
errno = 0;
if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("map \"%s\": map file %s name too long",
+ syserr("db map \"%s\": map file %s name too long",
map->map_mname, map->map_file);
return NULL;
}
- i = strlen(buf);
- if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
- buf[i - 3] = '\0';
key.size = strlen(name);
if (key.size > sizeof(keybuf) - 1)
@@ -2405,15 +2584,15 @@ db_map_lookup(map, name, av, statp)
errno = db->fd(db, &fd);
# endif /* DB_VERSION_MAJOR < 2 */
if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_SH);
- if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
+ (void) lockfile(fd, buf, NULL, LOCK_SH);
+ if (map_has_chged(map, buf, fd))
{
/* Reopen the database to sync the cache */
int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
: O_RDONLY;
if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_UN);
+ (void) lockfile(fd, buf, NULL, LOCK_UN);
map->map_mflags |= MF_CLOSING;
map->map_class->map_close(map);
map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
@@ -2498,7 +2677,7 @@ db_map_lookup(map, name, av, statp)
}
save_errno = errno;
if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_UN);
+ (void) lockfile(fd, buf, NULL, LOCK_UN);
if (st != 0)
{
errno = save_errno;
@@ -2686,56 +2865,6 @@ db_map_close(map)
** CDB Modules
*/
-static bool smdb_add_extension __P((char *, int, char *, char *));
-
-/*
-** SMDB_ADD_EXTENSION -- Adds an extension to a file name.
-**
-** Just adds a . followed by a string to a db_name if there
-** is room and the db_name does not already have that extension.
-**
-** Parameters:
-** full_name -- The final file name.
-** max_full_name_len -- The max length for full_name.
-** db_name -- The name of the db.
-** extension -- The extension to add.
-**
-** Returns:
-** SMDBE_OK -- Success.
-** Anything else is an error. Look up more info about the
-** error in the comments for the specific open() used.
-*/
-
-static bool
-smdb_add_extension(full_name, max_full_name_len, db_name, extension)
- char *full_name;
- int max_full_name_len;
- char *db_name;
- char *extension;
-{
- int extension_len;
- int db_name_len;
-
- if (full_name == NULL || db_name == NULL || extension == NULL)
- return false; /* SMDBE_INVALID_PARAMETER; */
-
- extension_len = strlen(extension);
- db_name_len = strlen(db_name);
-
- if (extension_len + db_name_len + 2 > max_full_name_len)
- return false; /* SMDBE_DB_NAME_TOO_LONG; */
-
- if (db_name_len < extension_len + 1 ||
- db_name[db_name_len - extension_len - 1] != '.' ||
- strcmp(&db_name[db_name_len - extension_len], extension) != 0)
- (void) sm_snprintf(full_name, max_full_name_len, "%s.%s",
- db_name, extension);
- else
- (void) sm_strlcpy(full_name, db_name, max_full_name_len);
-
- return true;
-}
-
bool
cdb_map_open(map, mode)
MAP *map;
@@ -2748,8 +2877,9 @@ cdb_map_open(map, mode)
char buf[MAXPATHLEN];
if (tTd(38, 2))
- sm_dprintf("cdb_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
+ sm_dprintf("cdb_map_open(%s, %s, %s)\n",
+ map->map_mname, map->map_file,
+ O_RDWR == (mode & O_ACCMODE) ? "rdwr" : "rdonly");
map->map_db1 = (ARBPTR_T)NULL;
map->map_db2 = (ARBPTR_T)NULL;
@@ -2844,6 +2974,10 @@ cdb_map_open(map, mode)
/* actually lock the opened file */
if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
syserr("cdb_map_open: cannot lock %s", buf);
+# else /* !LOCK_ON_OPEN */
+ if (tTd(55, 60))
+ sm_dprintf("lockopen(%s, fd=%d, action=nb, type=%s): SUCCESS\n",
+ buf, fd, mode == O_RDONLY ? "rd" : "wr");
# endif /* !LOCK_ON_OPEN */
map->map_lockfd = fd;
@@ -2867,8 +3001,20 @@ cdb_map_open(map, mode)
}
map->map_db2 = (ARBPTR_T)cdbmp;
+ mapchown(map->map_file, fd, -1, buf);
return true;
}
+ (void) lockfile(fd, buf, NULL, LOCK_UN);
+# if _FFR_TESTS
+ if (tTd(68, 101))
+ {
+ int sl;
+
+ sl = tTdlevel(68) - 100;
+ sm_dprintf("cdb_map_open: sleep=%d\n", sl);
+ sleep(sl);
+ }
+# endif
cdbp = (struct cdb *) xalloc(sizeof(*cdbp));
status = cdb_init(cdbp, fd);
@@ -2879,7 +3025,13 @@ cdb_map_open(map, mode)
syserr("initialization of cdb map failed");
return false;
}
+
map->map_db1 = (ARBPTR_T)cdbp;
+ if (bitset(MF_ALIAS, map->map_mflags) && !aliaswait(map, CDBEXT, true))
+ {
+ close(fd); /* XXX more error handling needed? */
+ return false;
+ }
return true;
}
@@ -2896,7 +3048,6 @@ cdb_map_lookup(map, name, av, statp)
int st, fd;
char key[MAXNAME + 1]; /* EAI:ok */
char buf[MAXPATHLEN];
- struct stat stbuf;
data = NULL;
cdbmap = map->map_db1;
@@ -2909,7 +3060,7 @@ cdb_map_lookup(map, name, av, statp)
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("cdb map \"%s\": map file %s name too long",
map->map_mname, map->map_file);
- return false;
+ return NULL;
}
klen = strlen(name);
@@ -2925,8 +3076,7 @@ cdb_map_lookup(map, name, av, statp)
fd = map->map_lockfd;
if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
(void) lockfile(fd, buf, NULL, LOCK_SH);
-
- if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
+ if (map_has_chged(map, buf, fd))
{
/* Reopen the database to sync the cache */
int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
@@ -3097,7 +3247,7 @@ cdb_map_close(map)
# endif
/*
-** NIS_MAP_OPEN -- open DBM map
+** NIS_MAP_OPEN -- open NIS map
*/
bool
@@ -4037,7 +4187,7 @@ ldapmap_lookup(map, name, av, statp)
char *argv[SM_LDAP_ARGS];
char keybuf[MAXKEY];
# if SM_LDAP_ARGS != MAX_MAP_ARGS
-# ERROR "SM_LDAP_ARGS must be the same as MAX_MAP_ARGS"
+# error "SM_LDAP_ARGS must be the same as MAX_MAP_ARGS"
# endif
# define AV_FREE(av) \
diff --git a/contrib/sendmail/src/map.h b/contrib/sendmail/src/map.h
index d93c971a7c03..513f167b4581 100644
--- a/contrib/sendmail/src/map.h
+++ b/contrib/sendmail/src/map.h
@@ -54,6 +54,10 @@ extern char *macro_map_lookup __P((MAP *, char *, char **, int *));
extern bool map_parseargs __P((MAP *, char *));
+#if LDAPMAP
+extern bool ldapmap_parseargs __P((MAP *, char *));
+#endif
+
#if NDBM
extern char *ndbm_map_lookup __P((MAP *, char *, char **, int *));
extern void ndbm_map_store __P((MAP *, char *, char *));
@@ -68,6 +72,10 @@ extern void null_map_close __P((MAP *));
extern char *null_map_lookup __P((MAP *, char *, char **, int *));
extern void null_map_store __P((MAP *, char *, char *));
+#if PH_MAP
+extern bool ph_map_parseargs __P((MAP *, char *));
+#endif
+
extern char *prog_map_lookup __P((MAP *, char *, char **, int *));
extern bool regex_map_init __P((MAP *, char *));
diff --git a/contrib/sendmail/src/mci.c b/contrib/sendmail/src/mci.c
index c134bd87e8c0..d400035f0d53 100644
--- a/contrib/sendmail/src/mci.c
+++ b/contrib/sendmail/src/mci.c
@@ -351,7 +351,6 @@ mci_clear(mci)
mactabclear(&mci->mci_macro);
}
-
/*
** MCI_GET -- get information about a particular host
**
@@ -617,6 +616,7 @@ struct mcifbits
};
static struct mcifbits MciFlags[] =
{
+ { MCIF_OCC_INCR, "OCC_INCR" },
{ MCIF_CACHED, "CACHED" },
{ MCIF_ESMTP, "ESMTP" },
{ MCIF_EXPN, "EXPN" },
@@ -630,7 +630,6 @@ static struct mcifbits MciFlags[] =
{ MCIF_CVT7TO8, "CVT7TO8" },
{ MCIF_INMIME, "INMIME" },
{ MCIF_AUTH, "AUTH" },
- { MCIF_AUTH2, "AUTH2" },
{ MCIF_AUTHACT, "AUTHACT" },
{ MCIF_ENHSTAT, "ENHSTAT" },
{ MCIF_PIPELINED, "PIPELINED" },
@@ -640,8 +639,16 @@ static struct mcifbits MciFlags[] =
{ MCIF_TLSACT, "TLSACT" },
#endif
{ MCIF_DLVR_BY, "DLVR_BY" },
+#if _FFR_IGNORE_EXT_ON_HELO
+ { MCIF_HELO, "HELO" },
+#endif
{ MCIF_INLONGLINE, "INLONGLINE" },
+ { MCIF_AUTH2, "AUTH2" },
+ { MCIF_ONLY_EHLO, "ONLY_EHLO" },
{ MCIF_NOTSTICKY, "NOTSTICKY" },
+#if USE_EAI
+ { MCIF_EAI, "EAI" },
+#endif
{ 0, NULL }
};
@@ -1200,7 +1207,7 @@ mci_traverse_persistent(action, pathname)
struct dirent *e;
char newpath[MAXPATHLEN];
#if MAXPATHLEN <= MAXNAMLEN - 3
-# ERROR "MAXPATHLEN <= MAXNAMLEN - 3"
+# error "MAXPATHLEN <= MAXNAMLEN - 3"
#endif
if ((d = opendir(pathname)) == NULL)
diff --git a/contrib/sendmail/src/milter.c b/contrib/sendmail/src/milter.c
index 215a52003a00..571c359fef9b 100644
--- a/contrib/sendmail/src/milter.c
+++ b/contrib/sendmail/src/milter.c
@@ -71,7 +71,6 @@ static void milter_delrcpt __P((char *, ssize_t, ENVELOPE *, const char *));
static int milter_replbody __P((char *, ssize_t, bool, ENVELOPE *, const char *));
static int milter_set_macros __P((char *, char **, char *, int));
-
/* milter states */
# define SMFS_CLOSED 'C' /* closed for all further actions */
# define SMFS_OPEN 'O' /* connected to remote milter filter */
@@ -1877,6 +1876,24 @@ milter_abort_filter(m, e)
** none
*/
+#if _FFR_TESTS
+# define TST_EO \
+ do \
+ { \
+ if (tTd(86, 100) && \
+ (SMFIC_EOH == cmd || SMFIC_BODYEOB == cmd) && \
+ strncmp(macros[i], "{EO", 3) == 0) \
+ { \
+ if (SMFIC_EOH == cmd) \
+ v = "at_EOH"; \
+ else if (SMFIC_BODYEOB == cmd) \
+ v = "at_EOM"; \
+ } \
+ } while (0)
+#else
+# define TST_EO ((void) 0)
+#endif
+
static void
milter_send_macros(m, macros, cmd, e)
struct milter *m;
@@ -1904,6 +1921,7 @@ milter_send_macros(m, macros, cmd, e)
if (mid == 0)
continue;
v = macvalue(mid, e);
+ TST_EO;
if (v == NULL)
continue;
expand(v, exp, sizeof(exp), e);
@@ -1928,6 +1946,7 @@ milter_send_macros(m, macros, cmd, e)
if (mid == 0)
continue;
v = macvalue(mid, e);
+ TST_EO;
if (v == NULL)
continue;
expand(v, exp, sizeof(exp), e);
@@ -2289,7 +2308,7 @@ milter_command(cmd, data, sz, stage, e, state, where, cmd_error)
/* log the time it took for the command per filter */
sm_syslog(LOG_INFO, e->e_id,
"Milter (%s): time command (%c), %d",
- m->mf_name, command, (int) (tn - curtime()));
+ m->mf_name, command, (int) (curtime() - tn));
}
if (*state != SMFIR_CONTINUE)
@@ -3329,9 +3348,9 @@ milter_changeheader(m, response, rlen, e)
** MILTER_SPLIT_RESPONSE -- Split response into fields.
**
** Parameters:
-** response -- encoded repsonse.
+** response -- encoded response.
** rlen -- length of response.
-** pargc -- number of arguments (ouput)
+** pargc -- number of arguments (output)
**
** Returns:
** array of pointers to the individual strings
diff --git a/contrib/sendmail/src/mime.c b/contrib/sendmail/src/mime.c
index 126304cb9819..75cb11289506 100644
--- a/contrib/sendmail/src/mime.c
+++ b/contrib/sendmail/src/mime.c
@@ -347,7 +347,7 @@ mime8to7(mci, header, e, boundaries, flags, level)
goto writeerr;
if (tTd(43, 35))
sm_dprintf(" ...%s\n", buf);
- collect(e->e_dfp, false, &hdr, e, false);
+ collect(e->e_dfp, SMTPMODE_NO, &hdr, e, false);
if (tTd(43, 101))
putline("+++after collect", mci);
if (!putheader(mci, hdr, e, flags))
@@ -409,7 +409,7 @@ mime8to7(mci, header, e, boundaries, flags, level)
goto writeerr;
mci->mci_flags |= MCIF_INMIME;
- collect(e->e_dfp, false, &hdr, e, false);
+ collect(e->e_dfp, SMTPMODE_NO, &hdr, e, false);
if (tTd(43, 101))
putline("+++after collect", mci);
if (!putheader(mci, hdr, e, flags))
@@ -483,7 +483,7 @@ mime8to7(mci, header, e, boundaries, flags, level)
** If more than 1/8 of the total characters have the
** eighth bit set, use base64; else use quoted-printable.
** However, only encode binary encoded data as base64,
- ** since otherwise the NL=>CRLF mapping will be a problem.
+ ** since otherwise the LF=>CRLF mapping will be a problem.
*/
if (tTd(43, 8))
@@ -837,7 +837,7 @@ mime_getchar(fp, boundaries, btp)
return *bp++;
}
/*
-** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF
+** MIME_GETCHAR_CRLF -- do mime_getchar, but translate LF => CRLF
**
** Parameters:
** fp -- the input file.
diff --git a/contrib/sendmail/src/parseaddr.c b/contrib/sendmail/src/parseaddr.c
index f73a2688309f..63f7d73c89de 100644
--- a/contrib/sendmail/src/parseaddr.c
+++ b/contrib/sendmail/src/parseaddr.c
@@ -89,7 +89,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
#if _FFR_8BITENVADDR
if (bitset(RF_IS_EXT, flags) && addr != NULL)
{
- int len = 0;
+ int len;
addr = quote_internal_chars(addr, NULL, &len, NULL);
}
@@ -155,8 +155,9 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
a = buildaddr(pvp, a, flags, e);
#if _FFR_8BITENVADDR
+ if (NULL != a->q_user)
{
- int len = 0;
+ int len;
a->q_user = quote_internal_chars(a->q_user, NULL, &len, e->e_rpool); /* EAI: ok */
}
@@ -267,7 +268,7 @@ parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
** isrcpt -- true iff the address is for a recipient.
**
** Returns:
-** true -- if the address has characters that are reservered
+** true -- if the address has characters that are reserved
** for macros or is too long.
** false -- otherwise.
*/
@@ -398,7 +399,7 @@ hasctrlchar(addr, isrcpt, complain)
break;
}
}
- if (!SMTPUTF8 && !EightBitAddrOK && (*addr & 0340) == 0200)
+ if (!SMTP_UTF8 && !EightBitAddrOK && (*addr & 0340) == 0200)
{
setstat(EX_USAGE);
result = "8-bit character";
@@ -447,7 +448,7 @@ allocaddr(a, flags, paddr, e)
ENVELOPE *e;
{
if (tTd(24, 4))
- sm_dprintf("allocaddr(flags=%x, paddr=%s, ad=%d)\n", flags, paddr, bitset(EF_SECURE, e->e_flags));
+ sm_dprintf("allocaddr: flags=%x, paddr=%s, ad=%d\n", flags, paddr, bitset(EF_SECURE, e->e_flags));
a->q_paddr = paddr;
@@ -688,7 +689,6 @@ unsigned char TokTypeNoC[256] =
ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE
};
-
#define NOCHAR (-1) /* signal nothing in lookahead token */
char **
@@ -2015,6 +2015,9 @@ buildaddr(tv, a, flags, e)
char **hostp;
char hbuf[MAXNAME + 1]; /* EAI:ok */
static char ubuf[MAXNAME_I + 2];
+#if _FFR_8BITENVADDR
+ int len;
+#endif
if (tTd(24, 5))
{
@@ -2211,7 +2214,12 @@ badaddr:
}
/* rewrite according recipient mailer rewriting rules */
- macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
+#if _FFR_8BITENVADDR
+ p = quote_internal_chars(a->q_host, NULL, &len, NULL);
+#else
+ p = a->q_host;
+#endif
+ macdefine(&e->e_macro, A_PERM, 'h', p);
if (ConfigLevel >= 10 ||
!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
@@ -2477,7 +2485,6 @@ static struct qflags AddressFlags[] =
{ "QEXPANDED", QEXPANDED },
{ "QDELIVERED", QDELIVERED },
{ "QDELAYED", QDELAYED },
- { "QTHISPASS", QTHISPASS },
{ "QALIAS", QALIAS },
{ "QBYTRACE", QBYTRACE },
{ "QBYNDELAY", QBYNDELAY },
@@ -2485,9 +2492,11 @@ static struct qflags AddressFlags[] =
{ "QINTBCC", QINTBCC },
{ "QDYNMAILER", QDYNMAILER },
{ "QSECURE", QSECURE },
+ { "QQUEUED", QQUEUED },
+ { "QINTREPLY", QINTREPLY },
+ { "QMXSECURE", QMXSECURE },
{ "QTHISPASS", QTHISPASS },
{ "QRCPTOK", QRCPTOK },
- { "QQUEUED", QQUEUED },
{ NULL, 0 }
};
@@ -2880,7 +2889,11 @@ maplocaluser(a, sendq, aliaslevel, e)
{
register char **pvp;
register ADDRESS *SM_NONVOLATILE a1 = NULL;
+ char *p;
char pvpbuf[PSBUFSIZE];
+#if _FFR_8BITENVADDR
+ int len;
+#endif
if (tTd(29, 1))
{
@@ -2897,7 +2910,12 @@ maplocaluser(a, sendq, aliaslevel, e)
return;
}
- macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
+#if _FFR_8BITENVADDR
+ p = quote_internal_chars(a->q_host, NULL, &len, NULL);
+#else
+ p = a->q_host;
+#endif
+ macdefine(&e->e_macro, A_PERM, 'h', p);
macdefine(&e->e_macro, A_PERM, 'u', a->q_user);
macdefine(&e->e_macro, A_PERM, 'z', a->q_home);
@@ -3321,8 +3339,10 @@ rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr)
rwset, p1, lbuf, ubuf);
else
sm_syslog(LOG_NOTICE, logid,
- "ruleset=%s, arg1=%s%s, reject=%s",
- rwset, p1, lbuf, MsgBuf);
+ "ruleset=%s, arg1=%s%s, %s=%s",
+ rwset, p1, lbuf,
+ bitset(RSF_STATUS, flags) ? "status" : "reject",
+ MsgBuf);
}
finis: ;
diff --git a/contrib/sendmail/src/queue.c b/contrib/sendmail/src/queue.c
index 42ac3eb603fd..b6484b054da9 100644
--- a/contrib/sendmail/src/queue.c
+++ b/contrib/sendmail/src/queue.c
@@ -21,6 +21,9 @@ SM_RCSID("@(#)$Id: queue.c,v 8.1000 2013-11-22 20:51:56 ca Exp $")
#if _FFR_DMTRIGGER
# include <sm/notify.h>
#endif
+#if USE_EAI
+# include <sm/ixlen.h>
+#endif
#define RELEASE_QUEUE (void) 0
#define ST_INODE(st) (st).st_ino
@@ -295,7 +298,6 @@ hash_q(p, h)
#define FILE_SYS_BLKSIZE(i) FILE_SYS(i).fs_blksize
#define FILE_SYS_DEV(i) FILE_SYS(i).fs_dev
-
/*
** Current qf file field assignments:
**
@@ -744,6 +746,8 @@ queueup(e, flags)
(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'D');
if (bitset(QINTBCC, q->q_flags))
(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'B');
+ if (bitset(QMXSECURE, q->q_flags))
+ (void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'X');
if (q->q_alias != NULL &&
bitset(QALIAS, q->q_alias->q_flags))
(void) sm_io_putc(tfp, SM_TIME_DEFAULT, 'A');
@@ -1637,7 +1641,6 @@ runqueue(forkflag, verbose, persistent, runall)
}
}
-
#if SM_HEAP_CHECK
if (sm_debug_active(&DebugLeakQ, 1))
sm_heap_setgroup(oldgroup);
@@ -1698,7 +1701,7 @@ skip_domains(skip)
/*
** RUNNER_WORK -- have a queue runner do its work
**
-** Have a queue runner do its work a list of entries.
+** Have a queue runner do its work on a list of entries (WorkQ).
** When work isn't directly being done then this process can take a signal
** and terminate immediately (in a clean fashion of course).
** When work is directly being done, it's not to be interrupted
@@ -2525,7 +2528,7 @@ runqueueevent(ignore)
** full -- (optional) to be set 'true' if WorkList is full
** more -- (optional) to be set 'true' if there are still more
** messages in this queue not added to WorkList
-** pnentries -- (optional) total nuber of entries in queue
+** pnentries -- (optional) total number of entries in queue
**
** Returns:
** The number of request in the queue (not necessarily
@@ -3708,6 +3711,7 @@ dowork(qgrp, qdir, id, forkflag, requeueflag, e)
else
{
pid = 0;
+ maps_reset_chged("dowork");
}
if (pid == 0)
@@ -3947,6 +3951,7 @@ doworklist(el, forkflag, requeueflag)
ei->e_quarmsg != NULL)
continue;
+ maps_reset_chged("doworklist");
rpool = sm_rpool_new_x(NULL);
clearenvelope(&e, true, rpool);
e.e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
@@ -4509,6 +4514,10 @@ readqf(e, openonly)
qflags |= QINTBCC;
break;
+ case 'X':
+ qflags |= QMXSECURE;
+ break;
+
case QDYNMAILFLG:
qflags |= QDYNMAILER;
break;
@@ -4887,6 +4896,28 @@ printqueue()
** Prints a listing of the mail queue on the standard output.
*/
+#if USE_EAI
+# define PRINTADDR(addr, len) \
+ do \
+ { \
+ if (smtputf8) \
+ { \
+ char xbuf[MAXNAME]; \
+ (void) dequote_internal_chars(addr, xbuf, sizeof(xbuf));\
+ if (utf8_valid(xbuf, strlen(xbuf))) \
+ { \
+ (void) sm_io_fprintf(smioout, \
+ SM_TIME_DEFAULT, \
+ "%.*s ", len, xbuf); \
+ break; \
+ } \
+ } \
+ prtstr(addr, len); \
+ } while (0)
+#else
+# define PRINTADDR(addr, len) prtstr(addr, len)
+#endif /* USE_EAI */
+
int
print_single_queue(qgrp, qdir)
int qgrp;
@@ -4998,6 +5029,9 @@ print_single_queue(qgrp, qdir)
char statmsg[MAXLINE];
char bodytype[MAXNAME + 1]; /* EAI:ok */
char qf[MAXPATHLEN];
+#if USE_EAI
+ bool smtputf8 = false;
+#endif
if (StopRequest)
stop_sendmail();
@@ -5114,7 +5148,7 @@ print_single_queue(qgrp, qdir)
bitset(EF_WARNING, flags)
? '+' : ' ',
ctime(&submittime) + 4);
- prtstr(&buf[1], 78);
+ PRINTADDR(buf+1, 78);
}
else
{
@@ -5123,7 +5157,7 @@ print_single_queue(qgrp, qdir)
"%8ld %.16s ",
dfsize,
ctime(&submittime));
- prtstr(&buf[1], 39);
+ PRINTADDR(buf+1, 39);
}
if (quarmsg[0] != '\0')
@@ -5174,14 +5208,14 @@ print_single_queue(qgrp, qdir)
(void) sm_io_fprintf(smioout,
SM_TIME_DEFAULT,
"\n\t\t\t\t\t\t");
- prtstr(p, 71);
+ PRINTADDR(p, 71);
}
else
{
(void) sm_io_fprintf(smioout,
SM_TIME_DEFAULT,
"\n\t\t\t\t\t ");
- prtstr(p, 38);
+ PRINTADDR(p, 38);
}
if (Verbose && statmsg[0] != '\0')
{
@@ -5202,6 +5236,11 @@ print_single_queue(qgrp, qdir)
{
switch (*p)
{
+#if USE_EAI
+ case 'e':
+ smtputf8 = true;
+ break;
+#endif /* USE_EAI */
case 'w':
flags |= EF_WARNING;
break;
@@ -5593,7 +5632,6 @@ unlockqueue(e)
sm_dprintf("unlockqueue(%s)\n",
e->e_id == NULL ? "NOQUEUE" : e->e_id);
-
/* if there is a lock file in the envelope, close it */
SM_CLOSE_FP(e->e_lockfp);
@@ -5840,7 +5878,7 @@ qid_printqueue(qgrp, qdir)
** fsize -- file size in bytes
** e -- envelope, or NULL
**
-** Result:
+** Returns:
** NOQDIR if no queue directory in qg has enough free space to
** hold a file of size 'fsize', otherwise the index of
** a randomly selected queue directory which resides on a
@@ -6351,7 +6389,6 @@ multiqueue_cache(basedir, blen, qg, qn, phash)
qg->qg_qpaths[qg->qg_numqueues].qp_subdirs |= flag; \
else
-
CHKRSUBDIR("qf", QP_SUBQF);
CHKRSUBDIR("df", QP_SUBDF);
CHKRSUBDIR("xf", QP_SUBXF);
@@ -7233,7 +7270,6 @@ init_shm(qn, owner, hash)
}
#endif /* SM_CONF_SHM */
-
/*
** SETUP_QUEUES -- set up all queue groups
**
@@ -7333,7 +7369,6 @@ setup_queues(owner)
for (i = 0; i < NumQueue && Queue[i] != NULL; i++)
Queue[i]->qg_nextrun = now;
-
if (UseMSP && OpMode != MD_TEST)
{
long sff = SFF_CREAT;
@@ -8017,7 +8052,7 @@ makeworkgroups()
** old -- old envelope.
** new -- new envelope.
**
-** Results:
+** Returns:
** Returns true on success, false on failure.
**
** Side Effects:
@@ -8119,7 +8154,7 @@ dup_df(old, new)
** qgrp -- index of queue group.
** qdir -- queue directory.
**
-** Results:
+** Returns:
** new envelope.
**
*/
@@ -8190,7 +8225,7 @@ split_env(e, sendqueue, qgrp, qdir)
** Parameters:
** e -- envelope.
**
-** Results:
+** Returns:
** SM_SPLIT_FAIL on failure
** SM_SPLIT_NONE if no splitting occurred,
** or 1 + the number of additional envelopes created.
@@ -8413,7 +8448,7 @@ split_across_queue_groups(e)
** Parameters:
** e -- envelope.
**
-** Results:
+** Returns:
** SM_SPLIT_FAIL on failure
** SM_SPLIT_NONE if no splitting occurred,
** or 1 + the number of additional envelopes created.
@@ -8605,7 +8640,7 @@ split_within_queue(e)
** Parameters:
** e -- envelope.
**
-** Results:
+** Returns:
** Returns true on success, false on failure.
**
** Side Effects:
@@ -8703,7 +8738,7 @@ split_by_recipient(e)
** e -- envelope information for the item
** reason -- quarantine reason, NULL means unquarantine.
**
-** Results:
+** Returns:
** true if item changed, false otherwise
**
** Side Effects:
@@ -8936,7 +8971,6 @@ quarantine_queue_item(qgrp, qdir, e, reason)
failing = true;
}
-
/* Figure out the new filename */
newtype = (reason == NULL ? NORMQF_LETTER : QUARQF_LETTER);
if (oldtype == newtype)
@@ -9062,7 +9096,7 @@ quarantine_queue_item(qgrp, qdir, e, reason)
** reason -- quarantine reason, "." means unquarantine.
** qgrplimit -- limit to single queue group unless NOQGRP
**
-** Results:
+** Returns:
** none.
**
** Side Effects:
@@ -9169,141 +9203,3 @@ quarantine_queue(reason, qgrplimit)
changed == 1 ? "" : "s");
}
}
-
-#if _FFR_DMTRIGGER
-/*
-** QM -- queue "manager"
-**
-** Parameters:
-** none.
-**
-** Results:
-** false on error
-**
-** Side Effects:
-** fork()s and runs as process to deliver queue entries
-*/
-
-bool
-qm()
-{
- int r;
- pid_t pid;
- long tmo;
-
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: start");
-
- (void) sm_blocksignal(SIGCHLD);
- (void) sm_signal(SIGCHLD, reapchild);
-
- pid = dofork();
- if (pid == -1)
- {
- const char *msg = "queue manager -- fork() failed";
- const char *err = sm_errstring(errno);
-
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID, "%s: %s",
- msg, err);
- (void) sm_releasesignal(SIGCHLD);
- return false;
- }
- if (pid != 0)
- {
- /* parent -- pick up intermediate zombie */
- (void) sm_releasesignal(SIGCHLD);
- return true;
- }
-
-/* XXX put this into a macro/function because it is used several times? */
- /* child -- clean up signals */
-
- /* Reset global flags */
- RestartRequest = NULL;
- RestartWorkGroup = false;
- ShutdownRequest = NULL;
- PendingSignal = 0;
- CurrentPid = getpid();
- close_sendmail_pid();
-
- /*
- ** Initialize exception stack and default exception
- ** handler for child process.
- */
-
- sm_exc_newthread(fatal_error);
- clrcontrol();
- proc_list_clear();
-
- /* Add parent process as first child item */
- proc_list_add(CurrentPid, "Queue manager", PROC_QM, 0, -1, NULL);
- (void) sm_releasesignal(SIGCHLD);
- (void) sm_signal(SIGCHLD, SIG_DFL);
- (void) sm_signal(SIGHUP, SIG_DFL);
- (void) sm_signal(SIGTERM, intsig);
-
- /* drop privileges */
- if (geteuid() == (uid_t) 0)
- (void) drop_privileges(false);
- disconnect(1, NULL);
- QuickAbort = false;
-
- r = sm_notify_start(true, 0);
- if (r != 0)
- syserr("sm_notify_start() failed=%d", r);
-
- /*
- ** Initially wait indefinitely, then only wait
- ** until something needs to get done (not yet implemented).
- */
-
- tmo = -1;
- while (true)
- {
- char buf[64];
- ENVELOPE *e;
- SM_RPOOL_T *rpool;
-
-/*
-** TODO: This should try to receive multiple ids:
-** after it got one, check for more with a very short timeout
-** and collect them in a list.
-** but them some other code should be used to run all of them.
-*/
-
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=start");
- r = sm_notify_rcv(buf, sizeof(buf), tmo);
- if (-ETIMEDOUT == r)
- {
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=timed_out");
- continue;
- }
- if (r < 0)
- {
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=%d", r);
- goto end;
- }
- if (r > 0 && r < sizeof(buf))
- buf[r] = '\0';
- buf[sizeof(buf) - 1] = '\0';
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: got=%s", buf);
- CurEnv = &QueueEnvelope;
- rpool = sm_rpool_new_x(NULL);
- e = newenvelope(&QueueEnvelope, CurEnv, rpool);
- e->e_flags = BlankEnvelope.e_flags;
- e->e_parent = NULL;
- r = sm_io_sscanf(buf, "N:%d:%d:%s", &e->e_qgrp, &e->e_qdir, e->e_id);
- if (r != 3)
- {
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: buf=%s, scan=%d", buf, r);
- goto end;
- }
- dowork(e->e_qgrp, e->e_qdir, e->e_id, true, false, e);
- }
-
- end:
- sm_syslog(LOG_DEBUG, NOQID, "queue manager: stop");
- finis(false, false, EX_OK);
- return false;
-}
-#endif /* _FFR_DMTRIGGER */
diff --git a/contrib/sendmail/src/ratectrl.c b/contrib/sendmail/src/ratectrl.c
index bfbf7d57990a..b32269ade37f 100644
--- a/contrib/sendmail/src/ratectrl.c
+++ b/contrib/sendmail/src/ratectrl.c
@@ -228,7 +228,7 @@ gen_hash(saddr)
}
}
#else /* HASH_ALG == 1 */
-# ERROR "unsupported HASH_ALG"
+# error "unsupported HASH_ALG"
hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size; ???
#endif /* HASH_ALG == 1 */
@@ -419,7 +419,6 @@ conn_limits(e, now, saddr, clflags, hashary, ratelimit, conclimit)
}
#endif
-
#if RATECTL_DEBUG
logit = true;
#endif
diff --git a/contrib/sendmail/src/readcf.c b/contrib/sendmail/src/readcf.c
index 47c9777cc33b..24b0a6f41bd2 100644
--- a/contrib/sendmail/src/readcf.c
+++ b/contrib/sendmail/src/readcf.c
@@ -16,8 +16,8 @@
#if STARTTLS
# include <tls.h>
#endif
-#if DNSSEC_TEST
-# include <sm_resolve.h>
+#if DNSSEC_TEST || _FFR_NAMESERVER
+# include "sm_resolve.h"
#endif
SM_RCSID("@(#)$Id: readcf.c,v 8.692 2013-11-22 20:51:56 ca Exp $")
@@ -33,12 +33,18 @@ SM_RCSID("@(#)$Id: readcf.c,v 8.692 2013-11-22 20:51:56 ca Exp $")
#define HOURS HOUR
static void fileclass __P((int, char *, char *, bool, bool, bool));
+#if _FFR_DYN_CLASS
+static void dynclass __P((int, char *));
+#endif
static char **makeargv __P((char *));
static void settimeout __P((char *, char *, bool));
static void toomany __P((int, int));
static char *extrquotstr __P((char *, char **, char *, bool *));
static void parse_class_words __P((int, char *));
+#if _FFR_CLASS_RM_ENTRY
+static void classrmentry __P((int, char *));
+#endif
#if _FFR_BOUNCE_QUEUE
static char *bouncequeue = NULL;
@@ -161,6 +167,11 @@ readcf(cfname, safe, e)
char pvpbuf[MAXLINE + MAXATOM];
static char *null_list[1] = { NULL };
extern unsigned char TokTypeNoC[];
+#if _FFR_CLASS_RM_ENTRY
+ int off;
+#else
+# define off 1
+#endif
FileName = cfname;
LineNumber = 0;
@@ -463,7 +474,6 @@ readcf(cfname, safe, e)
endtoken = 0;
break;
-
#if 0
/*
** This doesn't work yet as there are maps defined *after* the cf
@@ -534,12 +544,12 @@ readcf(cfname, safe, e)
if (mid == 0)
break;
#if USE_EAI && 0
- if ('j' == mid && !addr_is_ascii(ep))
- {
- usrerr("hostname %s must be ASCII", ep);
- finis(false, true, EX_CONFIG);
- /* NOTREACHED */
- }
+// if ('j' == mid && !addr_is_ascii(ep))
+// {
+// usrerr("hostname %s must be ASCII", ep);
+// finis(false, true, EX_CONFIG);
+// /* NOTREACHED */
+// }
#endif
p = munchstring(ep, NULL, '\0');
macdefine(&e->e_macro, A_TEMP, mid, p);
@@ -551,9 +561,15 @@ readcf(cfname, safe, e)
case 'C': /* word class */
case 'T': /* trusted user (set class `t') */
+#if _FFR_CLASS_RM_ENTRY
+ if (bp[0] != '\0' && bp[1] == '-')
+ off = 2;
+ else
+ off = 1;
+#endif
if (bp[0] == 'C')
{
- mid = macid_parse(&bp[1], &ep);
+ mid = macid_parse(&bp[off], &ep);
if (mid == 0)
break;
expand(ep, exbuf, sizeof(exbuf), e);
@@ -565,7 +581,7 @@ readcf(cfname, safe, e)
else
{
mid = 't';
- p = &bp[1];
+ p = &bp[off];
}
while (*p != '\0')
{
@@ -580,11 +596,29 @@ readcf(cfname, safe, e)
delim = *p;
*p = '\0';
if (wd[0] != '\0')
- setclass(mid, wd);
+ {
+ if (off < 2)
+ setclass(mid, wd);
+#if _FFR_CLASS_RM_ENTRY
+ else
+ classrmentry(mid, wd);
+#endif /* _FFR_CLASS_RM_ENTRY */
+ }
*p = delim;
}
break;
+#if _FFR_DYN_CLASS
+ case 'A': /* dynamic class */
+ mid = macid_parse(&bp[1], &ep);
+ if (mid == 0)
+ break;
+ for (p = ep; SM_ISSPACE(*p); )
+ p++;
+ dynclass(mid, p);
+ break;
+#endif
+
case 'F': /* word class from file */
mid = macid_parse(&bp[1], &ep);
if (mid == 0)
@@ -940,11 +974,11 @@ toomany(id, maxcnt)
syserr("too many %c lines, %d max", id, maxcnt);
}
/*
-** FILECLASS -- read members of a class from a file
+** FILECLASS -- read members of a class from a file, program, or map
**
** Parameters:
** class -- class to define.
-** filename -- name of file to read.
+** filename -- name of file to read/specification of map and key.
** fmt -- scanf string to use for match.
** ismap -- if set, this is a map lookup.
** safe -- if set, this is a safe read.
@@ -955,8 +989,10 @@ toomany(id, maxcnt)
** none
**
** Side Effects:
-** puts all lines in filename that match a scanf into
-** the named class.
+** puts all entries retrieved from a file, program, or map
+** into the named class:
+** - file or |prg: all words in lines that match a scanf fmt
+** - map: all words in value (rhs) of a map lookup of a key
*/
/*
@@ -1109,7 +1145,6 @@ fileclass(class, filename, fmt, ismap, safe, optional)
sm_dprintf("fileclass: F{%s}: map class %s, key %s, spec %s\n",
mn, cl, key, spec);
-
/* parse map spec */
if (!map.map_class->map_parse(&map, spec))
{
@@ -1229,6 +1264,124 @@ fileclass(class, filename, fmt, ismap, safe, optional)
(void) waitfor(pid);
}
+#if _FFR_DYN_CLASS
+
+/*
+** DYNCLASS -- open a dynamic class
+**
+** Parameters:
+** class -- class to define.
+** arg -- rest of class definition from cf.
+**
+** Returns:
+** none
+*/
+
+static void
+dynclass(class, arg)
+ int class;
+ char *arg;
+{
+ char *p;
+ char *tag;
+ char *mn;
+ char *maptype, *spec;
+ STAB *mapclass, *dynmap;
+
+ mn = newstr(macname(class));
+ if (*arg == '\0')
+ {
+ syserr("dynamic class: A{%s}: missing class definition", mn);
+ return;
+ }
+ tag = arg;
+ dynmap = stab(mn, ST_DYNMAP, ST_FIND);
+ if (NULL != dynmap)
+ {
+ syserr("dynamic class: A{%s}: already defined", mn);
+ goto error;
+ }
+
+ /* skip past tag */
+ if ((p = strchr(arg, '@')) == NULL)
+ {
+ /* should not happen */
+ syserr("dynamic class: A{%s}: bogus map specification", mn);
+ goto error;
+ }
+
+ /* skip past '@' */
+ *p++ = '\0';
+ maptype = p;
+
+ if ((spec = strchr(maptype, ':')) == NULL)
+ {
+ syserr("dynamic class: A{%s}: missing map class", mn);
+ goto error;
+ }
+ *spec++ ='\0';
+
+ /* set up map structure */
+ mapclass = stab(maptype, ST_MAPCLASS, ST_FIND);
+ if (NULL == mapclass)
+ {
+ syserr("dynamic class: A{%s}: map type %s not available",
+ mn, maptype);
+ goto error;
+ }
+
+ if (tTd(37, 5))
+ sm_dprintf("dynamic class: A{%s}: type='%s', tag='%s', spec='%s'\n",
+ mn, maptype, tag, spec);
+
+ /* enter map in stab */
+ dynmap = stab(mn, ST_DYNMAP, ST_ENTER);
+ if (NULL == dynmap)
+ {
+ syserr("dynamic class: A{%s}: cannot enter", mn);
+ goto error2;
+ }
+ dynmap->s_dynclass.map_class = &mapclass->s_mapclass;
+ dynmap->s_dynclass.map_mname = newstr(mn);
+
+ /* parse map spec */
+ if (!dynmap->s_dynclass.map_class->map_parse(&dynmap->s_dynclass, spec))
+ {
+ /* map_parse() showed the error already */
+ goto error;
+ }
+
+ /* open map */
+ if (dynmap->s_dynclass.map_class->map_open(&dynmap->s_dynclass, O_RDONLY))
+ {
+ dynmap->s_dynclass.map_mflags |= MF_OPEN;
+ dynmap->s_dynclass.map_pid = getpid();
+ }
+ else
+ {
+ syserr("dynamic class: A{%s}: map open failed", mn);
+ goto error;
+ }
+ dynmap->s_dynclass.map_mflags |= MF_VALID;
+ dynmap->s_dynclass.map_tag = newstr(tag);
+
+#if 0
+ /* close map: where to do this? */
+ dynmap->s_dynclass.map_mflags |= MF_CLOSING;
+ dynmap->s_dynclass.map_class->map_close(&map);
+ dynmap->s_dynclass.map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
+#endif
+ sm_free(mn);
+ return;
+
+ error:
+ dynmap->s_dynclass.map_mflags |= MF_OPENBOGUS;
+ error2:
+ sm_free(mn);
+ return;
+}
+#endif
+
#if _FFR_RCPTFLAGS
/* first character for dynamically created mailers */
static char dynmailerp = ' ';
@@ -1380,7 +1533,6 @@ newmodmailer(rcpt, fl)
** enters the mailer into the mailer table.
*/
-
void
makemailer(line)
char *line;
@@ -2958,7 +3110,7 @@ static struct optioninfo
#endif
#if _FFR_EIGHT_BIT_ADDR_OK
# if !ALLOW_255
-# ERROR "_FFR_EIGHT_BIT_ADDR_OK requires ALLOW_255"
+# error "_FFR_EIGHT_BIT_ADDR_OK requires ALLOW_255"
# endif
# define O_EIGHT_BIT_ADDR_OK 0xdf
{ "EightBitAddrOK", O_EIGHT_BIT_ADDR_OK, OI_NONE },
@@ -3013,7 +3165,7 @@ static struct optioninfo
# define O_TLSFB2CLEAR 0xef
{ "TLSFallbacktoClear", O_TLSFB2CLEAR, OI_NONE },
#endif
-#if DNSSEC_TEST
+#if DNSSEC_TEST || _FFR_NAMESERVER
# define O_NSPORTIP 0xf0
{ "NameServer", O_NSPORTIP, OI_NONE },
#endif
@@ -3021,7 +3173,7 @@ static struct optioninfo
# define O_DANE 0xf1
{ "DANE", O_DANE, OI_NONE },
#endif
-#if DNSSEC_TEST
+#if DNSSEC_TEST || _FFR_NAMESERVER
# define O_NSSRCHLIST 0xf2
{ "NameSearchList", O_NSSRCHLIST, OI_NONE },
#endif
@@ -3744,7 +3896,6 @@ setoption(opt, val, safe, sticky, e)
WkTimeFact = atoi(val);
break;
-
#if _FFR_QUEUE_GROUP_SORTORDER
/* coordinate this with makequeue() */
#endif
@@ -4737,7 +4888,7 @@ setoption(opt, val, safe, sticky, e)
UseCompressedIPv6Addresses = atobool(val);
break;
-#if DNSSEC_TEST
+#if DNSSEC_TEST || _FFR_NAMESERVER
case O_NSPORTIP:
nsportip(val);
break;
@@ -4776,9 +4927,9 @@ setoption(opt, val, safe, sticky, e)
#if USE_EAI
/* hack for testing */
if (isascii(*val) && isdigit(*val))
- SMTPUTF8 = (int) strtol(val, NULL, 0);
+ SMTP_UTF8 = (int) strtol(val, NULL, 0);
else
- SMTPUTF8 = atobool(val);
+ SMTP_UTF8 = atobool(val);
#else
if (atobool(val))
syserr("readcf: option: %s set but no USE_EAI support",
@@ -4861,6 +5012,42 @@ setclass(class, str)
setbitn(bitidx(class), s->s_class);
}
}
+
+#if _FFR_CLASS_RM_ENTRY
+/*
+** CLASSRMENTRY -- remove a string from a class
+**
+** Parameters:
+** class -- the class from which to remove the string.
+** str -- the string to remove
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** removes the string from the class (if it was in there).
+*/
+
+static void
+classrmentry(class, str)
+ int class;
+ char *str;
+{
+ STAB *s;
+
+ s = stab(str, ST_CLASS, ST_FIND);
+ if (NULL == s /* || ST_CLASS != s->s_symtype */)
+ {
+ if (tTd(37, 8))
+ sm_dprintf("classrmentry: entry=%s not in class %s\n", str, macname(class));
+ return;
+ }
+ clrbitn(bitidx(class), s->s_class);
+ if (tTd(37, 8))
+ sm_dprintf("classrmentry(%s, %s)=%d\n", macname(class), str, bitnset(bitidx(class), s->s_class));
+}
+#endif /* _FFR_CLASS_RM_ENTRY */
+
/*
** MAKEMAPENTRY -- create a map entry
**
@@ -5169,7 +5356,6 @@ static struct timeoutinfo
{ NULL, 0 },
};
-
static void
settimeout(name, val, sticky)
char *name;
diff --git a/contrib/sendmail/src/recipient.c b/contrib/sendmail/src/recipient.c
index a118f38c7168..96e4a1d25d96 100644
--- a/contrib/sendmail/src/recipient.c
+++ b/contrib/sendmail/src/recipient.c
@@ -117,9 +117,11 @@ sortbysignature(xx, yy)
/* Let's avoid redoing the signature over and over again */
if (xx->q_signature == NULL)
- xx->q_signature = hostsignature(xx->q_mailer, xx->q_host, xx->q_flags & QSECURE);
+ xx->q_signature = hostsignature(xx->q_mailer, xx->q_host,
+ QISSECURE(xx), NULL);
if (yy->q_signature == NULL)
- yy->q_signature = hostsignature(yy->q_mailer, yy->q_host, yy->q_flags & QSECURE);
+ yy->q_signature = hostsignature(yy->q_mailer, yy->q_host,
+ QISSECURE(yy), NULL);
ret = strcmp(xx->q_signature, yy->q_signature);
/*
@@ -748,7 +750,7 @@ recipient(new, sendq, aliaslevel, e)
if (i == 0) /* equal */
{
/*
- ** Sortbysignature() has said that the two have
+ ** sortbysignature() has said that the two have
** equal MX RR's and the same user. Calling sameaddr()
** now checks if the two hosts are as identical as the
** MX RR's are (which might not be the case)
@@ -1600,7 +1602,6 @@ include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
else
ev = NULL;
-
/* check for writable parent directory */
p = strrchr(fname, '/');
if (p != NULL)
@@ -1977,7 +1978,7 @@ sendtoargv(argv, e)
{
int len = 0;
- if (!SMTPUTF8 && !asciistr(p))
+ if (!SMTP_UTF8 && !asciistr(p))
{
usrerr("non-ASCII recipient address %s requires SMTPUTF8",
p);
diff --git a/contrib/sendmail/src/savemail.c b/contrib/sendmail/src/savemail.c
index 0bf91fd5e06b..008fddeb552f 100644
--- a/contrib/sendmail/src/savemail.c
+++ b/contrib/sendmail/src/savemail.c
@@ -1887,8 +1887,8 @@ pruneroute(addr)
while (start != NULL)
{
- if (getmxrr(hostbuf, mxhosts, NULL, TRYFALLBACK, &rcode, NULL, -1)
- > 0)
+ if (getmxrr(hostbuf, mxhosts, NULL, TRYFALLBACK, &rcode, NULL,
+ -1, NULL) > 0)
{
(void) sm_strlcpy(addr + 1, start + 1,
strlen(addr) - 1);
diff --git a/contrib/sendmail/src/sched.c b/contrib/sendmail/src/sched.c
new file mode 100644
index 000000000000..8a15bcf10f6e
--- /dev/null
+++ b/contrib/sendmail/src/sched.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2021 Proofpoint, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sendmail.h>
+
+#if _FFR_DMTRIGGER
+#include <sm/sendmail.h>
+#include <sm/notify.h>
+
+static ENVELOPE QmEnvelope;
+
+/*
+** Macro for fork():
+** FORK_P1(): parent
+** FORK_C1(): child
+** Note: these are not "universal", e.g.,
+** proc_list_add() might be used in parent or child.
+** maybe check pname != NULL to invoke proc_list_add()?
+*/
+
+#define FORK_P1(emsg, pname, ptype) \
+ do { \
+ (void) sm_blocksignal(SIGCHLD); \
+ (void) sm_signal(SIGCHLD, reapchild); \
+ \
+ pid = dofork(); \
+ if (pid == -1) \
+ { \
+ const char *msg = emsg; \
+ const char *err = sm_errstring(errno); \
+ \
+ if (LogLevel > 8) \
+ sm_syslog(LOG_INFO, NOQID, "%s: %s", \
+ msg, err); \
+ (void) sm_releasesignal(SIGCHLD); \
+ return false; \
+ } \
+ if (pid != 0) \
+ { \
+ proc_list_add(pid, pname, ptype, 0, -1, NULL); \
+ /* parent -- pick up intermediate zombie */ \
+ (void) sm_releasesignal(SIGCHLD); \
+ return true; \
+ } \
+ } while (0)
+
+#define FORK_C1() \
+ do { \
+ /* child -- clean up signals */ \
+ \
+ /* Reset global flags */ \
+ RestartRequest = NULL; \
+ RestartWorkGroup = false; \
+ ShutdownRequest = NULL; \
+ PendingSignal = 0; \
+ CurrentPid = getpid(); \
+ close_sendmail_pid(); \
+ \
+ /* \
+ ** Initialize exception stack and default exception \
+ ** handler for child process. \
+ */ \
+ \
+ sm_exc_newthread(fatal_error); \
+ clrcontrol(); \
+ proc_list_clear(); \
+ \
+ (void) sm_releasesignal(SIGCHLD); \
+ (void) sm_signal(SIGCHLD, SIG_DFL); \
+ (void) sm_signal(SIGHUP, SIG_DFL); \
+ (void) sm_signal(SIGTERM, intsig); \
+ \
+ /* drop privileges */ \
+ if (geteuid() == (uid_t) 0) \
+ (void) drop_privileges(false); \
+ disconnect(1, NULL); \
+ QuickAbort = false; \
+ \
+ } while (0)
+
+/*
+** QM -- queue "manager"
+**
+** Parameters:
+** none.
+**
+** Returns:
+** false on error
+**
+** Side Effects:
+** fork()s and runs as process to deliver queue entries
+*/
+
+bool
+qm()
+{
+ int r;
+ pid_t pid;
+ long tmo;
+
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: start");
+
+ FORK_P1("Queue manager -- fork() failed", "QM", PROC_QM);
+ FORK_C1();
+
+ r = sm_notify_start(true, 0);
+ if (r != 0)
+ syserr("sm_notify_start() failed=%d", r);
+
+ /*
+ ** Initially wait indefinitely, then only wait
+ ** until something needs to get done (not yet implemented).
+ */
+
+ tmo = -1;
+ while (true)
+ {
+ char buf[64];
+ ENVELOPE *e;
+ SM_RPOOL_T *rpool;
+
+/*
+** TODO: This should try to receive multiple ids:
+** after it got one, check for more with a very short timeout
+** and collect them in a list.
+** but them some other code should be used to run all of them.
+*/
+
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=start");
+ r = sm_notify_rcv(buf, sizeof(buf), tmo);
+ if (-ETIMEDOUT == r)
+ {
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=timed_out");
+ continue;
+ }
+ if (r < 0)
+ {
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=%d", r);
+ goto end;
+ }
+ if (r > 0 && r < sizeof(buf))
+ buf[r] = '\0';
+ buf[sizeof(buf) - 1] = '\0';
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: got=%s", buf);
+ CurEnv = &QmEnvelope;
+ rpool = sm_rpool_new_x(NULL);
+ e = newenvelope(&QmEnvelope, CurEnv, rpool);
+ e->e_flags = BlankEnvelope.e_flags;
+ e->e_parent = NULL;
+ r = sm_io_sscanf(buf, "N:%d:%d:%s", &e->e_qgrp, &e->e_qdir, e->e_id);
+ if (r != 3)
+ {
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: buf=%s, scan=%d", buf, r);
+ goto end;
+ }
+ dowork(e->e_qgrp, e->e_qdir, e->e_id, true, false, e);
+ }
+
+ end:
+ sm_syslog(LOG_DEBUG, NOQID, "queue manager: stop");
+ finis(false, false, EX_OK);
+ /* NOTREACHED */
+ return false;
+}
+#endif /* _FFR_DMTRIGGER */
diff --git a/contrib/sendmail/src/sendmail.8 b/contrib/sendmail/src/sendmail.8
index 14e17a22635e..5e001dce8cf9 100644
--- a/contrib/sendmail/src/sendmail.8
+++ b/contrib/sendmail/src/sendmail.8
@@ -87,8 +87,8 @@ or
Go into
ARPANET
mode.
-All input lines must end with a CR-LF,
-and all messages will be generated with a CR-LF at the end.
+All input lines must end with a CRLF,
+and all messages will be generated with a CRLF at the end.
Also,
the ``From:'' and ``Sender:''
fields are examined for the name of the sender.
diff --git a/contrib/sendmail/src/sendmail.h b/contrib/sendmail/src/sendmail.h
index c0ede8f0a759..0f6d01d537ec 100644
--- a/contrib/sendmail/src/sendmail.h
+++ b/contrib/sendmail/src/sendmail.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2013 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2013, 2023,2024 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -46,16 +46,16 @@
# endif
#else /* STARTTLS */
# if DANE
-# ERROR "DANE set but STARTTLS not defined"
+# error "DANE set but STARTTLS not defined"
# endif
# if _FFR_TLS_ALTNAMES
-# ERROR "_FFR_TLS_ALTNAMES set but STARTTLS not defined"
+# error "_FFR_TLS_ALTNAMES set but STARTTLS not defined"
# endif
# if _FFR_TLSFB2CLEAR
-# ERROR "_FFR_TLSFB2CLEAR set but STARTTLS not defined"
+# error "_FFR_TLSFB2CLEAR set but STARTTLS not defined"
# endif
# if _FFR_TLS_USE_CERTIFICATE_CHAIN_FILE
-# ERROR "_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE set but STARTTLS not defined"
+# error "_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE set but STARTTLS not defined"
# endif
#endif /* STARTTLS */
@@ -124,9 +124,12 @@ SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.1104 2013-11-22 20:5
# undef NOERROR /* avoid <sys/streams.h> conflict */
# endif
# include <resolv.h>
+# if !defined(NO_DATA)
+# define NO_DATA NO_ADDRESS
+# endif
#else /* NAMED_BIND */
-# undef SM_SET_H_ERRNO
-# define SM_SET_H_ERRNO(err)
+# undef SM_SET_H_ERRNO
+# define SM_SET_H_ERRNO(err)
#endif /* NAMED_BIND */
#if HESIOD
@@ -140,29 +143,39 @@ SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.1104 2013-11-22 20:5
# define ALLOW_255 1
#endif
#if _FFR_EAI && _FFR_EIGHT_BIT_ADDR_OK
-# ERROR "Cannot enable both of these FFRs: _FFR_EAI _FFR_EIGHT_BIT_ADDR_OK"
+# error "Cannot enable both of these FFRs: _FFR_EAI _FFR_EIGHT_BIT_ADDR_OK"
#endif
#if _FFR_OCC && !SM_CONF_SHM
-# ERROR "_FFR_OCC requires SM_CONF_SHM"
+# error "_FFR_OCC requires SM_CONF_SHM"
#endif
-#if _FFR_SM_LDAP_DBG && !(LDAPMAP && defined(LBER_OPT_LOG_PRINT_FN))
-# ERROR "_FFR_SM_LDAP_DBG requires LDAPMAP and LBER_OPT_LOG_PRINT_FN"
+#if !NOT_SENDMAIL
+# if _FFR_SM_LDAP_DBG && !(LDAPMAP && defined(LBER_OPT_LOG_PRINT_FN))
+# error "_FFR_SM_LDAP_DBG requires LDAPMAP and LBER_OPT_LOG_PRINT_FN"
+# endif
#endif
#if _FFR_LOG_MORE1 > 1 || _FFR_LOG_MORE2 > 1
# if _FFR_LOG_MORE1 != _FFR_LOG_MORE2
-# ERROR "_FFR_LOG_MORE1 != _FFR_LOG_MORE2"
+# error "_FFR_LOG_MORE1 != _FFR_LOG_MORE2"
+# endif
+#endif
+
+#if !NOT_SENDMAIL
+# if LDAP_NETWORK_TIMEOUT && !(LDAPMAP && defined(LDAP_OPT_NETWORK_TIMEOUT))
+# error "LDAP_NETWORK_TIMEOUT requires LDAPMAP"
# endif
#endif
-#if LDAP_NETWORK_TIMEOUT && !(LDAPMAP && defined(LDAP_OPT_NETWORK_TIMEOUT))
-# ERROR "LDAP_NETWORK_TIMEOUT requires LDAPMAP"
+#if !NOT_SENDMAIL
+# if LDAP_REFERRALS && !LDAPMAP
+# error "LDAP_REFERRALS requires LDAPMAP"
+# endif
#endif
#if _FFR_VRFY_TRUSTED_FIRST && !defined(X509_V_FLAG_TRUSTED_FIRST)
-# ERROR "_FFR_VRFY_TRUSTED_FIRST set but X509_V_FLAG_TRUSTED_FIRST not defined"
+# error "_FFR_VRFY_TRUSTED_FIRST set but X509_V_FLAG_TRUSTED_FIRST not defined"
#endif
#if _FFR_8BITENVADDR
@@ -171,26 +184,37 @@ SM_UNUSED(static char SmailId[]) = "@(#)$Id: sendmail.h,v 8.1104 2013-11-22 20:5
# define MAXNAME_I MAXNAME
#endif
+#if !defined(_FFR_M_ONLY_IPV4)
+# define _FFR_M_ONLY_IPV4 1
+#endif
+
#define SM_IS_EMPTY(s) (NULL == (s) || '\0' == *(s))
#if STARTTLS
# if DANE
+# define DANE_FP_LOG_LEN 256
+# define DANE_FP_DBG_LEN 4096
struct dane_vrfy_ctx_S
{
+ /* see tls.h: values for DANE option and dane_vrfy_chk */
int dane_vrfy_chk;
int dane_vrfy_res;
int dane_vrfy_port;
+ /* use OpenSSL functions for DANE checks? */
+ bool dane_vrfy_dane_enabled;
+
/* look up TLSA RRs, SNI unless dane_tlsa_sni is set. */
char *dane_vrfy_host;
char *dane_vrfy_sni; /* if not NULL: use for SNI */
- /* full fingerprint in printable format */
- char dane_vrfy_fp[1024];
+ /* fingerprint in printable format - just for logging */
+ char dane_vrfy_fp[DANE_FP_LOG_LEN];
};
typedef struct dane_tlsa_S dane_tlsa_T, *dane_tlsa_P;
typedef struct dane_vrfy_ctx_S dane_vrfy_ctx_T, *dane_vrfy_ctx_P;
+
# endif /* DANE */
/* TLS information context */
@@ -208,8 +232,8 @@ typedef struct tlsi_ctx_S tlsi_ctx_T, *tlsi_ctx_P;
#define TLSI_FL_CRLREQ 'R' /* CRL required */
#define TLSI_FL_FB2CLR 'C' /* fall back to clear text is ok */
#define TLSI_FL_NOFB2CLR 'c' /* do not fall back to clear text */
-#define TLSI_FL_NODANE 'd' /* do not use/lookup DANE */
-#define TLSI_FL_NOSTS 'M' /* do not use/lookup STS */
+#define TLSI_FL_NODANE 'd' /* do not use/look up DANE */
+#define TLSI_FL_NOSTS 'M' /* do not use/look up STS */
/* internal */
#define TLSI_FL_STS_NOFB2CLR 0x01 /* no clear text: STS is used */
#define SM_TLSI_IS(tlsi_ctx, flag) \
@@ -265,14 +289,14 @@ typedef int (*sasl_callback_ft)(void);
# define SASL SASL_VERSION
# else /* SASL == 1 || SASL == 2 */
# if SASL != SASL_VERSION
-# ERROR "README: -DSASL (SASL) does not agree with the version of the CYRUS_SASL library (SASL_VERSION)"
-# ERROR "README: see README!"
+# error "README: -DSASL (SASL) does not agree with the version of the CYRUS_SASL library (SASL_VERSION)"
+# error "README: see README!"
# endif /* SASL != SASL_VERSION */
# endif /* SASL == 1 || SASL == 2 */
# else /* defined(SASL_VERSION_MAJOR) && defined(SASL_VERSION_MINOR) && defined(SASL_VERSION_STEP) */
# if SASL == 1
-# ERROR "README: please set -DSASL to the version of the CYRUS_SASL library"
-# ERROR "README: see README!"
+# error "README: please set -DSASL to the version of the CYRUS_SASL library"
+# error "README: see README!"
# endif /* SASL == 1 */
# endif /* defined(SASL_VERSION_MAJOR) && defined(SASL_VERSION_MINOR) && defined(SASL_VERSION_STEP) */
#endif /* SASL */
@@ -351,7 +375,7 @@ struct address
char *q_paddr; /* the printname for the address */
char *q_user; /* user name */
char *q_ruser; /* real user name, or NULL if q_user */
- char *q_host; /* host name */
+ char *q_host; /* host name [x] */
#if DANE
char *q_qname; /* original query (host) name */
#endif
@@ -382,6 +406,18 @@ struct address
typedef struct address ADDRESS;
+
+/*
+** Note: only some of the flags are saved in the queue;
+** the code in queue.c does not use the actual value but maps each flag
+** to/from an associated character.
+** If the values would not change then those could be stored/retrieved
+** directly (applying a mask to select those flags which should be kep) --
+** the mapping to/from characters provides a "defined" external interface
+** provided those mappings are kept (and if an old mapping is removed then
+** it should be kept as comment so it is not reused "too soon").
+*/
+
/* bit values for q_flags */
#define QGOODUID 0x00000001 /* the q_uid q_gid fields are good */
#define QPRIMARY 0x00000002 /* set from RCPT or argv */
@@ -403,9 +439,10 @@ typedef struct address ADDRESS;
#define QBYNRELAY 0x00020000 /* DeliverBy: notify, relayed */
#define QINTBCC 0x00040000 /* internal Bcc */
#define QDYNMAILER 0x00080000 /* "dynamic mailer" */
-#define QSECURE 0x00100000 /* DNSSEC ok */
+#define QSECURE 0x00100000 /* DNSSEC ok for host lookup */
#define QQUEUED 0x00200000 /* queued */
#define QINTREPLY 0x00400000 /* internally rejected (delivery) */
+#define QMXSECURE 0x00800000 /* DNSSEC ok for MX lookup */
#define QTHISPASS 0x40000000 /* temp: address set this pass */
#define QRCPTOK 0x80000000 /* recipient() processed address */
@@ -413,6 +450,8 @@ typedef struct address ADDRESS;
#define Q_PINGFLAGS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY)
+#define QISSECURE(r) (0 != ((r)->q_flags & QSECURE))
+
#if _FFR_RCPTFLAGS
# define QMATCHFLAGS (QINTBCC|QDYNMAILER)
# define QMATCH_FLAG(a) ((a)->q_flags & QMATCHFLAGS)
@@ -617,8 +656,8 @@ struct mailer
#define M_NOMX '0' /* turn off MX lookups */
#define M_NONULLS '1' /* don't send null bytes */
#define M_FSMTP '2' /* force SMTP (no ESMTP even if offered) */
- /* '4' free? */
#define M_EBCDIC '3' /* extend Q-P encoding for EBCDIC */
+#define M_ONLY_IPV4 '4' /* Use only IPv4 */
#define M_TRYRULESET5 '5' /* use ruleset 5 after local aliasing */
#define M_7BITHDRS '6' /* strip headers to 7 bits even in 8 bit path */
#define M_7BITS '7' /* use 7-bit path */
@@ -633,6 +672,9 @@ struct mailer
#define M_PLUS '+' /* Reserved: Used in mc for adding new flags */
#define M_MINUS '-' /* Reserved: Used in mc for removing flags */
#define M_NOMHHACK '!' /* Don't perform HM hack dropping explicit from */
+#if _FFR_SMTPS_CLIENT
+# define M_SMTPS_CLIENT '_' /* use SMTP over TLS (465/TCP) */
+#endif
/* functions */
extern void initerrmailers __P((void));
@@ -767,12 +809,12 @@ extern bool filesys_free __P((long));
(SASL_SEC_FORWARD_SECRECY & SASL_SEC_MASK) == 0 || \
(SASL_SEC_NOANONYMOUS & SASL_SEC_MASK) == 0 || \
(SASL_SEC_PASS_CREDENTIALS & SASL_SEC_MASK) == 0
-# ERROR "change SASL_SEC_MASK notify sendmail.org!"
+# error "change SASL_SEC_MASK notify sendmail.org!"
# endif /* SASL_SEC_NOPLAINTEXT & SASL_SEC_MASK) == 0 ... */
# endif /* SASL >= 20101 */
# define MAXOUTLEN 8192 /* length of output buffer, should be 2^n */
# if (SASL_AUTH_AUTH & SASL_SEC_MASK) != 0
-# ERROR "change SASL_AUTH_AUTH notify sendmail.org!"
+# error "change SASL_AUTH_AUTH notify sendmail.org!"
# endif
/* functions */
@@ -875,7 +917,7 @@ MCI
#define MCIF_8BITMIME 0x00000040 /* BODY=8BITMIME supported */
#define MCIF_7BIT 0x00000080 /* strip this message to 7 bits */
/* 0x00000100 unused, was MCIF_MULTSTAT: MAIL11V3: handles MULT status */
-#define MCIF_INHEADER 0x00000200 /* currently outputing header */
+#define MCIF_INHEADER 0x00000200 /* currently outputting header */
#define MCIF_CVT8TO7 0x00000400 /* convert from 8 to 7 bits */
#define MCIF_DSN 0x00000800 /* DSN extension supported */
#define MCIF_8BITOK 0x00001000 /* OK to send 8 bit characters */
@@ -915,6 +957,7 @@ MCI
#define MCIF_EXTENS (MCIF_EXPN|MCIF_SIZE|MCIF_8BITMIME|MCIF_DSN|MCIF_8BITOK|MCIF_AUTH|MCIF_ENHSTAT|MCIF_PIPELINED|MCIF_VERB|MCIF_TLS|MCIF_DLVR_BY|MCIF_AUTH2|MCIF_EAI)
/* states */
+/* XREF: deliver.c: mcis[] -- any changes here must be reflected there! */
#define MCIS_CLOSED 0 /* no traffic on this connection */
#define MCIS_OPENING 1 /* sending initial protocol */
#define MCIS_OPEN 2 /* open, initial protocol sent */
@@ -1032,7 +1075,6 @@ TIMERS
TIMER ti_overall; /* the whole process */
};
-
#define PUSHTIMER(l, t) { if (tTd(98, l)) pushtimer(&t); }
#define POPTIMER(l, t) { if (tTd(98, l)) poptimer(&t); }
@@ -1115,11 +1157,13 @@ struct envelope
MCI *e_mci; /* connection info */
char *e_auth_param; /* readonly; NULL or static storage or
* allocated from e_rpool */
+#if _FFR_TIMERS
TIMERS e_timers; /* per job timers */
+#endif
long e_deliver_by; /* deliver by */
int e_dlvr_flag; /* deliver by flag */
SM_RPOOL_T *e_rpool; /* resource pool for this envelope */
- unsigned int e_features; /* server features */
+ unsigned long e_features; /* server features */
#define ENHSC_LEN 11
#if _FFR_MILTER_ENHSC
char e_enhsc[ENHSC_LEN]; /* enhanced status code */
@@ -1128,6 +1172,9 @@ struct envelope
int e_rcode; /* reply code */
char e_renhsc[ENHSC_LEN]; /* enhanced status code */
char *e_text; /* reply text */
+#if _FFR_LOG_STAGE
+ int e_estate; /* protocol state when error happened */
+#endif
};
#define PRT_NONNEGL(v) ((v) < 0 ? LONG_MAX : (v))
@@ -1151,8 +1198,8 @@ struct envelope
#define EF_LOGSENDER 0x00008000L /* need to log the sender */
#define EF_NORECEIPT 0x00010000L /* suppress all return-receipts */
#define EF_HAS8BIT 0x00020000L /* at least one 8-bit char in body */
-/* was: EF_NL_NOT_EOL 0x00040000L * don't accept raw NL as EOLine */
-/* was: EF_CRLF_NOT_EOL 0x00080000L * don't accept CR-LF as EOLine */
+/* was: EF_NL_NOT_EOL 0x00040000L * don't accept raw LF as EOLine */
+/* was: EF_CRLF_NOT_EOL 0x00080000L * don't accept CRLF as EOLine */
#define EF_RET_PARAM 0x00100000L /* RCPT command had RET argument */
#define EF_HAS_DF 0x00200000L /* set when data file is instantiated */
#define EF_IS_MIME 0x00400000L /* really is a MIME message */
@@ -1163,6 +1210,7 @@ struct envelope
#define EF_UNSAFE 0x08000000L /* unsafe: read from untrusted source */
#define EF_TOODEEP 0x10000000L /* message is nested too deep */
#define EF_SECURE 0x20000000L /* DNSSEC for currently parsed addr */
+#define EF_7BITBODY 0x40000000L /* strip body to 7bit on input */
#define DLVR_NOTIFY 0x01
#define DLVR_RETURN 0x02
@@ -1414,8 +1462,8 @@ typedef union
/* functions */
extern int getcanonname __P((char *, int, bool, int *));
-extern int getmxrr __P((char *, char **, unsigned short *, unsigned int, int *, int *, int));
-extern char *hostsignature __P((MAILER *, char *, bool));
+extern int getmxrr __P((char *, char **, unsigned short *, unsigned int, int *, int *, int, int *));
+extern char *hostsignature __P((MAILER *, char *, bool, unsigned long *));
extern int getfallbackmxrr __P((char *));
/*
@@ -1462,6 +1510,9 @@ MAP
short map_return[MAXMAPACTIONS]; /* return bitmaps for stacked maps */
};
+#if _FFR_DYN_CLASS
+# define map_tag map_domain /* overload map field */
+#endif
/* bit values for map_mflags */
#define MF_VALID 0x00000001 /* this entry is valid */
@@ -1474,7 +1525,8 @@ MAP
#define MF_ALIAS 0x00000080 /* this is an alias file */
#define MF_TRY0NULL 0x00000100 /* try with no null byte */
#define MF_TRY1NULL 0x00000200 /* try with the null byte */
-#define MF_LOCKED 0x00000400 /* this map is currently locked */
+#define MF_LOCKED 0x00000400 /* map is locked (RDWR) */
+/* that means: no extra lockfile() calls must be made (in *map_lookup()) */
#define MF_ALIASWAIT 0x00000800 /* alias map in aliaswait state */
#define MF_IMPL_HASH 0x00001000 /* implicit: underlying hash database */
#define MF_IMPL_NDBM 0x00002000 /* implicit: underlying NDBM database */
@@ -1491,6 +1543,7 @@ MAP
#define MF_CLOSING 0x01000000 /* map is being closed */
#define MF_SECURE 0x02000000 /* DNSSEC result is "secure" */
#define MF_KEEPXFMT 0x04000000 /* keep [x] format */
+#define MF_CHKED_CHGD 0x08000000 /* checked whether underlying map changed */
#define DYNOPENMAP(map) \
do \
@@ -1552,6 +1605,11 @@ extern int udbexpand __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
extern void _udbx_close __P((void));
extern char *udbsender __P((char *, SM_RPOOL_T *));
#endif
+#if _FFR_MAP_CHK_FILE > 1
+extern void maps_reset_chged __P((const char *));
+#else
+# define maps_reset_chged(msg)
+#endif
/*
** LDAP related items
@@ -1579,7 +1637,6 @@ struct lssvalues
};
/* functions */
-extern bool ldapmap_parseargs __P((MAP *, char *));
extern void ldapmap_set_defaults __P((char *));
#endif /* LDAPMAP */
@@ -1712,6 +1769,9 @@ struct symtab
#if DANE
dane_tlsa_P sv_tlsa; /* pointer to TLSA RRs */
#endif
+#if _FFR_DYN_CLASS
+ MAP sv_dynclass; /* map for dynamic class */
+#endif
} s_value;
};
@@ -1746,9 +1806,12 @@ typedef struct symtab STAB;
#if DANE
# define ST_TLSA_RR 17 /* cached TLSA RRs */
#endif
+#if _FFR_DYN_CLASS
+# define ST_DYNMAP 18 /* dynamic map */
+#endif
/* This entry must be last */
-#define ST_MCI 18 /* mailer connection info (offset) */
+#define ST_MCI 19 /* mailer connection info (offset) */
#define s_class s_value.sv_class
#define s_mailer s_value.sv_mailer
@@ -1775,6 +1838,9 @@ typedef struct symtab STAB;
#if DANE
# define s_tlsa s_value.sv_tlsa
#endif
+#if _FFR_DYN_CLASS
+# define s_dynclass s_value.sv_dynclass
+#endif
/* opcodes to stab */
#define ST_FIND 0 /* find entry */
@@ -1960,6 +2026,7 @@ EXTERN unsigned long PrivacyFlags; /* privacy flags */
#define RSF_COUNT 0x0004 /* count rejections (statistics)? */
#define RSF_ADDR 0x0008 /* reassemble address */
#define RSF_STRING 0x0010 /* reassemble address as string */
+#define RSF_STATUS 0x0020 /* log "status" instead of "reject" */
/*
** Flags passed to mime8to7 and putheader.
@@ -2246,6 +2313,7 @@ extern void sync_dir __P((char *, bool));
#endif
#if _FFR_DMTRIGGER
extern bool qm __P((void));
+extern int deliver __P((ENVELOPE *, ADDRESS *));
#endif
/*
@@ -2320,6 +2388,11 @@ extern void inittimeouts __P((char *, bool));
# define tTd(flag, level) (tTdvect[flag] >= (unsigned char)level)
#else
# define tTd(flag, level) (tTdvect[flag] >= (unsigned char)level && !IntSig)
+# if _FFR_TESTS
+# define TTD(flag, level) (tTdvect[flag] >= (unsigned char)level && !IntSig)
+# else
+# define TTD(flag, level) false
+# endif
#endif
#define tTdlevel(flag) (tTdvect[flag])
@@ -2402,6 +2475,7 @@ extern unsigned char tTdvect[100]; /* trace vector */
} while (0)
/* reply types (text in SmtpMsgBuffer) */
+/* XREF: deliver.c: xs_states[] -- any changes here must be reflected there! */
#define XS_DEFAULT 0 /* other commands, e.g., RSET */
#define XS_STARTTLS 1
#define XS_AUTH 2
@@ -2509,6 +2583,8 @@ EXTERN int volatile CurChildren; /* current number of daemonic children */
EXTERN int CurrentLA; /* current load average */
#if DANE
EXTERN int Dane; /* DANE */
+#else
+# define Dane 0 /* XREF: see tls.h: #define DANE_NEVER */
#endif
EXTERN int DefaultNotify; /* default DSN notification flags */
EXTERN int DelayLA; /* load average to delay connections */
@@ -2560,9 +2636,9 @@ EXTERN char *MemoryResource;/* memory resource to look up */
#endif /* _FFR_MEMSTAT */
EXTERN int SuperSafe; /* be extra careful, even if expensive */
#if USE_EAI
-EXTERN int SMTPUTF8; /* enable SMTPUTF8 support */
+EXTERN int SMTP_UTF8; /* enable SMTPUTF8 support */
#else
-# define SMTPUTF8 false
+# define SMTP_UTF8 false
#endif
EXTERN int VendorCode; /* vendor-specific operation enhancements */
EXTERN int Verbose; /* set if blow-by-blow desired */
@@ -2691,10 +2767,10 @@ extern int skipaddrhost __P((const char *, bool));
/* alias file */
extern void alias __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-extern bool aliaswait __P((MAP *, char *, bool));
+extern bool aliaswait __P((MAP *, const char *, bool));
extern void forward __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
extern void readaliases __P((MAP *, SM_FILE_T *, bool, bool));
-extern bool rebuildaliases __P((MAP *, bool));
+extern bool rebuildaliases __P((MAP *));
extern void setalias __P((char *));
/* logging */
@@ -2704,7 +2780,7 @@ extern void PRINTFLIKE(3, 4) sm_syslog __P((int, const char *, const char *, ...
/* SMTP */
extern void giveresponse __P((int, char *, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *, ADDRESS *));
-extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)__P((char *, bool, MAILER *, MCI *, ENVELOPE *)), char **, int));
+extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)__P((char *, bool, MAILER *, MCI *, ENVELOPE *)), char **, int, char **));
extern void smtp __P((char *volatile, BITMAP256, ENVELOPE *volatile));
#if SASL
extern int smtpauth __P((MAILER *, MCI *, ENVELOPE *));
@@ -2784,9 +2860,12 @@ extern void buildfname __P((char *, char *, char *, int));
extern bool chkclientmodifiers __P((int));
extern bool chkdaemonmodifiers __P((int));
extern int checkcompat __P((ADDRESS *, ENVELOPE *));
-#ifdef XDEBUG
+#if XDEBUG
extern void checkfd012 __P((char *));
extern void checkfdopen __P((int, char *));
+#else
+# define checkfd012(str) ((void) 0)
+# define checkfdopen(n, str) ((void) 0)
#endif
extern void checkfds __P((char *));
extern bool chownsafe __P((int, bool));
@@ -2796,7 +2875,7 @@ extern void cleanup_shm __P((bool));
#endif
extern void close_sendmail_pid __P((void));
extern void clrdaemon __P((void));
-extern void collect __P((SM_FILE_T *, bool, HDR **, ENVELOPE *, bool));
+extern void collect __P((SM_FILE_T *, int, HDR **, ENVELOPE *, bool));
extern time_t convtime __P((char *, int));
extern char **copyplist __P((char **, bool, SM_RPOOL_T *));
extern void copy_class __P((int, int));
@@ -2979,6 +3058,15 @@ extern bool xtextok __P((char *));
extern int xunlink __P((char *));
extern char *xuntextify __P((char *));
+/* flags for collect() */
+#define SMTPMODE_NO 0
+#define SMTPMODE_LAX 0x01
+#define SMTPMODE_CRLF 0x02 /* CRLF.CRLF required for EOM */
+#define SMTPMODE_LF_421 0x04 /* bare LF: drop connection */
+#define SMTPMODE_CR_421 0x08 /* bare CR: drop connection */
+#define SMTPMODE_LF_SP 0x10 /* bare LF: replace with space */
+#define SMTPMODE_CR_SP 0x20 /* bare CR: replace with space */
+
#define ASSIGN_IFDIFF(old, new) \
do \
{ \
@@ -2992,6 +3080,7 @@ extern char *xuntextify __P((char *));
#if USE_EAI
extern bool addr_is_ascii __P((const char *));
+extern bool str_is_print __P((const char *));
extern const char *hn2alabel __P((const char *));
#endif
diff --git a/contrib/sendmail/src/sfsasl.c b/contrib/sendmail/src/sfsasl.c
index 7e6b1d141532..8237c1719117 100644
--- a/contrib/sendmail/src/sfsasl.c
+++ b/contrib/sendmail/src/sfsasl.c
@@ -172,7 +172,7 @@ extern void sm_sasl_free __P((void *));
** buf -- the location to place the decrypted information
** size -- the number of bytes to read after decryption
**
-** Results:
+** Returns:
** -1 on error
** otherwise the number of bytes read
*/
@@ -561,7 +561,7 @@ tls_close(fp)
** err -- SSL error
** where -- description of operation
**
-** Results:
+** Returns:
** >0 on success
** 0 on timeout
** <0 on error
@@ -676,7 +676,7 @@ tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
** Parameters:
** rd_tmo -- read timeout
**
-** Results:
+** Returns:
** previous read timeout
** This is a hack: there is no way to pass it in
*/
@@ -702,7 +702,7 @@ set_tls_rd_tmo(rd_tmo)
** buf -- the location to place the data
** size -- the number of bytes to read from connection
**
-** Results:
+** Returns:
** -1 on error
** otherwise the number of bytes read
*/
diff --git a/contrib/sendmail/src/sm_resolve.c b/contrib/sendmail/src/sm_resolve.c
index 977b34103550..e713337c7f04 100644
--- a/contrib/sendmail/src/sm_resolve.c
+++ b/contrib/sendmail/src/sm_resolve.c
@@ -43,14 +43,17 @@
#include <sendmail.h>
#include <sm/sendmail.h>
-#if DNSMAP || DANE
-# if NAMED_BIND
-# if NETINET
-# include <netinet/in_systm.h>
-# include <netinet/ip.h>
-# endif
+
+#if NAMED_BIND
+# if NETINET
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# endif
+# if DNSSEC_TEST || _FFR_NAMESERVER
# define _DEFINE_SMR_GLOBALS 1
-# include "sm_resolve.h"
+# endif
+# include "sm_resolve.h"
+# if DNSMAP || DANE
#include <arpa/inet.h>
@@ -733,92 +736,6 @@ getttlfromstring(str)
return strtoul(str + strlen(TTL_PRE), NULL, 10);
}
-/*
-** DNS_SETNS -- set one NS in resolver context
-**
-** Parameters:
-** ns -- (IPv4 address of) nameserver
-** port -- nameserver port
-**
-** Returns:
-** None.
-*/
-
-static void dns_setns __P((struct in_addr *, unsigned int));
-
-static void
-dns_setns(ns, port)
- struct in_addr *ns;
- unsigned int port;
-{
- _res.nsaddr_list[0].sin_family = AF_INET;
- _res.nsaddr_list[0].sin_addr = *ns;
- if (port != 0)
- _res.nsaddr_list[0].sin_port = htons(port);
- _res.nscount = 1;
- if (tTd(8, 61))
- sm_dprintf("dns_setns(%s,%u)\n", inet_ntoa(*ns), port);
-}
-
-/*
-** NSPORTIP -- parse port@IPv4 and set NS accordingly
-**
-** Parameters:
-** p -- port@Ipv4
-**
-** Returns:
-** <0: error
-** >0: ok
-**
-** Side Effects:
-** sets NS for DNS lookups
-*/
-
-/*
-** There should be a generic function for this...
-** milter_open(), socket_map_open(), others?
-*/
-
-int
-nsportip(p)
- char *p;
-{
- char *h;
- int r;
- unsigned short port;
- struct in_addr nsip;
-
- if (SM_IS_EMPTY(p))
- return -1;
-
- port = 0;
- while (SM_ISSPACE(*p))
- p++;
- if (*p == '\0')
- return -1;
- h = strchr(p, '@');
- if (h != NULL)
- {
- *h = '\0';
- if (isascii(*p) && isdigit(*p))
- port = atoi(p);
- *h = '@';
- p = h + 1;
- }
- h = strchr(p, ' ');
- if (h != NULL)
- *h = '\0';
- r = inet_pton(AF_INET, p, &nsip);
- if (r > 0)
- {
- if ((_res.options & RES_INIT) == 0)
- (void) res_init();
- dns_setns(&nsip, port);
- }
- if (h != NULL)
- *h = ' ';
- return r > 0 ? 0 : -1;
-}
# if defined(T_TLSA)
/*
@@ -1286,7 +1203,7 @@ tstdns_querydomain(name, domain, class, type, answer, anslen)
** DNS_LOOKUP_INT -- perform DNS lookup
**
** Parameters:
-** domain -- name to lookup
+** domain -- name to look up
** rr_class -- resource record class
** rr_type -- resource record type
** retrans -- retransmission timeout
@@ -1435,7 +1352,7 @@ dns_lookup_int(domain, rr_class, rr_type, retrans, retry, options, flags, err, h
** DNS_LOOKUP_MAP -- perform DNS map lookup
**
** Parameters:
-** domain -- name to lookup
+** domain -- name to look up
** rr_class -- resource record class
** rr_type -- resource record type
** retrans -- retransmission timeout
@@ -1633,5 +1550,100 @@ dns2he(dr, family)
return h;
}
# endif /* DANE */
-# endif /* NAMED_BIND */
-#endif /* DNSMAP || DANE */
+# endif /* DNSMAP || DANE */
+
+# if DNSSEC_TEST || _FFR_NAMESERVER
+/*
+** DNS_ADDNS -- add one NS in resolver context
+**
+** Parameters:
+** ns -- (IPv4 address of) nameserver
+** port -- nameserver port (host order)
+**
+** Returns:
+** None.
+*/
+
+static void dns_addns __P((struct in_addr *, unsigned int));
+static int nsidx = 0;
+#ifndef MAXNS
+# define MAXNS 3
+#endif
+static void
+dns_addns(ns, port)
+ struct in_addr *ns;
+ unsigned int port;
+{
+ if (nsidx >= MAXNS)
+ syserr("too many NameServers defined (%d max)", MAXNS);
+ _res.nsaddr_list[nsidx].sin_family = AF_INET;
+ _res.nsaddr_list[nsidx].sin_addr = *ns;
+ if (port != 0)
+ _res.nsaddr_list[nsidx].sin_port = htons(port);
+ _res.nscount = ++nsidx;
+ if (tTd(8, 61))
+ sm_dprintf("dns_addns: nsidx=%d, ns=%s:%u\n",
+ nsidx - 1, inet_ntoa(*ns), port);
+}
+
+/*
+** NSPORTIP -- parse port@IPv4 and set NS accordingly
+**
+** Parameters:
+** p -- port@IPv4
+**
+** Returns:
+** <0: error
+** >=0: ok
+**
+** Side Effects:
+** sets NS for DNS lookups
+*/
+
+/*
+** There should be a generic function for this...
+** milter_open(), socket_map_open(), others?
+*/
+
+int
+nsportip(p)
+ char *p;
+{
+ char *h;
+ int r;
+ unsigned short port;
+ struct in_addr nsip;
+
+ if (SM_IS_EMPTY(p))
+ return -1;
+
+ port = 0;
+ while (SM_ISSPACE(*p))
+ p++;
+ if (*p == '\0')
+ return -1;
+ h = strchr(p, '@');
+ if (h != NULL)
+ {
+ *h = '\0';
+ if (isascii(*p) && isdigit(*p))
+ port = atoi(p);
+ *h = '@';
+ p = h + 1;
+ }
+ h = strchr(p, ' ');
+ if (h != NULL)
+ *h = '\0';
+ r = inet_pton(AF_INET, p, &nsip);
+ if (r > 0)
+ {
+ if ((_res.options & RES_INIT) == 0)
+ (void) res_init();
+ dns_addns(&nsip, port);
+ }
+ if (h != NULL)
+ *h = ' ';
+ return r > 0 ? 0 : -1;
+}
+# endif /* DNSSEC_TEST || _FFR_NAMESERVER */
+#endif /* NAMED_BIND */
diff --git a/contrib/sendmail/src/sm_resolve.h b/contrib/sendmail/src/sm_resolve.h
index 3e4b90993cef..e09af575947b 100644
--- a/contrib/sendmail/src/sm_resolve.h
+++ b/contrib/sendmail/src/sm_resolve.h
@@ -43,10 +43,10 @@
/* $Id: sm_resolve.h,v 8.9 2013-11-22 20:51:56 ca Exp $ */
-#if DNSMAP || DANE
-# ifndef __ROKEN_RESOLVE_H__
-# define __ROKEN_RESOLVE_H__
+#ifndef SM_RESOLVE_H
+#define SM_RESOLVE_H
+#if DNSMAP || DANE
/* We use these, but they are not always present in <arpa/nameser.h> */
# ifndef T_TXT
@@ -166,14 +166,6 @@ int getttlfromstring __P((const char *));
int tstdns_search __P((const char *, int, int, u_char *, int));
int tstdns_querydomain __P((const char *, const char *, int, int, unsigned char *, int));
-# ifdef _DEFINE_SMR_GLOBALS
-# define SMR_EXTERN
-# else
-# define SMR_EXTERN extern
-# endif
-SMR_EXTERN char *NameSearchList;
-# undef SMR_EXTERN
-extern int nsportip __P((char *));
# endif /* DNSSEC_TEST*/
#ifndef RES_TRUSTAD
@@ -181,5 +173,17 @@ extern int nsportip __P((char *));
#endif
#define SM_RES_DNSSEC (RES_USE_EDNS0|RES_USE_DNSSEC|RES_TRUSTAD)
-# endif /* ! __ROKEN_RESOLVE_H__ */
#endif /* DNSMAP || DANE */
+
+#if DNSSEC_TEST || _FFR_NAMESERVER
+# ifdef _DEFINE_SMR_GLOBALS
+# define SMR_EXTERN
+# else
+# define SMR_EXTERN extern
+# endif
+SMR_EXTERN char *NameSearchList;
+# undef SMR_EXTERN
+extern int nsportip __P((char *));
+#endif /* DNSSEC_TEST || _FFR_NAMESERVER */
+
+#endif /* ! SM_RESOLVE_H */
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c
index bd416c3ebdaa..3a6aea87df21 100644
--- a/contrib/sendmail/src/srvrsmtp.c
+++ b/contrib/sendmail/src/srvrsmtp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2010, 2012-2014 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2010, 2012-2014,2021-2024 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -52,30 +52,36 @@ static bool NotFirstDelivery = false;
#endif
/* server features */
-#define SRV_NONE 0x0000 /* none... */
-#define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */
-#define SRV_VRFY_CLT 0x0002 /* request a cert */
-#define SRV_OFFER_AUTH 0x0004 /* offer AUTH */
-#define SRV_OFFER_ETRN 0x0008 /* offer ETRN */
-#define SRV_OFFER_VRFY 0x0010 /* offer VRFY (not yet used) */
-#define SRV_OFFER_EXPN 0x0020 /* offer EXPN */
-#define SRV_OFFER_VERB 0x0040 /* offer VERB */
-#define SRV_OFFER_DSN 0x0080 /* offer DSN */
+#define SRV_NONE 0x00000000 /* none... */
+#define SRV_OFFER_TLS 0x00000001 /* offer STARTTLS */
+#define SRV_VRFY_CLT 0x00000002 /* request a cert */
+#define SRV_OFFER_AUTH 0x00000004 /* offer AUTH */
+#define SRV_OFFER_ETRN 0x00000008 /* offer ETRN */
+#define SRV_OFFER_VRFY 0x00000010 /* offer VRFY (not yet used) */
+#define SRV_OFFER_EXPN 0x00000020 /* offer EXPN */
+#define SRV_OFFER_VERB 0x00000040 /* offer VERB */
+#define SRV_OFFER_DSN 0x00000080 /* offer DSN */
#if PIPELINING
-# define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */
+# define SRV_OFFER_PIPE 0x00000100 /* offer PIPELINING */
# if _FFR_NO_PIPE
-# define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */
+# define SRV_NO_PIPE 0x00000200 /* disable PIPELINING, sleep if used */
# endif
#endif /* PIPELINING */
-#define SRV_REQ_AUTH 0x0400 /* require AUTH */
-#define SRV_REQ_SEC 0x0800 /* require security - equiv to AuthOptions=p */
-#define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */
+#define SRV_REQ_AUTH 0x00000400 /* require AUTH */
+#define SRV_REQ_SEC 0x00000800 /* require security - equiv to AuthOptions=p */
+#define SRV_TMP_FAIL 0x00001000 /* ruleset caused a temporary failure */
#if USE_EAI
-# define SRV_OFFER_EAI 0x2000 /* offer SMTPUTF8 */
+# define SRV_OFFER_EAI 0x00002000 /* offer SMTPUTF8 */
#endif
-#define SRV_NO_HTTP_CMD 0x4000 /* always reject HTTP commands */
+#define SRV_NO_HTTP_CMD 0x00004000 /* always reject HTTP commands */
+#define SRV_BAD_PIPELINE 0x00008000 /* reject bad pipelining (see comment below) */
+#define SRV_REQ_CRLF 0x00010000 /* require CRLF as EOL */
+#define SRV_BARE_LF_421 0x00020000 /* bare LF - drop connection */
+#define SRV_BARE_CR_421 0x00040000 /* bare CR - drop connection */
+#define SRV_BARE_LF_SP 0x00080000
+#define SRV_BARE_CR_SP 0x00100000
-static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int));
+static unsigned long srvfeatures __P((ENVELOPE *, char *, unsigned long));
#define STOP_ATTACK ((time_t) -1)
static time_t checksmtpattack __P((volatile unsigned int *, unsigned int,
@@ -83,6 +89,7 @@ static time_t checksmtpattack __P((volatile unsigned int *, unsigned int,
static void printvrfyaddr __P((ADDRESS *, bool, bool));
static char *skipword __P((char *volatile, char *));
static void setup_smtpd_io __P((void));
+static struct timeval *channel_readable __P((SM_FILE_T *, int));
#if SASL
# ifndef MAX_AUTH_USER_LEN
@@ -165,33 +172,51 @@ extern ENVELOPE BlankEnvelope;
#if USE_EAI
/*
-** ADDR_IS_ASCII -- check whether an address is 100% printable ASCII
+** ADDR_IS_ASCII -- check whether a string (address) is ASCII
**
** Parameters:
-** a -- an address (or other string)
+** str -- a string
**
** Returns:
-** TRUE if a is non-NULL and points to only printable ASCII
-** FALSE if a is NULL and points to printable ASCII
-** FALSE if a is non-NULL and points to something containing 8-bittery
+** TRUE iff str is non-NULL and points to only ASCII
*/
bool
-addr_is_ascii(a)
- const char *a;
+addr_is_ascii(str)
+ const char *str;
{
- while (a != NULL && *a != '\0' && *a >= ' ' && (unsigned char)*a < 127)
- a++;
- return (a != NULL && *a == '\0');
+ while (str != NULL && *str != '\0' && isascii((unsigned char)*str))
+ str++;
+ return (str != NULL && *str == '\0');
}
+/*
+** STR_IS_PRINT -- check whether a string is printable ASCII
+**
+** Parameters:
+** str -- a string
+**
+** Returns:
+** TRUE iff str is non-NULL and points to only printable ASCII
+*/
+
+bool
+str_is_print(str)
+ const char *str;
+{
+ while (str != NULL && *str != '\0' && *str >= ' ' && (unsigned char)*str < 127)
+ str++;
+ return (str != NULL && *str == '\0');
+}
+
+
# define CHECK_UTF8_ADDR(a, q) \
do \
{ \
q = NULL; \
if (addr_is_ascii(a)) \
break; \
- if (!SMTPUTF8) \
+ if (!SMTP_UTF8) \
break; \
if (!e->e_smtputf8) \
q = "553 5.6.7 Address requires SMTPUTF8"; \
@@ -199,7 +224,7 @@ addr_is_ascii(a)
{ \
char str[MAXNAME]; \
dequote_internal_chars(a, str, sizeof(str)); \
- if (!utf8_valid(str, strlen(str)) && SMTPUTF8 <= 1) \
+ if (!utf8_valid(str, strlen(str)) && SMTP_UTF8 <= 1) \
q = "553 5.6.7 Address not valid UTF8"; \
} \
} while (0)
@@ -456,6 +481,90 @@ rcptmods(rcpt, e)
# define rcptmods(a, e)
#endif /* _FFR_RCPTFLAGS */
+#if _FFR_8BITENVADDR
+
+/*
+** SEP_ARGS -- separate address and argument string for MAIL/RCPT command
+**
+** Parameters:
+** args -- arguments (converted to and from internal format)
+** orig -- string after command (original data)
+** id -- envelope id (for logging only)
+** addr -- for logging only: address (original data)
+**
+** Returns:
+** nothing
+*/
+
+static void sep_args __P((char *, char *, const char *, const char *));
+
+static void
+sep_args(args, orig, id, addr)
+ char *args;
+ char *orig;
+ const char *id;
+ const char *addr;
+{
+ int lr, lo;
+ char *q;
+
+ lr = strlen(args);
+ lo = strlen(orig);
+ if (lr >= lo)
+ {
+ sm_syslog(LOG_ERR, id,
+ "ERROR=ARGS_NOT_FOUND, address='%s', rest='%s', orig='%s', strlen(rest)=%d, strlen(orig)=%d",
+ addr, args, orig, lr, lo);
+ return;
+ }
+
+ q = orig + (lo - lr);
+ if (!(q > orig && *--q == ' '))
+ {
+ sm_syslog(LOG_INFO, id,
+ "ERROR=ARGS_DO_NOT_MATCH, address='%s', rest='%s', orig='%s', q='%s', strlen(rest)=%d, strlen(orig)=%d, cmp=%d",
+ addr, args, orig, q, lr, lo, strcmp(args, q));
+ return;
+ }
+
+ for (; q > orig && *q == ' '; q--)
+ *q = '\0';
+}
+#endif /* _FFR_8BITENVADDR */
+
+/*
+** CHANNEL_READBLE -- determine if data is readable from the SMTP channel
+**
+** Parameters:
+** channel -- connect channel for reading
+** timeout -- how long to pause for data in milliseconds
+**
+** Returns:
+** timeval contained how long we waited if data detected,
+** NULL otherwise
+*/
+
+static struct timeval *
+channel_readable(channel, timeout)
+ SM_FILE_T *channel;
+ int timeout;
+{
+ struct timeval bp, ep; /* {begin,end} pause */
+ static struct timeval tp; /* total pause */
+ int eoftest;
+
+ /* check if data is on the channel during the pause */
+ gettimeofday(&bp, NULL);
+ if ((eoftest = sm_io_getc(channel, timeout)) != SM_IO_EOF)
+ {
+ gettimeofday(&ep, NULL);
+ sm_io_ungetc(channel, SM_TIME_DEFAULT, eoftest);
+ timersub(&ep, &bp, &tp);
+ return &tp;
+ }
+ return NULL;
+}
+
/*
** SMTP -- run the SMTP protocol.
**
@@ -579,7 +688,7 @@ static char *CurSmtpClient; /* who's at the other end of channel */
# define MAXSHIFT 8
#endif
#if MAXSHIFT > 31
-# ERROR "MAXSHIFT > 31 is invalid"
+# error "MAXSHIFT > 31 is invalid"
#endif
@@ -616,7 +725,7 @@ typedef struct
char *sm_quarmsg; /* carry quarantining across messages */
} SMTP_T;
-static bool smtp_data __P((SMTP_T *, ENVELOPE *));
+static bool smtp_data __P((SMTP_T *, ENVELOPE *, bool));
#define MSG_TEMPFAIL "451 4.3.2 Please try again later"
@@ -822,8 +931,6 @@ do \
: (tls_active ? "ESMTPS" : "ESMTP"))
#endif /* USE_EAI */
-static bool SevenBitInput_Saved; /* saved version of SevenBitInput */
-
#if _FFR_NOREFLECT
# define SHOWCMDINREPLY(inp) (bitset(PRIV_NOREFLECTION, PrivacyFlags) ? \
"(suppressed)" : inp)
@@ -874,7 +981,7 @@ smtp(nullserver, d_flags, e)
char *args[MAXSMTPARGS];
char inp[MAXINPLINE];
#if MAXINPLINE < MAXLINE
-# ERROR "MAXINPLINE must NOT be less than MAXLINE"
+# error "MAXINPLINE must NOT be less than MAXLINE"
#endif
char cmdbuf[MAXLINE];
#if SASL
@@ -914,6 +1021,7 @@ smtp(nullserver, d_flags, e)
int rfd, wfd;
volatile bool tls_active = false;
volatile bool smtps = bitnset(D_SMTPS, d_flags);
+ bool gotostarttls = false;
bool saveQuickAbort;
bool saveSuprErrs;
time_t tlsstart;
@@ -921,11 +1029,9 @@ smtp(nullserver, d_flags, e)
int save_errno;
extern int TLSsslidx;
#endif /* STARTTLS */
- volatile unsigned int features;
-#if PIPELINING
-# if _FFR_NO_PIPE
+ volatile unsigned long features;
+#if PIPELINING && _FFR_NO_PIPE
int np_log = 0;
-# endif
#endif
volatile time_t log_delay = (time_t) 0;
#if MILTER
@@ -940,9 +1046,9 @@ smtp(nullserver, d_flags, e)
#if _FFR_BADRCPT_SHUTDOWN
int n_badrcpts_adj;
#endif
+ bool gotodoquit = false;
RESET_AUTH_FAIL_LOG_USER;
- SevenBitInput_Saved = SevenBitInput;
smtp.sm_nrcpts = 0;
#if MILTER
smtp.sm_milterize = (nullserver == NULL);
@@ -985,7 +1091,15 @@ smtp(nullserver, d_flags, e)
sm_setproctitle(true, e, "server %s startup", CurSmtpClient);
- /* Set default features for server. */
+ maps_reset_chged("server:smtp");
+
+ /*
+ ** Set default features for server.
+ **
+ ** Changing SRV_BARE_LF_421 | SRV_BARE_CR_421 below also
+ ** requires changing srvfeatures() variant code.
+ */
+
features = ((bitset(PRIV_NOETRN, PrivacyFlags) ||
bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN)
| (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE)
@@ -1003,14 +1117,16 @@ smtp(nullserver, d_flags, e)
#if PIPELINING
| SRV_OFFER_PIPE
#endif
+ | SRV_BAD_PIPELINE
#if STARTTLS
| (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS)
| (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE
: SRV_VRFY_CLT)
#endif
#if USE_EAI
- | (SMTPUTF8 ? SRV_OFFER_EAI : 0)
+ | (SMTP_UTF8 ? SRV_OFFER_EAI : 0)
#endif
+ | SRV_REQ_CRLF | SRV_BARE_LF_421 | SRV_BARE_CR_421
;
if (nullserver == NULL)
{
@@ -1025,15 +1141,13 @@ smtp(nullserver, d_flags, e)
}
else
{
-#if PIPELINING
-# if _FFR_NO_PIPE
+#if PIPELINING && _FFR_NO_PIPE
if (bitset(SRV_NO_PIPE, features))
{
/* for consistency */
features &= ~SRV_OFFER_PIPE;
}
-# endif /* _FFR_NO_PIPE */
-#endif /* PIPELINING */
+#endif /* PIPELINING && _FFR_NO_PIPE */
#if SASL
if (bitset(SRV_REQ_SEC, features))
SASLOpts |= SASL_SEC_NOPLAINTEXT;
@@ -1046,7 +1160,8 @@ smtp(nullserver, d_flags, e)
{
/* Can't use ("%s", ...) due to message() requirements */
message(nullserver);
- goto doquit;
+ gotodoquit = true;
+ goto cmdloop;
}
e->e_features = features;
@@ -1248,7 +1363,8 @@ smtp(nullserver, d_flags, e)
/* arrange to ignore send list */
e->e_sendqueue = NULL;
lognullconnection = false;
- goto doquit;
+ gotodoquit = true;
+ goto cmdloop;
}
}
@@ -1313,7 +1429,8 @@ smtp(nullserver, d_flags, e)
/* arrange to ignore send list */
e->e_sendqueue = NULL;
- goto doquit;
+ gotodoquit = true;
+ goto cmdloop;
}
else
{
@@ -1366,7 +1483,8 @@ smtp(nullserver, d_flags, e)
/* arrange to ignore send list */
e->e_sendqueue = NULL;
- goto doquit;
+ gotodoquit = true;
+ goto cmdloop;
}
if (response != NULL)
sm_free(response);
@@ -1401,46 +1519,23 @@ smtp(nullserver, d_flags, e)
if (msecs > 0)
{
- int fd;
- fd_set readfds;
- struct timeval timeout;
- struct timeval bp, ep, tp; /* {begin,end,total}pause */
- int eoftest;
+ struct timeval *tp; /* total pause */
- /* pause for a moment */
- timeout.tv_sec = msecs / 1000;
- timeout.tv_usec = (msecs % 1000) * 1000;
-
- /* Obey RFC 2821: 4.3.5.2: 220 timeout of 5 minutes */
- if (timeout.tv_sec >= 300)
- {
- timeout.tv_sec = 300;
- timeout.tv_usec = 0;
- }
+ /* Obey RFC 2821: 4.5.3.2: 220 timeout of 5 minutes (300 seconds) */
+ if (msecs >= 300000)
+ msecs = 300000;
/* check if data is on the socket during the pause */
- fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
- FD_ZERO(&readfds);
- SM_FD_SET(fd, &readfds);
- gettimeofday(&bp, NULL);
- if (select(fd + 1, FDSET_CAST &readfds,
- NULL, NULL, &timeout) > 0 &&
- FD_ISSET(fd, &readfds) &&
- (eoftest = sm_io_getc(InChannel, SM_TIME_DEFAULT))
- != SM_IO_EOF)
- {
- sm_io_ungetc(InChannel, SM_TIME_DEFAULT,
- eoftest);
- gettimeofday(&ep, NULL);
- timersub(&ep, &bp, &tp);
+ if ((tp = channel_readable(InChannel, msecs)) != NULL)
+ {
greetcode = "554";
nullserver = "Command rejected";
sm_syslog(LOG_INFO, e->e_id,
"rejecting commands from %s [%s] due to pre-greeting traffic after %d seconds",
peerhostname,
anynet_ntoa(&RealHostAddr),
- (int) tp.tv_sec +
- (tp.tv_usec >= 500000 ? 1 : 0)
+ (int) tp->tv_sec +
+ (tp->tv_usec >= 500000 ? 1 : 0)
);
}
}
@@ -1460,7 +1555,8 @@ smtp(nullserver, d_flags, e)
first = true;
gothello = false;
smtp.sm_gotmail = false;
- goto starttls;
+ gotostarttls = true;
+ goto cmdloop;
}
greeting:
@@ -1522,6 +1618,8 @@ smtp(nullserver, d_flags, e)
smtp.sm_gotmail = false;
for (;;)
{
+
+ cmdloop:
SM_TRY
{
QuickAbort = false;
@@ -1540,6 +1638,19 @@ smtp(nullserver, d_flags, e)
FileName = NULL;
(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
+ if (gotodoquit)
+ {
+ gotodoquit = false;
+ goto doquit;
+ }
+#if STARTTLS
+ if (gotostarttls)
+ {
+ gotostarttls = false;
+ goto starttls;
+ }
+#endif
+
/* read the input line */
SmtpPhase = "server cmd read";
sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient);
@@ -1635,14 +1746,10 @@ smtp(nullserver, d_flags, e)
/* clean up end of line */
fixcrlf(inp, true);
-#if PIPELINING
-# if _FFR_NO_PIPE
+#if PIPELINING && _FFR_NO_PIPE
/*
** if there is more input and pipelining is disabled:
** delay ... (and maybe discard the input?)
- ** XXX this doesn't really work, at least in tests using
- ** telnet SM_IO_IS_READABLE only returns 1 if there were
- ** more than 2 input lines available.
*/
if (bitset(SRV_NO_PIPE, features) &&
@@ -1654,9 +1761,7 @@ smtp(nullserver, d_flags, e)
CurSmtpClient);
sleep(1);
}
-
-# endif /* _FFR_NO_PIPE */
-#endif /* PIPELINING */
+#endif /* PIPELINING && _FFR_NO_PIPE */
#if SASL
if (authenticating == SASL_PROC_AUTH)
@@ -2014,7 +2119,7 @@ smtp(nullserver, d_flags, e)
message("503 5.3.3 AUTH not available");
break;
}
- if (authenticating == SASL_IS_AUTH)
+ if (auth_active)
{
message("503 5.5.0 Already Authenticated");
break;
@@ -2249,11 +2354,15 @@ smtp(nullserver, d_flags, e)
tlslogerr(LOG_WARNING, 8, "server");
goto tls_done;
}
+# if DANE
+ tlsi_ctx.tlsi_dvc.dane_vrfy_dane_enabled = false;
+ tlsi_ctx.tlsi_dvc.dane_vrfy_chk = DANE_NEVER;
+# endif
if (get_tls_se_features(e, srv_ssl, &tlsi_ctx, true)
!= EX_OK)
{
/* do not offer too much info to client */
- message("454 4.3.3 TLS curently not available");
+ message("454 4.3.3 TLS currently not available");
SMTLSFAILED;
}
r = SSL_set_ex_data(srv_ssl, TLSsslidx, &tlsi_ctx);
@@ -2262,8 +2371,8 @@ smtp(nullserver, d_flags, e)
if (LogLevel > 5)
{
sm_syslog(LOG_ERR, NOQID,
- "STARTTLS=server, error: SSL_set_ex_data failed=%d",
- r);
+ "STARTTLS=server, error: SSL_set_ex_data failed=%d, TLSsslidx=%d",
+ r, TLSsslidx);
tlslogerr(LOG_WARNING, 9, "server");
}
SMTLSFAILED;
@@ -2469,6 +2578,30 @@ smtp(nullserver, d_flags, e)
STOP_IF_ATTACK(checksmtpattack(&n_helo, MAXHELOCOMMANDS,
true, "HELO/EHLO", e));
+ /*
+ ** Despite the fact that the name indicates this
+ ** a PIPELINE related feature, do not enclose
+ ** it in #if PIPELINING so we can protect SMTP
+ ** servers not compiled with PIPELINE support
+ ** from transaction stuffing.
+ */
+
+ /* check if data is on the socket before the EHLO reply */
+ if (bitset(SRV_BAD_PIPELINE, features) &&
+ sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0)
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "rejecting %s from %s [%s] due to traffic before response",
+ SmtpPhase, CurHostName,
+ anynet_ntoa(&RealHostAddr));
+ usrerr("554 5.5.0 SMTP protocol error");
+ nullserver = "Command rejected";
+#if MILTER
+ smtp.sm_milterize = false;
+#endif
+ break;
+ }
+
#if 0
/* RFC2821 4.1.4 allows duplicate HELO/EHLO */
/* check for duplicate HELO/EHLO per RFC 1651 4.2 */
@@ -2726,6 +2859,7 @@ smtp(nullserver, d_flags, e)
p = skipword(p, "from");
if (p == NULL)
break;
+ maps_reset_chged("server:MAIL");
if (tempfail)
{
if (LogLevel > 9)
@@ -2817,6 +2951,7 @@ smtp(nullserver, d_flags, e)
#if _FFR_8BITENVADDR
len = sizeof(iaddr) - (delimptr - iaddr);
(void) dequote_internal_chars(delimptr, delimptr, len);
+ sep_args(delimptr, origp, e->e_id, p);
#endif
}
if (Errors > 0)
@@ -2862,7 +2997,7 @@ smtp(nullserver, d_flags, e)
}
/* reset to default value */
- SevenBitInput = SevenBitInput_Saved;
+ e->e_flags &= ~EF_7BITBODY;
/* now parse ESMTP arguments */
e->e_msgsize = 0;
@@ -3154,6 +3289,7 @@ smtp(nullserver, d_flags, e)
#if _FFR_8BITENVADDR
len = sizeof(iaddr) - (delimptr - iaddr);
(void) dequote_internal_chars(delimptr, delimptr, len);
+ sep_args(delimptr, origp, e->e_id, p);
#endif
}
@@ -3381,7 +3517,8 @@ smtp(nullserver, d_flags, e)
case CMDDATA: /* data -- text of mail */
DELAY_CONN("DATA");
- if (!smtp_data(&smtp, e))
+ if (!smtp_data(&smtp, e,
+ bitset(SRV_BAD_PIPELINE, features)))
goto doquit;
break;
@@ -3663,7 +3800,7 @@ smtp(nullserver, d_flags, e)
}
#endif /* STARTTLS */
#if SASL
- if (authenticating == SASL_IS_AUTH)
+ if (auth_active)
{
sasl_dispose(&conn);
authenticating = SASL_NOT_AUTH;
@@ -3671,7 +3808,7 @@ smtp(nullserver, d_flags, e)
}
#endif /* SASL */
-doquit:
+ doquit:
/* avoid future 050 messages */
disconnect(1, e);
@@ -3861,6 +3998,7 @@ doquit:
** Parameters:
** smtp -- status of SMTP connection.
** e -- envelope.
+** check_stuffing -- check for transaction stuffing.
**
** Returns:
** true iff SMTP session can continue.
@@ -3870,9 +4008,10 @@ doquit:
*/
static bool
-smtp_data(smtp, e)
+smtp_data(smtp, e, check_stuffing)
SMTP_T *smtp;
ENVELOPE *e;
+ bool check_stuffing;
{
#if MILTER
bool milteraccept;
@@ -3884,7 +4023,7 @@ smtp_data(smtp, e)
ENVELOPE *ee;
char *id;
char *oldid;
- unsigned int features;
+ unsigned long features;
char buf[32];
SmtpPhase = "server DATA";
@@ -3898,6 +4037,18 @@ smtp_data(smtp, e)
usrerr("503 5.0.0 Need RCPT (recipient)");
return true;
}
+
+ /* check if data is on the socket before the DATA reply */
+ if (check_stuffing &&
+ sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0)
+ {
+ sm_syslog(LOG_INFO, e->e_id,
+ "rejecting %s from %s [%s] due to traffic before response",
+ SmtpPhase, CurHostName, anynet_ntoa(&RealHostAddr));
+ usrerr("554 5.5.0 SMTP protocol error");
+ return false;
+ }
+
(void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts);
if (rscheck("check_data", buf, NULL, e,
RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL,
@@ -4018,7 +4169,13 @@ smtp_data(smtp, e)
SmtpPhase = "collect";
buffer_errors();
- collect(InChannel, true, NULL, e, true);
+ collect(InChannel, SMTPMODE_LAX
+ | (bitset(SRV_BARE_LF_421, e->e_features) ? SMTPMODE_LF_421 : 0)
+ | (bitset(SRV_BARE_CR_421, e->e_features) ? SMTPMODE_CR_421 : 0)
+ | (bitset(SRV_BARE_LF_SP, e->e_features) ? SMTPMODE_LF_SP : 0)
+ | (bitset(SRV_BARE_CR_SP, e->e_features) ? SMTPMODE_CR_SP : 0)
+ | (bitset(SRV_REQ_CRLF, e->e_features) ? SMTPMODE_CRLF : 0),
+ NULL, e, true);
/* redefine message size */
(void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize));
@@ -4810,7 +4967,7 @@ skipword(p, w)
}
/*
-** RESET_MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
+** RESET_MAIL_ESMTP_ARGS -- reset ESMTP arguments for MAIL
**
** Parameters:
** e -- the envelope.
@@ -4826,7 +4983,7 @@ reset_mail_esmtp_args(e)
/* "size": no reset */
/* "body" */
- SevenBitInput = SevenBitInput_Saved;
+ e->e_flags &= ~EF_7BITBODY;
e->e_bodytype = NULL;
/* "envid" */
@@ -4901,13 +5058,9 @@ mail_esmtp_args(a, kp, vp, e)
/* NOTREACHED */
}
else if (SM_STRCASEEQ(vp, "8bitmime"))
- {
- SevenBitInput = false;
- }
+ ;
else if (SM_STRCASEEQ(vp, "7bit"))
- {
- SevenBitInput = true;
- }
+ e->e_flags |= EF_7BITBODY;
else
{
usrerr("501 5.5.4 Unknown BODY type %s",
@@ -5504,39 +5657,50 @@ initsrvtls(tls_ok)
static struct
{
char srvf_opt;
- unsigned int srvf_flag;
+ unsigned long srvf_flag;
+ unsigned long srvf_flag2;
} srv_feat_table[] =
{
- { 'A', SRV_OFFER_AUTH },
- { 'B', SRV_OFFER_VERB },
- { 'C', SRV_REQ_SEC },
- { 'D', SRV_OFFER_DSN },
- { 'E', SRV_OFFER_ETRN },
- { 'H', SRV_NO_HTTP_CMD },
+ { 'A', SRV_OFFER_AUTH , 0 },
+ { 'B', SRV_OFFER_VERB , 0 },
+ { 'C', SRV_REQ_SEC , 0 },
+ { 'D', SRV_OFFER_DSN , 0 },
+ { 'E', SRV_OFFER_ETRN , 0 },
+ { 'F', SRV_BAD_PIPELINE , 0 },
+ { 'G', SRV_BARE_LF_421 , SRV_BARE_LF_SP },
+ { 'H', SRV_NO_HTTP_CMD , 0 },
#if USE_EAI
- { 'I', SRV_OFFER_EAI },
+ { 'I', SRV_OFFER_EAI , 0 },
+#endif
+/* { 'J', 0 , 0 }, */
+/* { 'K', 0 , 0 }, */
+ { 'L', SRV_REQ_AUTH , 0 },
+/* { 'M', 0 , 0 }, */
+#if PIPELINING && _FFR_NO_PIPE
+ { 'N', SRV_NO_PIPE , 0 },
#endif
- { 'L', SRV_REQ_AUTH },
+ { 'O', SRV_REQ_CRLF , 0 }, /* eOl */
#if PIPELINING
-# if _FFR_NO_PIPE
- { 'N', SRV_NO_PIPE },
-# endif
- { 'P', SRV_OFFER_PIPE },
-#endif /* PIPELINING */
- { 'R', SRV_VRFY_CLT }, /* same as V; not documented */
- { 'S', SRV_OFFER_TLS },
-/* { 'T', SRV_TMP_FAIL }, */
- { 'V', SRV_VRFY_CLT },
- { 'X', SRV_OFFER_EXPN },
-/* { 'Y', SRV_OFFER_VRFY }, */
- { '\0', SRV_NONE }
+ { 'P', SRV_OFFER_PIPE , 0 },
+#endif
+/* { 'Q', 0 , 0 }, */
+ { 'R', SRV_VRFY_CLT , 0 }, /* same as V; not documented */
+ { 'S', SRV_OFFER_TLS , 0 },
+/* { 'T', SRV_TMP_FAIL , 0 }, */
+ { 'U', SRV_BARE_CR_421 , SRV_BARE_CR_SP },
+ { 'V', SRV_VRFY_CLT , 0 },
+/* { 'W', 0 , 0 }, */
+ { 'X', SRV_OFFER_EXPN , 0 },
+/* { 'Y', SRV_OFFER_VRFY , 0 }, */
+/* { 'Z', 0 , 0 }, */
+ { '\0', SRV_NONE , 0 }
};
-static unsigned int
+static unsigned long
srvfeatures(e, clientname, features)
ENVELOPE *e;
char *clientname;
- unsigned int features;
+ unsigned long features;
{
int r, i, j;
char **pvp, c, opt;
@@ -5570,7 +5734,7 @@ srvfeatures(e, clientname, features)
{
if (LogLevel > 9)
sm_syslog(LOG_WARNING, e->e_id,
- "srvfeatures: unknown feature %s",
+ "srv_features: unknown feature %s",
pvp[i]);
break;
}
@@ -5579,9 +5743,40 @@ srvfeatures(e, clientname, features)
features &= ~(srv_feat_table[j].srvf_flag);
break;
}
+
+ /*
+ ** Note: the "noflag" code below works ONLY for
+ ** the current situation:
+ ** - _flag itself is set by default
+ ** (drop session if bare CR or LF is found)
+ ** - _flag2 is only "effective" if _flag is not set,
+ ** hence using it turns off _flag.
+ ** If that situation changes, the code must be changed!
+ */
+
if (c == tolower(opt))
{
- features |= srv_feat_table[j].srvf_flag;
+ unsigned long flag, noflag;
+
+ c = pvp[i][1];
+ flag = noflag = 0;
+ if ('2' == c)
+ {
+ flag = srv_feat_table[j].srvf_flag2;
+ noflag = srv_feat_table[j].srvf_flag;
+ }
+ else if ('\0' == c)
+ flag = srv_feat_table[j].srvf_flag;
+ if (0 != flag)
+ {
+ features |= flag;
+ if (0 != noflag)
+ features &= ~noflag;
+ }
+ else if (LogLevel > 9)
+ sm_syslog(LOG_WARNING, e->e_id,
+ "srv_features: unknown variant %s",
+ pvp[i]);
break;
}
++j;
@@ -5748,7 +5943,7 @@ reset_saslconn(sasl_conn_t **conn, char *hostname,
sasl_external_properties_t * ext_ssf)
# endif /* SASL >= 20000 */
#else /* __STDC__ */
-# ERROR "SASL requires __STDC__"
+# error "SASL requires __STDC__"
#endif /* __STDC__ */
{
int result;
diff --git a/contrib/sendmail/src/stab.c b/contrib/sendmail/src/stab.c
index 3fe1c7d60a00..bcdc7b4b7246 100644
--- a/contrib/sendmail/src/stab.c
+++ b/contrib/sendmail/src/stab.c
@@ -204,6 +204,12 @@ stab(name, type, op)
break;
#endif
+#if _FFR_DYN_CLASS
+ case ST_DYNMAP:
+ len = sizeof(s->s_dynclass);
+ break;
+#endif
+
default:
/*
** Each mailer has its own MCI stab entry:
diff --git a/contrib/sendmail/src/tls.c b/contrib/sendmail/src/tls.c
index e2cac7632288..5c11e3d202f1 100644
--- a/contrib/sendmail/src/tls.c
+++ b/contrib/sendmail/src/tls.c
@@ -26,19 +26,23 @@ SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $")
# include <tls.h>
# if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER <= 0x00907000L
-# ERROR "OpenSSL version OPENSSL_VERSION_NUMBER is unsupported."
+# error "OpenSSL versions <= 0x00907000L are unsupported."
+# endif
+
+# if DANE && OPENSSL_VERSION_NUMBER == 0x30200000L
+# error OpenSSL 3.2.0 has a bug related to DANE
+# error see https://github.com/openssl/openssl/pull/22821
# endif
/*
** *SSL version numbers:
-** OpenSSL 0.9 - 1.1 (so far), 3.0 (in alpha)
+** OpenSSL 0.9 - 1.1 (so far), 3.[012]
** LibreSSL 2.0 (0x20000000L - part of "These will never change")
*/
-# if (OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L) || OPENSSL_VERSION_NUMBER >= 0x30000000L
+# if (OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L) || OPENSSL_VERSION_NUMBER >= 0x30000000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
# define MTA_HAVE_DH_set0_pqg 1
# define MTA_HAVE_DSA_GENERATE_EX 1
-
# define MTA_HAVE_OPENSSL_init_ssl 1
# define MTA_ASN1_STRING_data ASN1_STRING_get0_data
# include <openssl/bn.h>
@@ -49,6 +53,27 @@ SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $")
# define MTA_ASN1_STRING_data ASN1_STRING_data
# endif
+/* Is this ok or use HAVE_SSL_get1_peer_certificate instead? */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# define MTA_SSL_get_peer_certificate SSL_get1_peer_certificate
+
+# ifndef HAVE_ERR_get_error_all
+# define HAVE_ERR_get_error_all 1
+# endif
+
+/* use SSL_CTX_set_dh_auto()? which versions provide it? */
+# define MTA_DH_AUTO 1
+#else
+# define MTA_SSL_get_peer_certificate SSL_get_peer_certificate
+# define MTA_DH_AUTO 0
+#endif
+
+#if HAVE_ERR_get_error_all
+# define MTA_SSL_ERR_get(f, l, d, fl, fct) ERR_get_error_all(f, l, fct, d, fl)
+#else /* if HAVE_ERR_get_error_line_data ? */
+# define MTA_SSL_ERR_get(f, l, d, fl, fct) ERR_get_error_line_data(f, l, d, fl)
+#endif
+
# if !TLS_NO_RSA && MTA_RSA_TMP_CB
static RSA *rsa_tmp = NULL; /* temporary RSA key */
static RSA *tmp_rsa_key __P((SSL *, int, int));
@@ -57,7 +82,7 @@ static int tls_verify_cb __P((X509_STORE_CTX *, void *));
static int x509_verify_cb __P((int, X509_STORE_CTX *));
-static void apps_ssl_info_cb __P((const SSL *, int , int));
+static void apps_ssl_info_cb __P((const SSL *, int, int));
static bool tls_ok_f __P((char *, char *, int));
static bool tls_safe_f __P((char *, long, bool));
static int tls_verify_log __P((int, X509_STORE_CTX *, const char *));
@@ -184,7 +209,6 @@ get_dh2048()
}
# endif /* !NO_DH */
-
/*
** TLS_RAND_INIT -- initialize STARTTLS random generator
**
@@ -373,8 +397,9 @@ tls_rand_init(randfile, logl)
return true;
# endif /* ! HASURANDOMDEV */
}
+
/*
-** INIT_TLS_LIBRARY -- Calls functions which setup TLS library for global use.
+** INIT_TLS_LIBRARY -- Calls functions which set up TLS library for global use.
**
** Parameters:
** fipsmode -- use FIPS?
@@ -391,6 +416,17 @@ init_tls_library(fipsmode)
{
bool bv;
+# if _FFR_FIPSMODE
+ if (fipsmode && CertFingerprintAlgorithm == NULL)
+ CertFingerprintAlgorithm = "sha1";
+# if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (LogLevel > 12)
+ sm_syslog(LOG_DEBUG, NOQID,
+ "fipsmode=%d, evp_is_FIPS=%d", fipsmode,
+ EVP_default_properties_is_fips_enabled(NULL));
+# endif
+# endif /* _FFR_FIPSMODE */
+
/*
** OPENSSL_init_ssl(3): "As of version 1.1.0 OpenSSL will
** automatically allocate all resources that it needs
@@ -420,7 +456,7 @@ init_tls_library(fipsmode)
if (bv)
bv = tls_rand_init(RandFile, 7);
-# if _FFR_FIPSMODE
+# if _FFR_FIPSMODE && OPENSSL_VERSION_NUMBER < 0x30000000L
if (bv && fipsmode)
{
if (!FIPS_mode_set(1))
@@ -434,16 +470,13 @@ init_tls_library(fipsmode)
ERR_error_string(err, NULL));
return -1;
}
- else
+ else if (LogLevel > 9)
{
- if (LogLevel > 9)
- sm_syslog(LOG_INFO, NOQID,
- "STARTTLS=init, FIPSMode=ok");
+ sm_syslog(LOG_INFO, NOQID,
+ "STARTTLS=init, FIPSMode=ok");
}
- if (CertFingerprintAlgorithm == NULL)
- CertFingerprintAlgorithm = "sha1";
}
-# endif /* _FFR_FIPSMODE */
+# endif /* _FFR_FIPSMODE && OPENSSL_VERSION_NUMBER < 0x30000000L */
if (!TLS_set_engine(SSLEngine, true))
{
@@ -704,7 +737,9 @@ load_certkey(ssl, srv, certfile, keyfile)
/* certfile etc. must be "safe". */
sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK
| SFF_NOGWFILES | SFF_NOWWFILES
- | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
+ | SFF_ROOTOK | SFF_OPENASROOT;
+ if (!bitnset(DBS_CERTOWNER, DontBlameSendmail))
+ sff |= SFF_MUSTOWN;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
@@ -1035,11 +1070,19 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
** /file/name read parameters from /file/name
*/
-# define SET_DH_DFL \
+# if MTA_DH_AUTO
+# define SET_DH_DFL \
+ do { \
+ dhparam = "a"; \
+ req |= TLS_I_DHAUTO; \
+ } while (0)
+# else
+# define SET_DH_DFL \
do { \
dhparam = "I"; \
req |= TLS_I_DHFIXED; \
} while (0)
+# endif
if (bitset(TLS_I_TRY_DH, req))
{
@@ -1047,6 +1090,11 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
{
char c = *dhparam;
+# if MTA_DH_AUTO
+ if (c == 'a')
+ req |= TLS_I_DHAUTO;
+ else
+# endif
if (c == '1')
req |= TLS_I_DH1024;
else if (c == 'I' || c == 'i')
@@ -1081,7 +1129,9 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
/* certfile etc. must be "safe". */
sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK
| SFF_NOGWFILES | SFF_NOWWFILES
- | SFF_MUSTOWN | SFF_ROOTOK | SFF_OPENASROOT;
+ | SFF_ROOTOK | SFF_OPENASROOT;
+ if (!bitnset(DBS_CERTOWNER, DontBlameSendmail))
+ sff |= SFF_MUSTOWN;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
@@ -1165,7 +1215,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
/* hack for testing! */
if (tTd(96, 101) || getenv("SSL_MODE_AUTO_RETRY") != NULL)
- SSL_CTX_set_mode(*ctx, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_mode(*ctx, SSL_MODE_AUTO_RETRY);
else
# endif /* _FFR_TESTS */
/* "else" in #if code above */
@@ -1342,8 +1392,8 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
EC_KEY *ecdh;
# endif
- if (tTd(96, 8))
- sm_dprintf("inittls: req=%#lx, status=%#lx\n",
+ if (tTd(96, 81))
+ sm_dprintf("inittls: where=try_dh, req=%#lx, status=%#lx\n",
req, status);
if (bitset(TLS_S_DHPAR_OK, status))
{
@@ -1377,6 +1427,11 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
}
}
}
+# if MTA_DH_AUTO
+ if (dh == NULL && bitset(TLS_I_DHAUTO, req))
+ SSL_CTX_set_dh_auto(*ctx, 1);
+ else
+# endif
if (dh == NULL && bitset(TLS_I_DH1024|TLS_I_DH2048, req))
{
int bits;
@@ -1415,8 +1470,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
sm_dprintf("inittls: Using precomputed 512 bit DH parameters\n");
dh = get_dh512();
}
-
- if (dh == NULL)
+ if (dh == NULL && !bitset(TLS_I_DHAUTO, req))
{
if (LogLevel > 9)
{
@@ -1431,7 +1485,7 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
if (bitset(TLS_I_REQ_DH, req))
return false;
}
- else
+ else if (dh != NULL)
{
/* important to avoid small subgroup attacks */
SSL_CTX_set_options(*ctx, SSL_OP_SINGLE_DH_USE);
@@ -1466,7 +1520,6 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
}
# endif /* !NO_DH */
-
/* XXX do we need this cache here? */
if (bitset(TLS_I_CACHE, req))
{
@@ -1495,33 +1548,11 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
SSL_CTX_set_tmp_rsa_callback(*ctx, tmp_rsa_key);
# endif
- /*
- ** We have to install our own verify callback:
- ** SSL_VERIFY_PEER requests a client cert but even
- ** though *FAIL_IF* isn't set, the connection
- ** will be aborted if the client presents a cert
- ** that is not "liked" (can't be verified?) by
- ** the TLS library :-(
- */
-
- /*
- ** XXX currently we could call tls_set_verify()
- ** but we hope that that function will later on
- ** only set the mode per connection.
- */
-
- SSL_CTX_set_verify(*ctx,
- bitset(TLS_I_NO_VRFY, req) ? SSL_VERIFY_NONE
- : SSL_VERIFY_PEER,
- NULL);
-
if (srv)
{
SSL_CTX_set_client_CA_list(*ctx,
SSL_load_client_CA_file(cacertfile));
}
- SSL_CTX_set_cert_verify_callback(*ctx, tls_verify_cb,
- NULL);
}
else
{
@@ -1546,6 +1577,29 @@ inittls(ctx, req, options, srv, certfile, keyfile, cacertpath, cacertfile, dhpar
}
}
+ /*
+ ** XXX currently we could call tls_set_verify()
+ ** but we hope that that function will later on
+ ** only set the mode per connection.
+ */
+
+ SSL_CTX_set_verify(*ctx,
+ bitset(TLS_I_NO_VRFY, req) ? SSL_VERIFY_NONE
+ : SSL_VERIFY_PEER,
+ NULL);
+
+ /*
+ ** Always use our callback instead of the builtin version.
+ ** We have to install our own verify callback:
+ ** SSL_VERIFY_PEER requests a client cert but even
+ ** though *FAIL_IF* isn't set, the connection
+ ** will be aborted if the client presents a cert
+ ** that is not "liked" (can't be verified?) by
+ ** the TLS library :-(
+ */
+
+ SSL_CTX_set_cert_verify_callback(*ctx, tls_verify_cb, NULL);
+
/* XXX: make this dependent on an option? */
if (tTd(96, 9))
SSL_CTX_set_info_callback(*ctx, apps_ssl_info_cb);
@@ -1635,10 +1689,10 @@ cert_fp(cert, evp_digest, mac, macro)
static const char hexcodes[] = "0123456789ABCDEF";
n = 0;
- if (X509_digest(cert, EVP_digest, md, &n) == 0 || n <= 0)
+ if ((r = X509_digest(cert, evp_digest, md, &n)) == 0 || n <= 0)
{
macdefine(mac, A_TEMP, macid(macro), "");
- return 0;
+ return (0 == r) ? 0 : n;
}
SM_ASSERT((n * 3) + 2 < sizeof(md5h));
@@ -1758,6 +1812,110 @@ getaltnames(cert, srv, host)
# define getaltnames(cert, srv, host)
# endif /* _FFR_TLS_ALTNAMES */
+# if DANE
+
+/*
+** DANE_RES -- get DANE result if possible
+**
+** Parameters:
+** ssl -- TLS connection structure
+** dane_vrfy_ctx -- dane verify context
+**
+** Returns:
+** SM_SUCCESS: DANE result dane_vrfy_res is valid
+** SM_NOTDONE: DANE checking not enabled
+** <0: some error
+*/
+
+static int dane_res __P((SSL *, dane_vrfy_ctx_P));
+
+static int
+dane_res(ssl, dane_vrfy_ctx)
+ SSL *ssl;
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+{
+# if HAVE_SSL_CTX_dane_enable
+ int depth, r;
+ EVP_PKEY *mspki;
+ uint8_t usage, selector, mtype;
+ unsigned const char *rr;
+ size_t rrlen;
+# endif
+
+ if (NULL == dane_vrfy_ctx)
+ {
+ /* can this happen? should it be logged? */
+ if (tTd(96, 20))
+ sm_dprintf("ERROR: dane_res: dane_vrfy_ctx=NULL\n");
+ return SM_NOTDONE;
+ }
+ if (tTd(96, 20))
+ sm_dprintf("dane_res: dane_vrfy_dane_enabled=%d, chk=%#x, res=%d\n",
+ dane_vrfy_ctx->dane_vrfy_dane_enabled,
+ dane_vrfy_ctx->dane_vrfy_chk,
+ dane_vrfy_ctx->dane_vrfy_res);
+ if (!VRFY_DANE(dane_vrfy_ctx->dane_vrfy_chk))
+ {
+ dane_vrfy_ctx->dane_vrfy_res = DANE_VRFY_NONE;
+ return SM_NOTDONE;
+ }
+ if (dane_vrfy_ctx->dane_vrfy_chk & TLSAFLTEMPVRFY)
+ {
+ dane_vrfy_ctx->dane_vrfy_res = DANE_VRFY_TEMP;
+ return SM_SUCCESS;
+ }
+ if (!dane_vrfy_ctx->dane_vrfy_dane_enabled)
+ {
+ if (DANE_VRFY_NONE == dane_vrfy_ctx->dane_vrfy_res)
+ return SM_NOTDONE;
+ return SM_SUCCESS;
+ }
+
+# if HAVE_SSL_CTX_dane_enable
+ mspki = NULL;
+ depth = SSL_get0_dane_authority(ssl, NULL, &mspki);
+ if (tTd(96, 20))
+ sm_dprintf("dane_res: SSL_get0_dane_authority() depth=%d\n", depth);
+
+ if (depth < 0)
+ {
+ dane_vrfy_ctx->dane_vrfy_res = DANE_VRFY_FAIL;
+ return SM_SUCCESS;
+ }
+
+ dane_vrfy_ctx->dane_vrfy_res = DANE_VRFY_OK;
+ r = SSL_get0_dane_tlsa(ssl, &usage, &selector, &mtype, &rr, &rrlen);
+ if (tTd(96, 20))
+ sm_dprintf("dane_res: SSL_get0_dane_tlsa=%d, status=%s\n", r,
+ (mspki != NULL) ? "TA_public_key_verified_certificate"
+ : (depth > 0) ? "matched_TA_certificate"
+ : "matched_EE_certificate");
+
+ if (LogLevel > 11)
+ {
+ /* just for logging */
+ if (r >= 0 && rr != NULL && rrlen > 0)
+ {
+ (void) data2hex((unsigned char *)rr, rrlen,
+ (unsigned char *)dane_vrfy_ctx->dane_vrfy_fp,
+ sizeof(dane_vrfy_ctx->dane_vrfy_fp));
+ }
+
+ sm_syslog(LOG_DEBUG, NOQID,
+ "DANE_depth=%d, DANE_res=%d, SSL_get0_dane_tlsa=%d, fp=%s, status=%s",
+ depth, dane_vrfy_ctx->dane_vrfy_res, r,
+ dane_vrfy_ctx->dane_vrfy_fp,
+ (mspki != NULL) ? "TA_public_key_verified_certificate" :
+ (depth > 0) ? "matched_TA_certificate" : "matched_EE_certificate"
+ );
+ }
+# else
+ SM_ASSERT(!dane_vrfy_ctx->dane_vrfy_dane_enabled);
+# endif /* HAVE_SSL_CTX_dane_enable */
+ return SM_SUCCESS;
+}
+# endif /* DANE */
+
/*
** TLS_GET_INFO -- get information about TLS connection
**
@@ -1791,6 +1949,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
X509 *cert;
# if DANE
dane_vrfy_ctx_P dane_vrfy_ctx;
+ dane_tlsa_P dane_tlsa;
# endif
c = SSL_get_current_cipher(ssl);
@@ -1809,7 +1968,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
macdefine(mac, A_TEMP, macid("{tls_version}"), s);
who = srv ? "server" : "client";
- cert = SSL_get_peer_certificate(ssl);
+ cert = MTA_SSL_get_peer_certificate(ssl);
verifyok = SSL_get_verify_result(ssl);
if (LogLevel > 14)
sm_syslog(LOG_INFO, NOQID,
@@ -1875,7 +2034,16 @@ tls_get_info(ssl, srv, host, mac, certreq)
CHECK_X509_NAME("cn_issuer");
macdefine(mac, A_TEMP, macid("{cn_issuer}"),
xtextify(buf, "<>\")"));
- (void) cert_fp(cert, EVP_digest, mac, CERTFPMACRO);
+ r = cert_fp(cert, EVP_digest, mac, CERTFPMACRO);
+ if (r <= 0 && LogLevel > 8)
+ {
+ sm_syslog(LOG_WARNING, NOQID,
+ "STARTTLS=%s, relay=%.100s, X509_digest=%d, CertFingerprintAlgorithm=%s",
+ who, whichhost, r,
+ (NULL == CertFingerprintAlgorithm) ? "md5" :
+ CertFingerprintAlgorithm);
+ tlslogerr(LOG_WARNING, 8, who);
+ }
getaltnames(cert, srv, host);
}
else
@@ -1888,25 +2056,56 @@ tls_get_info(ssl, srv, host, mac, certreq)
}
# if DANE
dane_vrfy_ctx = NULL;
+ dane_tlsa = NULL;
if (TLSsslidx >= 0)
{
tlsi_ctx_T *tlsi_ctx;
tlsi_ctx = (tlsi_ctx_P) SSL_get_ex_data(ssl, TLSsslidx);
if (tlsi_ctx != NULL)
+ {
dane_vrfy_ctx = &(tlsi_ctx->tlsi_dvc);
+ dane_tlsa = dane_get_tlsa(dane_vrfy_ctx);
+ }
}
+
# define DANE_VRFY_RES_IS(r) \
((dane_vrfy_ctx != NULL) && dane_vrfy_ctx->dane_vrfy_res == (r))
- if (DANE_VRFY_RES_IS(DANE_VRFY_OK))
- {
- s = "TRUSTED";
- r = TLS_AUTH_OK;
- }
- else if (DANE_VRFY_RES_IS(DANE_VRFY_FAIL))
+
+ if (tTd(96, 10))
+ sm_dprintf("tls_get_info: verifyok=%d, dane_vrfy_res=%d\n",
+ (int)verifyok,
+ (dane_vrfy_ctx != NULL) ? dane_vrfy_ctx->dane_vrfy_res : -999);
+ if (SM_SUCCESS == dane_res(ssl, dane_vrfy_ctx))
{
- s = "DANE_FAIL";
- r = TLS_AUTH_FAIL;
+ if (DANE_VRFY_RES_IS(DANE_VRFY_OK))
+ {
+ s = "TRUSTED";
+ r = TLS_AUTH_OK;
+ }
+ else if (DANE_VRFY_RES_IS(DANE_VRFY_TEMP))
+ {
+ s = "DANE_TEMP";
+ r = TLS_AUTH_TEMP;
+ }
+ else if (DANE_VRFY_RES_IS(DANE_VRFY_FAIL))
+ {
+ if (dane_tlsa != NULL &&
+ TLSA_IS_FL(dane_tlsa, TLSAFL2MANY))
+ {
+ s = "DANE_TEMP";
+ r = TLS_AUTH_TEMP;
+ }
+ else
+ {
+ s = "DANE_FAIL";
+ r = TLS_AUTH_FAIL;
+ }
+ }
+ else {
+ s = "BOGUS_DANE_RES";
+ r = TLS_AUTH_FAIL;
+ }
}
else
# endif /* if DANE */
@@ -1925,6 +2124,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
r = TLS_AUTH_NO;
}
break;
+
default:
s = "FAIL";
r = TLS_AUTH_FAIL;
@@ -1942,6 +2142,8 @@ tls_get_info(ssl, srv, host, mac, certreq)
vers = macget(mac, macid("{tls_version}"));
cbits = macget(mac, macid("{cipher_bits}"));
algbits = macget(mac, macid("{alg_bits}"));
+
+ /* XXX: use s directly? */
s1 = macget(mac, macid("{verify}"));
s2 = macget(mac, macid("{cipher}"));
@@ -1951,7 +2153,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
# endif
/* XXX: maybe cut off ident info? */
sm_syslog(LOG_INFO, NOQID,
- "STARTTLS=%s, relay=%.100s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s/%.6s%s%s",
+ "STARTTLS=%s, relay=%.100s, version=%.16s, verify=%.16s, cipher=%.64s, bits=%.6s/%.6s%s%s%s%s",
who,
host == NULL ? "local" : host,
vers, s1, s2, /* sm_snprintf() can deal with NULL */
@@ -1960,8 +2162,17 @@ tls_get_info(ssl, srv, host, mac, certreq)
# if DANE
, LOG_DANE_FP ? ", pubkey_fp=" : ""
, LOG_DANE_FP ? dane_vrfy_ctx->dane_vrfy_fp : ""
+ , (dane_tlsa != NULL
+ && TLSA_IS_FL(dane_tlsa, TLSAFLUNS)
+ && !TLSA_IS_FL(dane_tlsa, TLSAFLSUP)
+ && DANE_VRFY_RES_IS(DANE_VRFY_NONE))
+ ? ONLYUNSUPTLSARR : ""
+ , (dane_tlsa != NULL
+ && TLSA_IS_FL(dane_tlsa, TLSAFL2MANY))
+ && DANE_VRFY_RES_IS(DANE_VRFY_FAIL)
+ ? ", note=too many TLSA RRs" : ""
# else
- , "", ""
+ , "", "", "", ""
# endif
);
if (LogLevel > 11)
@@ -1985,7 +2196,7 @@ tls_get_info(ssl, srv, host, mac, certreq)
}
/*
-** ENDTLS -- shutdown secure connection
+** ENDTLS -- shut down secure connection
**
** Parameters:
** pssl -- pointer to TLS session context
@@ -2245,7 +2456,6 @@ tls_verify_log(ok, ctx, name)
/*
** Declaration and access to tlsi_ctx in callbacks.
-** Currently only used in one of them.
*/
#define SM_DECTLSI \
@@ -2264,14 +2474,13 @@ tls_verify_log(ok, ctx, name)
} \
while (0)
-
# if DANE
/*
** DANE_GET_TLSA -- Retrieve TLSA RR for DANE
**
** Parameters:
-** dane -- dane verify context
+** dane_vrfy_ctx -- dane verify context
**
** Returns:
** dane_tlsa if TLSA RR is available
@@ -2288,28 +2497,28 @@ dane_get_tlsa(dane_vrfy_ctx)
dane_tlsa = NULL;
if (NULL == dane_vrfy_ctx)
return NULL;
- if (dane_vrfy_ctx->dane_vrfy_chk == DANE_NEVER ||
+ if (!CHK_DANE(dane_vrfy_ctx->dane_vrfy_chk) ||
dane_vrfy_ctx->dane_vrfy_host == NULL)
return NULL;
- GETTLSANOX(dane_vrfy_ctx->dane_vrfy_host, &s,
- dane_vrfy_ctx->dane_vrfy_port);
+ gettlsa(dane_vrfy_ctx->dane_vrfy_host, NULL, &s,
+ TLSAFLNOEXP, 0, dane_vrfy_ctx->dane_vrfy_port);
if (NULL == s)
goto notfound;
dane_tlsa = s->s_tlsa;
if (NULL == dane_tlsa)
goto notfound;
- if (0 == dane_tlsa->dane_tlsa_n)
+ if (!TLSA_HAS_RRs(dane_tlsa))
goto notfound;
if (tTd(96, 4))
- sm_dprintf("dane_get_tlsa, chk=%d, host=%s, n=%d, stat=entry found\n",
+ sm_dprintf("dane_get_tlsa: chk=%#x, host=%s, n=%d, stat=entry found\n",
dane_vrfy_ctx->dane_vrfy_chk,
dane_vrfy_ctx->dane_vrfy_host, dane_tlsa->dane_tlsa_n);
return dane_tlsa;
notfound:
if (tTd(96, 4))
- sm_dprintf("dane_get_tlsa, chk=%d, host=%s, stat=no valid entry found\n",
+ sm_dprintf("dane_get_tlsa: chk=%#x, host=%s, stat=no valid entry found\n",
dane_vrfy_ctx->dane_vrfy_chk,
dane_vrfy_ctx->dane_vrfy_host);
return NULL;
@@ -2337,7 +2546,7 @@ dane_verify(ctx, dane_vrfy_ctx)
int r, i, ok, mdalg;
X509 *cert;
dane_tlsa_P dane_tlsa;
- char *fp;
+ unsigned char *fp;
dane_tlsa = dane_get_tlsa(dane_vrfy_ctx);
if (dane_tlsa == NULL)
@@ -2346,7 +2555,8 @@ dane_verify(ctx, dane_vrfy_ctx)
dane_vrfy_ctx->dane_vrfy_fp[0] = '\0';
cert = X509_STORE_CTX_get0_cert(ctx);
if (tTd(96, 8))
- sm_dprintf("dane_verify, cert=%p\n", (void *)cert);
+ sm_dprintf("dane_verify: cert=%p, supported=%d\n",
+ (void *)cert, TLSA_IS_FL(dane_tlsa, TLSAFLSUP));
if (cert == NULL)
return DANE_VRFY_FAIL;
@@ -2366,7 +2576,7 @@ dane_verify(ctx, dane_vrfy_ctx)
r = 0;
for (i = 0; i < dane_tlsa->dane_tlsa_n; i++)
{
- char *p;
+ unsigned char *p;
int alg;
p = dane_tlsa->dane_tlsa_rr[i];
@@ -2375,7 +2585,7 @@ dane_verify(ctx, dane_vrfy_ctx)
alg = dane_tlsa_chk(p, dane_tlsa->dane_tlsa_len[i],
dane_vrfy_ctx->dane_vrfy_host, false);
if (tTd(96, 8))
- sm_dprintf("dane_verify, alg=%d, mdalg=%d\n",
+ sm_dprintf("dane_verify: alg=%d, mdalg=%d\n",
alg, mdalg);
if (alg != mdalg)
continue;
@@ -2397,7 +2607,7 @@ dane_verify(ctx, dane_vrfy_ctx)
}
if (tTd(96, 4))
- sm_dprintf("dane_verify, alg=%d, r=%d, len=%d\n",
+ sm_dprintf("dane_verify: alg=%d, r=%d, len=%d\n",
alg, r, dane_tlsa->dane_tlsa_len[i]);
if (r != dane_tlsa->dane_tlsa_len[i] - 3)
continue;
@@ -2411,15 +2621,15 @@ dane_verify(ctx, dane_vrfy_ctx)
if (memcmp(p + 3, fp, r) == 0)
{
if (tTd(96, 2))
- sm_dprintf("dane_verify, status=match\n");
+ sm_dprintf("dane_verify: status=match\n");
if (tTd(96, 8))
{
- unsigned char hex[256];
+ unsigned char hex[DANE_FP_DBG_LEN];
data2hex((unsigned char *)p,
dane_tlsa->dane_tlsa_len[i],
hex, sizeof(hex));
- sm_dprintf("dane_verify, pubkey_fp=%s\n"
+ sm_dprintf("dane_verify: pubkey_fp=%s\n"
, hex);
}
dane_vrfy_ctx->dane_vrfy_res = DANE_VRFY_OK;
@@ -2433,6 +2643,180 @@ dane_verify(ctx, dane_vrfy_ctx)
dane_vrfy_ctx->dane_vrfy_res = ok;
return ok;
}
+
+/*
+** SSL_DANE_ENABLE -- enable using OpenSSL DANE functions for a session
+**
+** Parameters:
+** dane_vrfy_ctx -- dane verify context
+** ssl -- TLS connection structure
+**
+** Returns:
+** SM_SUCCESS: OpenSSL DANE checking enabled
+** SM_NOTDONE: OpenSSL DANE checking not enabled
+** <0: some error
+*/
+
+int
+ssl_dane_enable(dane_vrfy_ctx, ssl)
+ dane_vrfy_ctx_P dane_vrfy_ctx;
+ SSL *ssl;
+{
+# if HAVE_SSL_CTX_dane_enable
+ const char *dane_tlsa_domain;
+ int r, i, usable;
+# endif
+ dane_tlsa_P dane_tlsa;
+
+ if (tTd(96, 20))
+ sm_dprintf("ssl_dane_enable: dane_vrfy_ctx=%p, dane_vrfy_dane_enabled=%d, dane_vrfy_chk=%#x\n",
+ dane_vrfy_ctx, dane_vrfy_ctx->dane_vrfy_dane_enabled,
+ dane_vrfy_ctx->dane_vrfy_chk);
+
+ dane_tlsa = dane_get_tlsa(dane_vrfy_ctx);
+ if (tTd(96, 20))
+ sm_dprintf("ssl_dane_enable: dane_tlsa=%p, n=%d, supported=%d\n",
+ dane_tlsa, dane_tlsa != NULL ? dane_tlsa->dane_tlsa_n : -999,
+ dane_tlsa != NULL ? TLSA_IS_FL(dane_tlsa, TLSAFLSUP) : -1);
+ if (NULL == dane_tlsa || !TLSA_IS_FL(dane_tlsa, TLSAFLSUP))
+ {
+ /* no DANE verification possible */
+ dane_vrfy_ctx->dane_vrfy_chk |= TLSAFLNOVRFY;
+ return SM_SUCCESS;
+ }
+ if (0 == (dane_vrfy_ctx->dane_vrfy_chk & TLSAFLADIP))
+ {
+ /* no DANE verification possible */
+ dane_vrfy_ctx->dane_vrfy_chk |= TLSAFLNOVRFY;
+ return SM_SUCCESS;
+ }
+
+ if (!dane_vrfy_ctx->dane_vrfy_dane_enabled)
+ {
+# if HAVE_SSL_CTX_dane_enable
+ dane_vrfy_ctx->dane_vrfy_chk |= TLSAFLTEMPVRFY;
+# endif
+ return SM_NOTDONE;
+ }
+
+# if HAVE_SSL_CTX_dane_enable
+ dane_tlsa_domain = !SM_IS_EMPTY(dane_vrfy_ctx->dane_vrfy_sni)
+ ? dane_vrfy_ctx->dane_vrfy_sni
+ : dane_vrfy_ctx->dane_vrfy_host;
+ r = SSL_dane_enable(ssl, dane_tlsa_domain);
+# if _FFR_TESTS
+ if (tTd(90, 102))
+ {
+ sm_dprintf("ssl_dane_enable: test=simulate SSL_dane_enable error\n");
+# ifdef SSL_F_SSL_DANE_ENABLE
+ SSLerr(SSL_F_SSL_DANE_ENABLE, ERR_R_MALLOC_FAILURE);
+# endif
+ r = -1; /* -ENOMEM; */
+ }
+# endif /* _FFR_TESTS */
+ if (r <= 0)
+ {
+# if HAVE_SSL_CTX_dane_enable
+ dane_vrfy_ctx->dane_vrfy_chk |= TLSAFLTEMPVRFY;
+# endif
+ if (LogLevel > 1)
+ sm_syslog(LOG_ERR, NOQID,
+ "STARTTLS=client, SSL_dane_enable=%d", r);
+ tlslogerr(LOG_ERR, 7, "client");
+
+ /* XXX need better error code */
+ return (r < 0) ? r : -EINVAL;
+ }
+ if (LogLevel > 13)
+ sm_syslog(LOG_DEBUG, NOQID,
+ "STARTTLS=client, SSL_dane_enable=%d, domain=%s",
+ r, dane_tlsa_domain);
+ (void) SSL_dane_set_flags(ssl, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
+
+ usable = 0;
+ for (i = 0; i < dane_tlsa->dane_tlsa_n; i++)
+ {
+ const unsigned char *rr;
+ const char *chk;
+
+ rr = (const unsigned char *)dane_tlsa->dane_tlsa_rr[i];
+ if (NULL == rr)
+ continue;
+
+ /*
+ ** only DANE-TA(2) or DANE-EE(3)
+ ** use dane_tlsa_chk() instead?
+ */
+
+# if _FFR_TESTS
+ if (tTd(90, 101) && 3 == rr[0] && 1 == rr[1])
+ {
+ sm_dprintf("TLSA, type=%d-%d-%d:%02x, status=unsupported_due_to_test",
+ (int)rr[0], (int)rr[1], (int)rr[2],
+ (int)rr[3]);
+ r = 0;
+ chk = "tlsa_test";
+ }
+ else
+# endif /* _FFR_TESTS */
+ if (!(2 == rr[0] || 3 == rr[0]))
+ {
+ r = 0;
+ chk = "tlsa_chk";
+ }
+ else
+ {
+ r = SSL_dane_tlsa_add(ssl, rr[0], rr[1], rr[2], rr + 3,
+ (size_t) (dane_tlsa->dane_tlsa_len[i] - 3));
+ chk = "SSL_dane_tlsa_add";
+ }
+ if (r > 0)
+ usable++;
+# if HAVE_SSL_CTX_dane_enable && 0
+/* should an error be ignored or cause a temporary failure? */
+ if (r < 0)
+ dane_vrfy_ctx->dane_vrfy_chk |= TLSAFLTEMPVRFY;
+# endif
+ else if (LogLevel > ((r < 0) ? 10 : 13))
+ {
+ unsigned char hex[DANE_FP_LOG_LEN];
+
+ (void) data2hex((unsigned char *)rr + 3,
+ dane_tlsa->dane_tlsa_len[i] - 3,
+ hex, sizeof(hex));
+ sm_syslog(LOG_DEBUG, NOQID,
+ "STARTTLS=client, %s=%d, type=%d-%d-%d, fp=%s"
+ , chk, r, rr[0], rr[1], rr[2], hex);
+ tlslogerr(LOG_DEBUG, (r < 0) ? 13 : 10, "client");
+ }
+ if (tTd(96, 20))
+ {
+ unsigned char hex[DANE_FP_DBG_LEN];
+
+ (void) data2hex((unsigned char *)rr + 3,
+ dane_tlsa->dane_tlsa_len[i] - 3,
+ hex, sizeof(hex));
+ sm_dprintf("ssl_dane_enable: SSL_dane_tlsa_add=%d, u=%d, s=%d, d=%d, len=%d, fp=%s\n"
+ , r, rr[0], rr[1], rr[2]
+ , dane_tlsa->dane_tlsa_len[i]-3, hex
+ );
+ }
+ }
+ if (tTd(96, 20))
+ sm_dprintf("ssl_dane_enable: usable=%d\n", usable);
+ if (0 == usable)
+ {
+ /* shouldn't happen - checked above! */
+ if (LogLevel > 1)
+ sm_syslog(LOG_CRIT, NOQID,
+ "ERROR: ssl_dane_enable() INCONSISTENY: %d usable TLSA RRs found but \"supported\" flag is set (%d)\n",
+ usable, TLSA_IS_FL(dane_tlsa, TLSAFLSUP));
+ dane_vrfy_ctx->dane_vrfy_chk |= TLSAFLNOVRFY;
+ return SM_SUCCESS;
+ }
+# endif /* HAVE_SSL_CTX_dane_enable */
+ return SM_SUCCESS;
+}
# endif /* DANE */
/*
@@ -2455,6 +2839,7 @@ tls_verify_cb(ctx, cb_ctx)
int ok;
# if DANE
SM_DECTLSI;
+ dane_vrfy_ctx_P dane_vrfy_ctx;
# endif
/*
@@ -2465,27 +2850,45 @@ tls_verify_cb(ctx, cb_ctx)
# if DANE
SM_GETTLSI;
- if (tlsi_ctx != NULL)
- {
- dane_vrfy_ctx_P dane_vrfy_ctx;
-
- dane_vrfy_ctx = &(tlsi_ctx->tlsi_dvc);
- ok = dane_verify(ctx, dane_vrfy_ctx);
- if (tTd(96, 2))
- sm_dprintf("dane_verify=%d, res=%d\n", ok,
- dane_vrfy_ctx->dane_vrfy_res);
- if (ok != DANE_VRFY_NONE)
- return 1;
+ if (tTd(96, 40))
+ sm_dprintf("tls_verify_cb: tlsi_ctx=%p, vrfy_chk=%#x\n", tlsi_ctx,
+ (tlsi_ctx != NULL && (dane_vrfy_ctx = &(tlsi_ctx->tlsi_dvc)) != NULL) ?
+ dane_vrfy_ctx->dane_vrfy_chk : -1);
+ if (tlsi_ctx != NULL && (dane_vrfy_ctx = &(tlsi_ctx->tlsi_dvc)) != NULL
+ && !dane_vrfy_ctx->dane_vrfy_dane_enabled
+ && (0 == (dane_vrfy_ctx->dane_vrfy_chk & TLSAFLTEMPVRFY))
+ && VRFY_DANE(dane_vrfy_ctx->dane_vrfy_chk)
+ )
+ {
+ int depth;
+
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+ if (tTd(96, 20))
+ sm_dprintf("tls_verify_cb: enabled=%d, chk=%#x, depth=%d\n",
+ dane_vrfy_ctx->dane_vrfy_dane_enabled,
+ dane_vrfy_ctx->dane_vrfy_chk, depth);
+
+ if (0 == depth)
+ {
+ ok = dane_verify(ctx, dane_vrfy_ctx);
+ if (tTd(96, 2))
+ sm_dprintf("tls_verify_cb: dane_verify=%d, res=%d\n", ok,
+ dane_vrfy_ctx->dane_vrfy_res);
+ if (ok != DANE_VRFY_NONE)
+ return 1;
+ }
}
+
+ if (tTd(96, 10))
+ sm_dprintf("tls_verify_cb: basic check? enabled=%d, chk=%#x\n",
+ (tlsi_ctx != NULL && dane_vrfy_ctx != NULL) ?
+ dane_vrfy_ctx->dane_vrfy_dane_enabled : -1,
+ (tlsi_ctx != NULL && dane_vrfy_ctx != NULL) ?
+ dane_vrfy_ctx->dane_vrfy_chk : -1);
# endif /* DANE */
ok = X509_verify_cert(ctx);
- if (ok <= 0)
- {
- if (LogLevel > 13)
- return tls_verify_log(ok, ctx, "TLS");
- }
- else if (LogLevel > 14)
+ if ((LogLevel > 13 && ok <= 0) || LogLevel > 14)
(void) tls_verify_log(ok, ctx, "TLS");
return 1;
}
@@ -2515,8 +2918,8 @@ tlslogerr(priority, ll, who)
if (LogLevel <= ll)
return;
- while ((l = ERR_get_error_line_data((const char **) &file, &line,
- (const char **) &data, &flags))
+ while ((l = MTA_SSL_ERR_get((const char **) &file, &line,
+ (const char **) &data, &flags, NULL))
!= 0)
{
sm_syslog(priority, NOQID,
diff --git a/contrib/sendmail/src/tls.h b/contrib/sendmail/src/tls.h
index 5ca6d7eab734..8ab2a774d231 100644
--- a/contrib/sendmail/src/tls.h
+++ b/contrib/sendmail/src/tls.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 2015, 2020-2023 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
@@ -7,7 +7,6 @@
* the sendmail distribution.
*/
-
#ifndef _TLS_H
# define _TLS_H 1
@@ -21,7 +20,7 @@
# endif
# endif /* !TLS_NO_RSA */
-# if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L
+# if (OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L) || OPENSSL_VERSION_NUMBER >= 0x30000000L
# define TLS_version_num OpenSSL_version_num
# else
# define TLS_version_num SSLeay
@@ -48,18 +47,37 @@
#endif
#if DANE
+
+# ifndef HAVE_SSL_CTX_dane_enable
+# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && OPENSSL_VERSION_NUMBER < 0x20000000L) || OPENSSL_VERSION_NUMBER >= 0x30000000L
+# define HAVE_SSL_CTX_dane_enable 1
+# endif
+# endif
+
+extern int ssl_dane_enable __P((dane_vrfy_ctx_P, SSL *));
+# define SM_NOTDONE 1
+# define SM_FULL 2
+
extern int gettlsa __P((char *, char *, STAB **, unsigned long, unsigned int, unsigned int));
-# define MAX_TLSA_RR 8
+# ifndef MAX_TLSA_RR
+# if HAVE_SSL_CTX_dane_enable
+# define MAX_TLSA_RR 64
+# else
+# define MAX_TLSA_RR 16
+# endif
+# endif
-# define DANE_VRFY_NONE 0 /* no TLSAs */
-# define DANE_VRFY_OK 1 /* TLSA check was ok */
-# define DANE_VRFY_FAIL (-1) /* TLSA check failed */
+# define DANE_VRFY_NONE 0 /* no DANE */
+/* # define DANE_VRFY_NO 1 * no TLSAs */
+# define DANE_VRFY_FAIL 2 /* TLSA check failed */
+# define DANE_VRFY_OK 3 /* TLSA check was ok */
+# define DANE_VRFY_TEMP 4 /* TLSA check failed temporarily */
/* return values for dane_tlsa_chk() */
# define TLSA_BOGUS (-10)
# define TLSA_UNSUPP (-1)
/* note: anything >= 0 is ok and refers to the hash algorithm */
-# define TLSA_IS_KNOWN(r) ((r) >= 0)
+# define TLSA_IS_SUPPORTED(r) ((r) >= 0)
# define TLSA_IS_VALID(r) ((r) >= TLSA_UNSUPP)
struct dane_tlsa_S
@@ -68,10 +86,13 @@ struct dane_tlsa_S
int dane_tlsa_n;
int dane_tlsa_dnsrc;
unsigned long dane_tlsa_flags;
- unsigned char dane_tlsa_usage[MAX_TLSA_RR];
- unsigned char dane_tlsa_selector[MAX_TLSA_RR];
- unsigned char dane_tlsa_digest[MAX_TLSA_RR];
- void *dane_tlsa_rr[MAX_TLSA_RR];
+
+ /*
+ ** Note: all "valid" TLSA RRs are stored,
+ ** not just those which are "supported"
+ */
+
+ unsigned char *dane_tlsa_rr[MAX_TLSA_RR];
int dane_tlsa_len[MAX_TLSA_RR];
char *dane_tlsa_sni;
};
@@ -83,40 +104,54 @@ struct dane_tlsa_S
# define DANEMODE(fl) ((fl) & 0x3)
# define TLSAFLNOEXP 0x00000010 /* do not check expiration */
+# define TLSAFLNEW 0x00000020
# define TLSAFLADMX 0x00000100
-# define TLSAFLADTLSA 0x00000200 /* currently unused */
+# define TLSAFLADIP 0x00000200 /* changes with each IP lookup! */
+# define TLSAFLNOTLS 0x00000400 /* starttls() failed */
+/* treat IPv4 and IPv6 the same - the ad flag should be identical */
+/* # define TLSAFLADTLSA * currently unused */
+/* NOTE: "flags" >= TLSAFLTEMP are stored, see TLSA_STORE_FL()! */
/* could be used to replace DNSRC */
-# define TLSAFLTEMP 0x00001000
-/* no TLSA? -- _n == 0 */
-# define TLSAFLNOTLSA 0x00002000 /* currently unused */
+# define TLSAFLTEMP 0x00001000 /* TLSA RR lookup tempfailed */
+# define TLSAFL2MANY 0x00004000 /* too many TLSA RRs */
/*
** Do not use this record, and do not look up new TLSA RRs because
** the MX/host lookup was not secure.
+** XXX: host->MX lookup info can NOT be stored in dane_tlsa!
** XXX: to determine: interaction with DANE=always
*/
-# define TLSAFLNOADMX 0x00010000
-# define TLSAFLNOADTLSA 0x00020000 /* TLSA: no AD - for DANE=always? */
+/* # define TLSAFLNOADMX 0x00010000 */
+/* # define TLSAFLNOADTLSA 0x00020000 * TLSA: no AD - for DANE=always? */
+
+# define TLSAFLTEMPVRFY 0x00008000 /* temporary DANE verification failure */
+# define TLSAFLNOVRFY 0x00080000 /* do NOT perform DANE verification */
+
+# define TLSAFLUNS 0x00100000 /* has unsupported TLSA RRs */
+# define TLSAFLSUP 0x00200000 /* has supported TLSA RRs */
# define TLSA_SET_FL(dane_tlsa, fl) (dane_tlsa)->dane_tlsa_flags |= (fl)
# define TLSA_CLR_FL(dane_tlsa, fl) (dane_tlsa)->dane_tlsa_flags &= ~(fl)
-# define TLSA_IS_FL(dane_tlsa, fl) ((dane_tlsa)->dane_tlsa_flags & (fl))
-# define TLSA_STORE_FL(fl) ((fl) >= TLSAFLTEMP)
+# define TLSA_IS_FL(dane_tlsa, fl) (((dane_tlsa)->dane_tlsa_flags & (fl)) != 0)
-# define GETTLSA(host, pste, port) gettlsa(host, NULL, pste, TLSAFLNONE, 0, port)
-# define GETTLSANOX(host, pste, port) gettlsa(host, NULL, pste, TLSAFLNOEXP, 0, port)
+/* any TLSA RRs? */
+# define TLSA_HAS_RRs(dane_tlsa) TLSA_IS_FL(dane_tlsa, TLSAFLUNS|TLSAFLSUP)
+
+# define TLSA_STORE_FL(fl) ((fl) >= TLSAFLTEMP)
/* values for DANE option and dane_vrfy_chk */
-# define DANE_NEVER TLSAFLNONE
-# define DANE_ALWAYS TLSAFLALWAYS /* NOT documented, testing... */
+# define DANE_NEVER TLSAFLNONE /* XREF: see sendmail.h: #define Dane */
+# define DANE_ALWAYS TLSAFLALWAYS /* NOT documented, testing... */
# define DANE_SECURE TLSAFLSECURE
-# define CHK_DANE(dane) ((dane) != DANE_NEVER)
+# define CHK_DANE(dane) (DANEMODE((dane)) != DANE_NEVER)
+# define VRFY_DANE(dane_vrfy_chk) (0 == ((dane_vrfy_chk) & TLSAFLNOVRFY))
/* temp fails? others? */
# define TLSA_RR_TEMPFAIL(dane_tlsa) (((dane_tlsa) != NULL) && (dane_tlsa)->dane_tlsa_dnsrc == TRY_AGAIN)
+# define ONLYUNSUPTLSARR ", status=all TLSA RRs are unsupported"
#endif /* DANE */
/*
@@ -154,6 +189,7 @@ not "read" anywhere
#define TLS_I_CRLF_EX 0x00800000 /* CRL file must exist */
#define TLS_I_CRLF_UNR 0x01000000 /* CRL file must be g/o unreadable */
#define TLS_I_DHFIXED 0x02000000 /* use fixed DH param */
+#define TLS_I_DHAUTO 0x04000000 /* */
/* require server cert */
#define TLS_I_SRV_CERT (TLS_I_CERT_EX | TLS_I_KEY_EX | \
@@ -170,6 +206,7 @@ not "read" anywhere
#define TLS_AUTH_OK 0
#define TLS_AUTH_NO 1
+#define TLS_AUTH_TEMP 2
#define TLS_AUTH_FAIL (-1)
# ifndef TLS_VRFY_PER_CTX
@@ -199,7 +236,7 @@ extern int tls_get_info __P((SSL *, bool, char *, MACROS_T *, bool));
extern void tlslogerr __P((int, int, const char *));
extern void tls_set_verify __P((SSL_CTX *, SSL *, bool));
# if DANE
-extern int dane_tlsa_chk __P((const char *, int, const char *, bool));
+extern int dane_tlsa_chk __P((const unsigned char *, int, const char *, bool));
extern int dane_tlsa_clr __P((dane_tlsa_P));
extern int dane_tlsa_free __P((dane_tlsa_P));
# endif
@@ -245,7 +282,7 @@ int TLS_set_engine __P((const char *, bool));
extern int set_tls_rd_tmo __P((int));
extern int data2hex __P((unsigned char *, int, unsigned char *, int));
# if DANE
-extern int pubkey_fp __P((X509 *, const char*, char **));
+extern int pubkey_fp __P((X509 *, const char*, unsigned char **));
extern dane_tlsa_P dane_get_tlsa __P((dane_vrfy_ctx_P));
# endif
diff --git a/contrib/sendmail/src/tlsh.c b/contrib/sendmail/src/tlsh.c
index 56dad3568e4f..eabb4c313d62 100644
--- a/contrib/sendmail/src/tlsh.c
+++ b/contrib/sendmail/src/tlsh.c
@@ -105,12 +105,12 @@ tls_data_md(buf, len, md)
}
/*
-** PUBKEY_FP -- get public key fingerprint
+** PUBKEY_FP -- generate public key fingerprint
**
** Parameters:
** cert -- TLS cert
** mdalg -- name of digest algorithm
-** fp -- (pointer to) fingerprint buffer
+** fp -- (pointer to) fingerprint buffer (output)
**
** Returns:
** <=0: cert fp calculation failed
@@ -121,10 +121,10 @@ int
pubkey_fp(cert, mdalg, fp)
X509 *cert;
const char *mdalg;
- char **fp;
+ unsigned char **fp;
{
int len, r;
- unsigned char *buf, *end;
+ unsigned char *end;
const EVP_MD *md;
SM_ASSERT(cert != NULL);
@@ -138,8 +138,8 @@ pubkey_fp(cert, mdalg, fp)
return -EINVAL;
if (len < EVP_MAX_MD_SIZE)
len = EVP_MAX_MD_SIZE;
- end = buf = sm_malloc(len);
- if (NULL == buf)
+ *fp = end = sm_malloc(len);
+ if (NULL == end)
return -ENOMEM;
if ('\0' == mdalg[0])
@@ -147,22 +147,19 @@ pubkey_fp(cert, mdalg, fp)
r = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
if (r <= 0 || r != len)
return -EINVAL;
- *fp = (char *)buf;
return len;
}
md = EVP_get_digestbyname(mdalg);
if (NULL == md)
{
- SM_FREE(buf);
+ SM_FREE(*fp);
return DANE_VRFY_FAIL;
}
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end);
- r = tls_data_md(buf, len, md);
+ r = tls_data_md(*fp, len, md);
if (r < 0)
- sm_free(buf);
- else
- *fp = (char *)buf;
+ sm_free(*fp);
return r;
}
@@ -176,17 +173,21 @@ pubkey_fp(cert, mdalg, fp)
** log -- whether to log problems
**
** Returns:
-** TLSA_*, see tls.h
+** >=0: "alg" aka "matching type"
+** <0: TLSA_*, see tls.h
*/
int
dane_tlsa_chk(rr, len, host, log)
- const char *rr;
+ const unsigned char *rr;
int len;
const char *host;
bool log;
{
int alg;
+# if HAVE_SSL_CTX_dane_enable
+ int sel, usg;
+# endif
if (len < 4)
{
@@ -199,8 +200,16 @@ dane_tlsa_chk(rr, len, host, log)
SM_ASSERT(rr != NULL);
alg = (int)rr[2];
+# if HAVE_SSL_CTX_dane_enable
+ usg = (int)rr[0];
+ sel = (int)rr[1];
+ if (usg >= 2 && usg <= 3 && sel >= 0 && sel <= 1 &&
+ alg >= 0 && alg <= 2)
+ return alg;
+# else
if ((int)rr[0] == 3 && (int)rr[1] == 1 && (alg >= 0 && alg <= 2))
return alg;
+# endif
if (log && LogLevel > 9)
sm_syslog(LOG_NOTICE, NOQID,
"TLSA=%s, type=%d-%d-%d:%02x, status=unsupported",
diff --git a/contrib/sendmail/src/udb.c b/contrib/sendmail/src/udb.c
index 0542952c7e28..8b8222cea1ec 100644
--- a/contrib/sendmail/src/udb.c
+++ b/contrib/sendmail/src/udb.c
@@ -40,7 +40,6 @@ DBT
** This depends on the 4.4BSD db package.
*/
-
struct udbent
{
char *udb_spec; /* string version of spec */
@@ -68,7 +67,7 @@ struct udbent
# define udb_fwdhost udb_u.udb_forward._udb_fwdhost
# if NEWDB
- /* type UE_FETCH -- lookup in local database */
+ /* type UE_FETCH -- look up in local database */
struct
{
char *_udb_dbname; /* pathname of database */
@@ -89,7 +88,6 @@ struct udbent
# define MAXUDBENT 10 /* maximum number of UDB entries */
-
struct udb_option
{
char *udbo_name;
@@ -580,7 +578,7 @@ udbsender(sender, rpool)
**
** Parameters:
** user -- the name of the user.
-** field -- the field to lookup.
+** field -- the field to look up.
** rpool -- resource pool from which to allocate result
**
** Returns:
@@ -598,11 +596,13 @@ udbmatch(user, field, rpool)
char *field;
SM_RPOOL_T *rpool;
{
- register char *p;
register struct udbent *up;
- int i;
+# if NEWDB || HESIOD
+ register char *p;
int keylen;
DBT key, info;
+# endif
+ int i;
char keybuf[MAXUDBKEY];
if (tTd(28, 1))
@@ -635,7 +635,9 @@ udbmatch(user, field, rpool)
/* build database key */
(void) sm_strlcpyn(keybuf, sizeof(keybuf), 3, user, ":", field);
+# if NEWDB || HESIOD
keylen = strlen(keybuf);
+# endif
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
@@ -707,7 +709,9 @@ udbmatch(user, field, rpool)
/* build database key */
(void) sm_strlcpyn(keybuf, sizeof(keybuf), 2, user, ":maildrop");
+# if NEWDB || HESIOD
keylen = strlen(keybuf);
+# endif
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
diff --git a/contrib/sendmail/src/usersmtp.c b/contrib/sendmail/src/usersmtp.c
index 5fe079176eaf..020ef184ef74 100644
--- a/contrib/sendmail/src/usersmtp.c
+++ b/contrib/sendmail/src/usersmtp.c
@@ -61,6 +61,9 @@ smtpclrse(e)
e->e_rcode = 0;
e->e_renhsc[0] = '\0';
e->e_text = NULL;
+#if _FFR_LOG_STAGE
+ e->e_estate = -1;
+#endif
/*
** Reset to avoid access to potentially dangling pointer
@@ -125,6 +128,7 @@ smtpinit(m, mci, e, onlyhelo)
e->e_rcode = 0;
e->e_renhsc[0] = '\0';
e->e_text = NULL;
+ maps_reset_chged("client:smtpinit");
switch (state)
{
case MCIS_MAIL:
@@ -168,7 +172,8 @@ smtpinit(m, mci, e, onlyhelo)
SmtpPhase = mci->mci_phase = "client greeting";
sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e), CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, XS_GREET);
+ r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, XS_GREET,
+ NULL);
if (r < 0)
goto tempfail1;
if (REPLYTYPE(r) == 4)
@@ -224,7 +229,7 @@ tryhelo:
r = reply(m, mci, e,
bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
: TimeOuts.to_helo,
- helo_options, NULL, XS_EHLO);
+ helo_options, NULL, XS_EHLO, NULL);
if (r < 0)
goto tempfail1;
else if (REPLYTYPE(r) == 5)
@@ -275,7 +280,7 @@ tryhelo:
/* tell it to be verbose */
smtpmessage("VERB", m, mci);
r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc,
- XS_DEFAULT);
+ XS_DEFAULT, NULL);
if (r < 0)
goto tempfail1;
}
@@ -1840,7 +1845,7 @@ attemptauth(m, mci, e, sai)
/* get the reply */
smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
- XS_AUTH);
+ XS_AUTH, NULL);
for (;;)
{
@@ -1884,7 +1889,7 @@ attemptauth(m, mci, e, sai)
*/
smtpresult = reply(m, mci, e, TimeOuts.to_auth,
- getsasldata, NULL, XS_AUTH);
+ getsasldata, NULL, XS_AUTH, NULL);
return EX_NOPERM;
}
@@ -1906,7 +1911,7 @@ attemptauth(m, mci, e, sai)
# endif
smtpmessage("%s", m, mci, in64);
smtpresult = reply(m, mci, e, TimeOuts.to_auth,
- getsasldata, NULL, XS_AUTH);
+ getsasldata, NULL, XS_AUTH, NULL);
}
/* NOTREACHED */
}
@@ -2089,7 +2094,7 @@ smtpmailfrom(m, mci, e)
e->e_smtputf8 = true;
}
- if (e->e_smtputf8 && !SMTPUTF8)
+ if (e->e_smtputf8 && !SMTP_UTF8)
{
extern char MsgBuf[];
@@ -2248,6 +2253,7 @@ smtpmailfrom(m, mci, e)
** Designates the sender.
*/
+ maps_reset_chged("client:MAIL");
mci->mci_state = MCIS_MAIL;
#if !USE_EAI
@@ -2291,7 +2297,7 @@ smtpmailfrom(m, mci, e)
SmtpPhase = mci->mci_phase = "client MAIL";
sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_MAIL);
+ r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_MAIL, NULL);
if (r < 0)
{
/* communications failure */
@@ -2390,6 +2396,9 @@ smtprcpt(to, m, mci, e, ctladdr, xstart)
char buf[MAXNAME + 1]; /* EAI:ok */
int len, nlen;
#endif
+#if PIPELINING
+ char *oldto;
+#endif
#if PIPELINING
/*
@@ -2397,20 +2406,24 @@ smtprcpt(to, m, mci, e, ctladdr, xstart)
** This should normally happen because of SMTP pipelining.
*/
+ oldto = e->e_to;
while (mci->mci_nextaddr != NULL &&
sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
{
int r;
+ e->e_to = mci->mci_nextaddr->q_paddr;
r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
if (r != EX_OK)
{
markfailure(e, mci->mci_nextaddr, mci, r, false);
giveresponse(r, mci->mci_nextaddr->q_status, m, mci,
- ctladdr, xstart, e, to);
+ ctladdr, xstart, e, mci->mci_nextaddr);
}
mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
+ e->e_to = oldto;
}
+ e->e_to = oldto;
#endif /* PIPELINING */
/*
@@ -2562,9 +2575,9 @@ smtprcptstat(to, m, mci, e)
}
enhsc = NULL;
- r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_RCPT);
+ r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_RCPT,
+ &to->q_rstatus);
save_errno = errno;
- to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
if (!bitnset(M_LMTP, m->m_flags))
to->q_statmta = mci->mci_host;
@@ -2719,7 +2732,7 @@ smtpdata(m, mci, e, ctladdr, xstart)
mci->mci_state = MCIS_DATA;
sm_setproctitle(true, e, "%s %s: %s",
qid_printname(e), CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DATA);
+ r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DATA, NULL);
if (r < 0 || REPLYTYPE(r) == 4)
{
if (r >= 0)
@@ -2840,7 +2853,7 @@ smtpdata(m, mci, e, ctladdr, xstart)
CurHostName, mci->mci_phase);
if (bitnset(M_LMTP, m->m_flags))
return EX_OK;
- r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_EOM);
+ r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_EOM, NULL);
if (r < 0)
return EX_TEMPFAIL;
if (mci->mci_state == MCIS_DATA)
@@ -2928,7 +2941,8 @@ smtpgetstat(m, mci, e)
enhsc = NULL;
/* check for the results of the transaction */
- r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DATA2);
+ r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DATA2,
+ NULL);
if (r < 0)
return EX_TEMPFAIL;
xstat = EX_NOTSTICKY;
@@ -3010,7 +3024,8 @@ smtpquit(m, mci, e)
SmtpPhase = "client QUIT";
mci->mci_state = MCIS_QUITING;
smtpmessage("QUIT", m, mci);
- (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, XS_QUIT);
+ (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, XS_QUIT,
+ NULL);
SuprErrs = oldSuprErrs;
if (mci->mci_state == MCIS_CLOSED)
goto end;
@@ -3081,7 +3096,7 @@ smtprset(m, mci, e)
SmtpPhase = "client RSET";
smtpmessage("RSET", m, mci);
- r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT);
+ r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT, NULL);
if (r < 0)
return;
@@ -3130,7 +3145,8 @@ smtpprobe(mci)
e = &BlankEnvelope;
SmtpPhase = "client probe";
smtpmessage("RSET", m, mci);
- r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT);
+ r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT,
+ NULL);
if (REPLYTYPE(r) != 2)
smtpquit(m, mci, e);
return r;
@@ -3147,16 +3163,18 @@ smtpprobe(mci)
** If null, no special processing is done.
** enhstat -- optional, returns enhanced error code string (if set)
** rtype -- type of SmtpMsgBuffer: does it contains secret data?
+** rtext -- pointer to where to save first line of reply (if set)
**
** Returns:
** reply code it reads.
+** -1 on I/O errors etc.
**
** Side Effects:
** flushes the mail file.
*/
int
-reply(m, mci, e, timeout, pfunc, enhstat, rtype)
+reply(m, mci, e, timeout, pfunc, enhstat, rtype, rtext)
MAILER *m;
MCI *mci;
ENVELOPE *e;
@@ -3164,6 +3182,7 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
char **enhstat;
int rtype;
+ char **rtext;
{
register char *bufp;
register int r;
@@ -3196,7 +3215,13 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
what = "greeting";
else
what = "unknown";
- sm_dprintf("reply to %s\n", what);
+#if PIPELINING
+ if (mci->mci_flags & MCIF_PIPELINED)
+ sm_dprintf("reply to %s:%d [but PIPELINED]\n", what, rtype);
+ else
+#endif
+ /* "else" in #if code above */
+ sm_dprintf("reply to %s:%d\n", what, rtype);
}
/*
@@ -3274,7 +3299,7 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
mci->mci_errno = errno;
oldholderrs = HoldErrs;
HoldErrs = true;
- usrerr("451 4.4.1 reply: read error from %s",
+ usrerr("451 4.4.2 reply: read error from %s",
CURHOSTNAME);
mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
@@ -3307,6 +3332,8 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
return -1;
}
fixcrlf(bufp, true);
+ if (tTd(18, 4))
+ sm_dprintf("received=%s\n", bufp);
/* EHLO failure is not a real error */
if (e->e_xfp != NULL && (bufp[0] == '4' ||
@@ -3348,6 +3375,9 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
if (!ISSMTPREPLY(bufp))
continue;
+ if (NULL != rtext && firstline)
+ *rtext = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
+
if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
enhstat != NULL &&
extenhsc(bufp + 4, ' ', enhstatcode) > 0)
@@ -3409,6 +3439,9 @@ reply(m, mci, e, timeout, pfunc, enhstat, rtype)
e->e_rcode = r;
e->e_text = sm_rpool_strdup_x(
e->e_rpool, bufp + o);
+#if _FFR_LOG_STAGE
+ e->e_estate = rtype;
+#endif
}
}
if (tTd(87, 2))
@@ -3520,7 +3553,5 @@ smtpmessage(f, m, mci, va_alist)
: m->m_eol);
}
else if (tTd(18, 1))
- {
sm_dprintf("smtpmessage: NULL mci_out\n");
- }
}
diff --git a/contrib/sendmail/src/util.c b/contrib/sendmail/src/util.c
index c923298a576c..edb3c503e68e 100644
--- a/contrib/sendmail/src/util.c
+++ b/contrib/sendmail/src/util.c
@@ -757,25 +757,29 @@ printav(fp, av)
for (cp = *av++; *cp != '\0'; cp++) {
v = (unsigned char)(*cp & 0x00ff);
- sm_dprintf("%c", v);
+ (void) sm_io_putc(fp, SM_TIME_DEFAULT, v);
# if 0
if (isascii(v) && isprint(v))
- sm_dprintf("%c", v);
+ (void) sm_io_putc(fp, SM_TIME_DEFAULT,
+ v);
else
- sm_dprintf("\\x%hhx", v);
+ (void) sm_io_fprintf(fp,
+ SM_TIME_DEFAULT, "\\x%hhx", v);
# endif
}
if (*av != NULL)
- sm_dprintf(" ");
+ (void) sm_io_putc(fp, SM_TIME_DEFAULT, ' ');
continue;
}
#endif /* _FFR_8BITENVADDR */
if (tTd(0, 44))
- sm_dprintf("\n\t%08lx=", (unsigned long) *av);
+ (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
+ "\n\t%08lx=", (unsigned long) *av);
else
(void) sm_io_putc(fp, SM_TIME_DEFAULT, ' ');
if (tTd(0, 99))
- sm_dprintf("%s", str2prt(*av++));
+ (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
+ "%s", str2prt(*av++));
else
xputs(fp, *av++);
}
@@ -1026,7 +1030,6 @@ makelower_a(pp, rpool)
return orig;
}
-
#if 0
makelower: Optimization for EAI case?
@@ -1084,15 +1087,15 @@ makelower_buf(str, buf, buflen)
}
/*
-** FIXCRLF -- fix <CR><LF> in line.
+** FIXCRLF -- fix CRLF in line.
**
** XXX: Could this be a problem for EAI? That is, can there
** be a string with \n and the previous octet is \n
** but is part of a UTF8 "char"?
**
-** Looks for the <CR><LF> combination and turns it into the
-** UNIX canonical <NL> character. It only takes one line,
-** i.e., it is assumed that the first <NL> found is the end
+** Looks for the CRLF combination and turns it into the
+** UNIX canonical LF character. It only takes one line,
+** i.e., it is assumed that the first LF found is the end
** of the line.
**
** Parameters:
@@ -1126,7 +1129,7 @@ fixcrlf(line, stripnl)
/*
** PUTLINE -- put a line like fputs obeying SMTP conventions
**
-** This routine always guarantees outputing a newline (or CRLF,
+** This routine always guarantees outputting a newline (or CRLF,
** as appropriate) at the end of the string.
**
** Parameters:
@@ -1151,7 +1154,7 @@ putline(l, mci)
/*
** PUTXLINE -- putline with flags bits.
**
-** This routine always guarantees outputing a newline (or CRLF,
+** This routine always guarantees outputting a newline (or CRLF,
** as appropriate) at the end of the string.
**
** Parameters:
@@ -1172,7 +1175,6 @@ putline(l, mci)
** output of l to mci->mci_out.
*/
-
#define PUTX(limit) \
do \
{ \
@@ -1420,7 +1422,6 @@ xunlink(f)
** buf otherwise.
*/
-
char *
sfgets(buf, siz, fp, timeout, during)
char *buf;
@@ -1461,9 +1462,7 @@ sfgets(buf, siz, fp, timeout, during)
CURHOSTNAME,
during);
buf[0] = '\0';
-#if XDEBUG
checkfd012(during);
-#endif
if (TrafficLogFile != NULL)
(void) sm_io_fprintf(TrafficLogFile,
SM_TIME_DEFAULT,
@@ -1531,7 +1530,7 @@ sfgets(buf, siz, fp, timeout, during)
** Side Effects:
** buf gets lines from f, with continuation lines (lines
** with leading white space) appended. CRLF's are mapped
-** into single newlines. Any trailing NL is stripped.
+** into single newlines. Any trailing LF is stripped.
** Increases LineNumber for each line.
*/
@@ -1774,6 +1773,7 @@ strcontainedin(icase, a, b)
return false;
}
+#if XDEBUG
/*
** CHECKFD012 -- check low numbered file descriptors
**
@@ -1791,12 +1791,10 @@ void
checkfd012(where)
char *where;
{
-#if XDEBUG
register int i;
for (i = 0; i < 3; i++)
fill_fd(i, where);
-#endif /* XDEBUG */
}
/*
@@ -1815,7 +1813,6 @@ checkfdopen(fd, where)
int fd;
char *where;
{
-#if XDEBUG
struct stat st;
if (fstat(fd, &st) < 0 && errno == EBADF)
@@ -1823,8 +1820,8 @@ checkfdopen(fd, where)
syserr("checkfdopen(%d): %s not open as expected!", fd, where);
printopenfds(true);
}
-#endif /* XDEBUG */
}
+#endif /* XDEBUG */
/*
** CHECKFDS -- check for new or missing file descriptors
@@ -2772,7 +2769,6 @@ proc_list_drop(pid, st, other)
}
}
-
if (type == PROC_CONTROL && WIFEXITED(st))
{
/* if so, see if we need to restart or shutdown */
@@ -2926,7 +2922,7 @@ proc_list_display(out, prefix)
** type -- type of process to signal
** signal -- the type of signal to send
**
-** Results:
+** Returns:
** none.
**
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
@@ -3025,9 +3021,21 @@ count_open_connections(hostaddr)
** inchannel -- FILE to check
**
** Returns:
+** >0 if X-CONNECT/PROXY was used successfully (D_XCNCT*)
+** 0 if X-CONNECT/PROXY was not given
** -1 on error
-** 0 if X-CONNECT was not given
-** >0 if X-CONNECT was used successfully (D_XCNCT*)
+** -2 PROXY UNKNOWN
+*/
+
+/*
+** HA proxy version 1:
+**
+** PROXY TCP[4|6] IPv[4|6]-src-addr IPv[4|6]-dst-addr src-port dst-port\r\n
+** PROXY UNKNOWN ...
+** examples:
+** "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"
+** "PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n"
+** "PROXY UNKNOWN\r\n"
*/
int
@@ -3041,6 +3049,11 @@ xconnect(inchannel)
char pvpbuf[PSBUFSIZE];
char *peerhostname; /* name of SMTP peer or "localhost" */
extern ENVELOPE BlankEnvelope;
+#if _FFR_HAPROXY
+ int haproxy = AF_UNSPEC;
+# define HAPROXY "PROXY "
+# define HAPROXYLEN (sizeof(HAPROXY) - 1)
+#endif
#define XCONNECT "X-CONNECT "
#define XCNNCTLEN (sizeof(XCONNECT) - 1)
@@ -3071,6 +3084,13 @@ xconnect(inchannel)
return 0;
}
+#if _FFR_HAPROXY
+ if (pvp != NULL && pvp[0] != NULL && strcasecmp(pvp[0], "haproxy1") == 0)
+ {
+ haproxy = AF_LOCAL;
+ }
+#endif
+
# if _FFR_XCNCT > 1
if (pvp != NULL && pvp[0] != NULL &&
pvp[0][0] == '2' && pvp[0][1] == '2' && pvp[0][2] == '0')
@@ -3089,12 +3109,46 @@ xconnect(inchannel)
p = sfgets(inp, sizeof(inp), InChannel, TimeOuts.to_nextcommand, "pre");
if (tTd(75, 6))
sm_syslog(LOG_INFO, NOQID, "x-connect: input=%s", p);
+#if _FFR_HAPROXY
+ if (AF_UNSPEC != haproxy)
+ {
+ if (p == NULL || strncasecmp(p, HAPROXY, HAPROXYLEN) != 0)
+ return -1;
+ p += HAPROXYLEN;
+# define HAPUNKNOWN "UNKNOWN"
+# define HAPUNKNOWNLEN (sizeof(HAPUNKNOWN) - 1)
+ if (strncasecmp(p, HAPUNKNOWN, HAPUNKNOWNLEN) == 0)
+ {
+ /* how to handle this? */
+ sm_syslog(LOG_INFO, NOQID, "haproxy: input=%s, status=ignored", p);
+ return -2;
+ }
+# define HAPTCP4 "TCP4 "
+# define HAPTCP6 "TCP6 "
+# define HAPTCPNLEN (sizeof(HAPTCP4) - 1)
+ if (strncasecmp(p, HAPTCP4, HAPTCPNLEN) == 0)
+ haproxy = AF_INET;
+# if NETINET6
+ if (strncasecmp(p, HAPTCP6, HAPTCPNLEN) == 0)
+ haproxy = AF_INET6;
+# endif
+ if (AF_LOCAL != haproxy)
+ {
+ p += HAPTCPNLEN;
+ goto getip;
+ }
+ return -1;
+ }
+#endif
if (p == NULL || strncasecmp(p, XCONNECT, XCNNCTLEN) != 0)
return -1;
p += XCNNCTLEN;
while (SM_ISSPACE(*p))
p++;
+#if _FFR_HAPROXY
+ getip:
+#endif
/* parameters: IPAddress [Hostname[ M]] */
b = p;
while (*p != '\0' && isascii(*p) &&
@@ -3122,6 +3176,42 @@ xconnect(inchannel)
# endif
else
return -1;
+#if _FFR_HAPROXY
+ if (AF_UNSPEC != haproxy)
+ {
+ /*
+ ** dst-addr and dst-port are ignored because
+ ** they are not really worth to check:
+ ** IPv[4|6]-dst-addr: must be one of "our" addresses,
+ ** dst-port: must be the DaemonPort.
+ ** We also do not check whether
+ ** haproxy == addr.sa.sa_family
+ */
+
+ if (' ' == delim)
+ {
+ b = ++p;
+ while (*p != '\0' && !SM_ISSPACE(*p))
+ ++p;
+ if (*p != '\0' && SM_ISSPACE(*p))
+ ++p;
+ if (*p != '\0')
+ {
+ unsigned short port;
+
+ port = htons(atoi(p));
+ if (AF_INET == haproxy)
+ RealHostAddr.sin.sin_port = port;
+# if NETINET6
+ if (AF_INET6 == haproxy)
+ RealHostAddr.sin6.sin6_port = port;
+# endif
+ }
+ }
+ SM_FREE(RealHostName);
+ return D_XCNCT;
+ }
+#endif
/* more parameters? */
if (delim != ' ')
diff --git a/contrib/sendmail/src/version.c b/contrib/sendmail/src/version.c
index 8619c58ee355..f70ce680c0ba 100644
--- a/contrib/sendmail/src/version.c
+++ b/contrib/sendmail/src/version.c
@@ -15,4 +15,4 @@
SM_RCSID("@(#)$Id: version.c,v 8.250 2014-01-27 12:55:16 ca Exp $")
-char Version[] = "8.17.1";
+char Version[] = "8.18.1";
diff --git a/contrib/sendmail/test/README b/contrib/sendmail/test/README
index 7ca022f3d9f8..e21dc2f109b1 100644
--- a/contrib/sendmail/test/README
+++ b/contrib/sendmail/test/README
@@ -20,8 +20,9 @@ t_dropgid.c test how to drop saved-gid for a set-group-ID program
t_exclopen.c test for security-defeating semantics that an open with
O_CREAT|O_EXCL set will successfully open a file named
by a symbolic link that to a non-existent file
-t_seteuid.c test whether seteuid works
-t_setgid.c test whether setgid works
-t_setreuid.c test whether setreuid works
-t_setuid.c test whether setuid works
+t_pathconf.c test whether pathconf(2) works
+t_seteuid.c test whether seteuid(2) works
+t_setgid.c test whether setgid(2) works
+t_setreuid.c test whether setreuid(2) works
+t_setuid.c test whether setuid(2) works
diff --git a/contrib/sendmail/vacation/vacation.1 b/contrib/sendmail/vacation/vacation.1
index 158fab1a7366..1da5c8def614 100644
--- a/contrib/sendmail/vacation/vacation.1
+++ b/contrib/sendmail/vacation/vacation.1
@@ -210,6 +210,12 @@ Sendmail(8)
includes this
``From''
line automatically.
+It also scans the headers for a
+``Return-Path:''
+header to determine the sender.
+If both are present, the sender from the
+``Return-Path:''
+header is used.
.PP
No message will be sent unless
.I login
@@ -234,10 +240,18 @@ or
``MAILER-DAEMON''
will be replied to (where these strings are
case insensitive) nor is a notification sent if a
-``Precedence: bulk''
+``Precedence: bulk'',
+``Precedence: list'',
or
``Precedence: junk''
line is included in the mail headers.
+Likewise, a response will not be sent if the headers contain a
+``Auto-Submitted:''
+header with any value except
+``no''
+or a
+``List-Id:''
+header is found.
The people who have sent you messages are maintained as a
db(3)
or
@@ -265,6 +279,15 @@ I am on vacation until July 22. If you have something urgent,
please contact Keith Bostic <bostic@CS.Berkeley.EDU>.
--eric
.fi
+.PP
+Any occurrence of the string
+``$SUBJECT''
+in
+.IR .vacation.msg
+will be replaced by the first line of the subject of the message
+that triggered the
+.B vacation
+program.
.SH FILES
.TP 1.8i
~/.vacation.db
diff --git a/contrib/sendmail/vacation/vacation.c b/contrib/sendmail/vacation/vacation.c
index 4ddd1a0e9bc2..6ef36602f2b5 100644
--- a/contrib/sendmail/vacation/vacation.c
+++ b/contrib/sendmail/vacation/vacation.c
@@ -22,7 +22,6 @@ SM_IDSTR(copyright,
SM_IDSTR(id, "@(#)$Id: vacation.c,v 8.148 2013-11-22 20:52:02 ca Exp $")
-
#include <ctype.h>
#include <stdlib.h>
#include <syslog.h>
@@ -86,6 +85,7 @@ ALIAS *Names = NULL;
SMDB_DATABASE *Db;
char From[MAXLINE];
+char Subject[MAXLINE];
bool CloseMBDB = false;
#if defined(__hpux) || defined(__osf__)
@@ -185,7 +185,7 @@ main(argc, argv)
exclude = false;
interval = INTERVAL_UNDEF;
*From = '\0';
-
+ *Subject = '\0';
#define OPTIONS "a:C:df:Iijlm:R:r:s:t:Uxz"
@@ -281,7 +281,7 @@ main(argc, argv)
if (mfail != 0)
{
msglog(LOG_NOTICE,
- "vacation: can't allocate memory for alias.\n");
+ "vacation: can't allocate memory for alias");
EXITM(EX_TEMPFAIL);
}
if (ufail != 0)
@@ -294,7 +294,7 @@ main(argc, argv)
if ((pw = getpwuid(getuid())) == NULL)
{
msglog(LOG_ERR,
- "vacation: no such user uid %u.\n", getuid());
+ "vacation: no such user uid %u", getuid());
EXITM(EX_NOUSER);
}
name = strdup(pw->pw_name);
@@ -305,7 +305,7 @@ main(argc, argv)
if (chdir(pw->pw_dir) != 0)
{
msglog(LOG_NOTICE,
- "vacation: no such directory %s.\n",
+ "vacation: no such directory %s",
pw->pw_dir);
EXITM(EX_NOINPUT);
}
@@ -316,7 +316,7 @@ main(argc, argv)
if (dbfilename == NULL || msgfilename == NULL)
{
msglog(LOG_NOTICE,
- "vacation: -U requires setting both -f and -m\n");
+ "vacation: -U requires setting both -f and -m");
EXITM(EX_NOINPUT);
}
user_info.smdbu_id = pw->pw_uid;
@@ -338,7 +338,7 @@ main(argc, argv)
if (err != EX_OK)
{
msglog(LOG_ERR,
- "vacation: can't open mailbox database: %s.\n",
+ "vacation: can't open mailbox database: %s",
sm_strexit(err));
EXITM(err);
}
@@ -346,13 +346,13 @@ main(argc, argv)
err = sm_mbdb_lookup(*argv, &user);
if (err == EX_NOUSER)
{
- msglog(LOG_ERR, "vacation: no such user %s.\n", *argv);
+ msglog(LOG_ERR, "vacation: no such user %s", *argv);
EXITM(EX_NOUSER);
}
if (err != EX_OK)
{
msglog(LOG_ERR,
- "vacation: can't read mailbox database: %s.\n",
+ "vacation: can't read mailbox database: %s",
sm_strexit(err));
EXITM(err);
}
@@ -360,7 +360,7 @@ main(argc, argv)
if (chdir(user.mbdb_homedir) != 0)
{
msglog(LOG_NOTICE,
- "vacation: no such directory %s.\n",
+ "vacation: no such directory %s",
user.mbdb_homedir);
EXITM(EX_NOINPUT);
}
@@ -372,7 +372,7 @@ main(argc, argv)
if (name == NULL)
{
msglog(LOG_ERR,
- "vacation: can't allocate memory for username.\n");
+ "vacation: can't allocate memory for username");
EXITM(EX_OSERR);
}
@@ -397,14 +397,13 @@ main(argc, argv)
sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY;
}
-
result = smdb_open_database(&Db, dbfilename,
O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0),
S_IRUSR|S_IWUSR, sff,
SMDB_TYPE_DEFAULT, &user_info, NULL);
if (result != SMDBE_OK)
{
- msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename,
+ msglog(LOG_NOTICE, "vacation: %s: %s", dbfilename,
sm_errstring(result));
EXITM(EX_DATAERR);
}
@@ -435,7 +434,7 @@ main(argc, argv)
if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL)
{
msglog(LOG_NOTICE,
- "vacation: can't allocate memory for username.\n");
+ "vacation: can't allocate memory for username");
(void) Db->smdb_close(Db);
EXITM(EX_OSERR);
}
@@ -461,14 +460,13 @@ main(argc, argv)
}
/*
-** EATMSG -- read stdin till EOF
+** EATMSG -- read stdin till EOF
**
** Parameters:
** none.
**
** Returns:
** nothing.
-**
*/
static void
@@ -483,7 +481,7 @@ eatmsg()
}
/*
-** READHEADERS -- read mail headers
+** READHEADERS -- read mail headers
**
** Parameters:
** alwaysrespond -- respond regardless of whether msg is to me
@@ -493,15 +491,49 @@ eatmsg()
**
** Side Effects:
** may exit().
-**
*/
+#define CLEANADDR(addr, type) \
+{ \
+ bool quoted = false; \
+ \
+ while (*addr != '\0') \
+ { \
+ /* escaped character */ \
+ if (*addr == '\\') \
+ { \
+ addr++; \
+ if (*addr == '\0') \
+ { \
+ msglog(LOG_NOTICE, \
+ "vacation: badly formatted \"%s\" line",\
+ type); \
+ EXITIT(EX_DATAERR); \
+ } \
+ } \
+ else if (*addr == '"') \
+ quoted = !quoted; \
+ else if (*addr == '\r' || *addr == '\n') \
+ break; \
+ else if (*addr == ' ' && !quoted) \
+ break; \
+ addr++; \
+ } \
+ if (quoted) \
+ { \
+ msglog(LOG_NOTICE, \
+ "vacation: badly formatted \"%s\" line", type); \
+ EXITIT(EX_DATAERR); \
+ } \
+ *addr = '\0'; \
+}
+
static int
readheaders(alwaysrespond)
bool alwaysrespond;
{
bool tome, cont;
- register char *p;
+ register char *p, *s;
register ALIAS *cur;
char buf[MAXLINE];
@@ -512,41 +544,33 @@ readheaders(alwaysrespond)
{
switch(*buf)
{
+ case 'A': /* "Auto-Submitted:" */
+ case 'a':
+ cont = false;
+ if (strlen(buf) <= 14 ||
+ strncasecmp(buf, "Auto-Submitted", 14) != 0 ||
+ (buf[14] != ':' && buf[14] != ' ' &&
+ buf[14] != '\t'))
+ break;
+ if ((p = strchr(buf, ':')) == NULL)
+ break;
+ while (*++p != '\0' && isascii(*p) && isspace(*p))
+ continue;
+ if (*p == '\0')
+ break;
+ if ((s = strpbrk(p, " \t\r\n")) != NULL)
+ *s = '\0';
+ /* Obey RFC3834: no auto-reply for auto-submitted mail */
+ if (strcasecmp(p, "no") != 0)
+ EXITIT(EX_NOUSER);
+ break;
+
case 'F': /* "From " */
cont = false;
if (strncmp(buf, "From ", 5) == 0)
{
- bool quoted = false;
-
p = buf + 5;
- while (*p != '\0')
- {
- /* escaped character */
- if (*p == '\\')
- {
- p++;
- if (*p == '\0')
- {
- msglog(LOG_NOTICE,
- "vacation: badly formatted \"From \" line.\n");
- EXITIT(EX_DATAERR);
- }
- }
- else if (*p == '"')
- quoted = !quoted;
- else if (*p == '\r' || *p == '\n')
- break;
- else if (*p == ' ' && !quoted)
- break;
- p++;
- }
- if (quoted)
- {
- msglog(LOG_NOTICE,
- "vacation: badly formatted \"From \" line.\n");
- EXITIT(EX_DATAERR);
- }
- *p = '\0';
+ CLEANADDR(p, "From ");
/* ok since both strings have MAXLINE length */
if (*From == '\0')
@@ -559,6 +583,23 @@ readheaders(alwaysrespond)
}
break;
+ case 'L': /* "List-Id:" */
+ case 'l':
+ cont = false;
+ if (strlen(buf) <= 7 ||
+ strncasecmp(buf, "List-Id", 7) != 0 ||
+ (buf[7] != ':' && buf[7] != ' ' &&
+ buf[7] != '\t'))
+ break;
+ if ((p = strchr(buf, ':')) == NULL)
+ break;
+
+ /* If we found a List-Id: header, don't send a reply */
+ EXITIT(EX_NOUSER);
+
+ /* NOTREACHED */
+ break;
+
case 'P': /* "Precedence:" */
case 'p':
cont = false;
@@ -569,7 +610,8 @@ readheaders(alwaysrespond)
break;
if ((p = strchr(buf, ':')) == NULL)
break;
- while (*++p != '\0' && isascii(*p) && isspace(*p));
+ while (*++p != '\0' && isascii(*p) && isspace(*p))
+ continue;
if (*p == '\0')
break;
if (strncasecmp(p, "junk", 4) == 0 ||
@@ -578,6 +620,46 @@ readheaders(alwaysrespond)
EXITIT(EX_NOUSER);
break;
+ case 'R': /* Return-Path */
+ case 'r':
+ cont = false;
+ if (strlen(buf) <= 11 ||
+ strncasecmp(buf, "Return-Path", 11) != 0 ||
+ (buf[11] != ':' && buf[11] != ' ' &&
+ buf[11] != '\t'))
+ break;
+ if ((p = strchr(buf, ':')) == NULL)
+ break;
+ while (*++p != '\0' && isascii(*p) && isspace(*p))
+ continue;
+ if (*p == '\0')
+ break;
+ (void) sm_strlcpy(From, p, sizeof From);
+ p = From;
+ CLEANADDR(p, "Return-Path:");
+ if (junkmail(From))
+ EXITIT(EX_NOUSER);
+ break;
+
+ case 'S': /* Subject */
+ case 's':
+ cont = false;
+ if (strlen(buf) <= 7 ||
+ strncasecmp(buf, "Subject", 7) != 0 ||
+ (buf[7] != ':' && buf[7] != ' ' &&
+ buf[7] != '\t'))
+ break;
+ if ((p = strchr(buf, ':')) == NULL)
+ break;
+ while (*++p != '\0' && isascii(*p) && isspace(*p))
+ continue;
+ if (*p == '\0')
+ break;
+ (void) sm_strlcpy(Subject, p, sizeof Subject);
+ if ((s = strpbrk(Subject, "\r\n")) != NULL)
+ *s = '\0';
+ break;
+
case 'C': /* "Cc:" */
case 'c':
if (strncasecmp(buf, "Cc:", 3) != 0)
@@ -609,15 +691,14 @@ findme:
EXITIT(EX_NOUSER);
if (*From == '\0')
{
- msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n");
+ msglog(LOG_NOTICE, "vacation: no initial \"From \" line");
EXITIT(EX_DATAERR);
}
EXITIT(EX_OK);
}
/*
-** NSEARCH --
-** do a nice, slow, search of a string for a substring.
+** NSEARCH -- do a nice, slow, search of a string for a substring.
**
** Parameters:
** name -- name to search.
@@ -625,7 +706,6 @@ findme:
**
** Returns:
** is name a substring of str?
-**
*/
static bool
@@ -657,15 +737,13 @@ nsearch(name, str)
}
/*
-** JUNKMAIL --
-** read the header and return if automagic/junk/bulk/list mail
+** JUNKMAIL -- read the header and return if automagic/junk/bulk/list mail
**
** Parameters:
** from -- sender address.
**
** Returns:
** is this some automated/junk/bulk/list mail?
-**
*/
struct ignore
@@ -808,15 +886,13 @@ junkmail(from)
#define VIT "__VACATION__INTERVAL__TIMER__"
/*
-** RECENT --
-** find out if user has gotten a vacation message recently.
+** RECENT -- find out if user has gotten a vacation message recently.
**
** Parameters:
** none.
**
** Returns:
** true iff user has gotten a vacation message recently.
-**
*/
static bool
@@ -868,8 +944,7 @@ recent()
}
/*
-** SETINTERVAL --
-** store the reply interval
+** SETINTERVAL -- store the reply interval
**
** Parameters:
** interval -- time interval for replies.
@@ -898,8 +973,7 @@ setinterval(interval)
}
/*
-** SETREPLY --
-** store that this user knows about the vacation.
+** SETREPLY -- store that this user knows about the vacation.
**
** Parameters:
** from -- sender address.
@@ -930,8 +1004,7 @@ setreply(from, when)
}
/*
-** XCLUDE --
-** add users to vacation db so they don't get a reply.
+** XCLUDE -- add users to vacation db so they don't get a reply.
**
** Parameters:
** f -- file pointer with list of address to exclude
@@ -960,8 +1033,7 @@ xclude(f)
}
/*
-** SENDMESSAGE --
-** exec sendmail to send the vacation file to sender
+** SENDMESSAGE -- exec sendmail to send the vacation file to sender
**
** Parameters:
** myname -- user name.
@@ -984,6 +1056,7 @@ sendmessage(myname, msgfn, sender)
SM_FILE_T *mfp, *sfp;
int i;
int pvect[2];
+ char *s;
char *pv[8];
char buf[MAXLINE];
@@ -991,9 +1064,9 @@ sendmessage(myname, msgfn, sender)
if (mfp == NULL)
{
if (msgfn[0] == '/')
- msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn);
+ msglog(LOG_NOTICE, "vacation: no %s file", msgfn);
else
- msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n",
+ msglog(LOG_NOTICE, "vacation: no ~%s/%s file",
myname, msgfn);
exit(EX_NOINPUT);
}
@@ -1047,7 +1120,17 @@ sendmessage(myname, msgfn, sender)
(void) sm_io_fprintf(sfp, SM_TIME_DEFAULT,
"Auto-Submitted: auto-replied\n");
while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf) >= 0)
- (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf);
+ {
+ if ((s = strstr(buf, "$SUBJECT")) != NULL)
+ {
+ *s = '\0';
+ (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf);
+ (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, Subject);
+ (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, s + 8);
+ }
+ else
+ (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf);
+ }
(void) sm_io_close(mfp, SM_TIME_DEFAULT);
(void) sm_io_close(sfp, SM_TIME_DEFAULT);
#if _FFR_VAC_WAIT4SM
@@ -1066,13 +1149,13 @@ static void
usage()
{
msglog(LOG_NOTICE,
- "uid %u: usage: vacation [-a alias] [-C cfpath] [-d] [-f db] [-i] [-j] [-l] [-m msg] [-R returnaddr] [-r interval] [-s sender] [-t time] [-U] [-x] [-z] login\n",
+ "uid %u: usage: vacation [-a alias] [-C cfpath] [-d] [-f db] [-i] [-j] [-l] [-m msg] [-R returnaddr] [-r interval] [-s sender] [-t time] [-U] [-x] [-z] login",
getuid());
exit(EX_USAGE);
}
/*
-** LISTDB -- list the contents of the vacation database
+** LISTDB -- list the contents of the vacation database
**
** Parameters:
** none.
@@ -1160,7 +1243,7 @@ listdb()
}
/*
-** DEBUGLOG -- write message to standard error
+** DEBUGLOG -- write message to standard error
**
** Append a message to the standard error for the convenience of
** end-users debugging without access to the syslog messages.
@@ -1190,5 +1273,6 @@ debuglog(i, fmt, va_alist)
SM_VA_START(ap, fmt);
sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap);
SM_VA_END(ap);
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\n");
SYSLOG_RET;
}
diff --git a/etc/sendmail/freebsd.mc b/etc/sendmail/freebsd.mc
index cf80a3133c74..1d9ca3272c0b 100644
--- a/etc/sendmail/freebsd.mc
+++ b/etc/sendmail/freebsd.mc
@@ -46,6 +46,7 @@ divert(-1)
# and owner of the SSL certificates and keys in /etc/mail/certs to be usable
# by that user.
#
+# Last updated: 2024-02-01
divert(0)
OSTYPE(freebsd6)
diff --git a/etc/sendmail/freebsd.submit.mc b/etc/sendmail/freebsd.submit.mc
index e14a6bc56500..0cee55610b1f 100644
--- a/etc/sendmail/freebsd.submit.mc
+++ b/etc/sendmail/freebsd.submit.mc
@@ -12,6 +12,7 @@ divert(-1)
# This is the FreeBSD configuration for a set-group-ID sm-msp sendmail
# that acts as a initial mail submission program.
#
+# Last updated: 2024-02-01
divert(0)dnl
define(`confCF_VERSION', `Submit')dnl
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index c7e248ad538b..4b78c655f73c 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -7845,6 +7845,7 @@ OLD_FILES+=usr/share/sendmail/cf/feature/delay_checks.m4
OLD_FILES+=usr/share/sendmail/cf/feature/dnsbl.m4
OLD_FILES+=usr/share/sendmail/cf/feature/domaintable.m4
OLD_FILES+=usr/share/sendmail/cf/feature/enhdnsbl.m4
+OLD_FILES+=usr/share/sendmail/cf/feature/fips3.m4
OLD_FILES+=usr/share/sendmail/cf/feature/generics_entire_domain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/genericstable.m4
OLD_FILES+=usr/share/sendmail/cf/feature/greet_pause.m4
diff --git a/usr.sbin/sendmail/Makefile b/usr.sbin/sendmail/Makefile
index b71e1ab07d20..5f0f5de1b175 100644
--- a/usr.sbin/sendmail/Makefile
+++ b/usr.sbin/sendmail/Makefile
@@ -16,7 +16,7 @@ MLINKS+=sendmail.8 purgestat.8
SRCS= alias.c arpadate.c bf.c collect.c conf.c control.c \
convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c \
macro.c main.c map.c mci.c milter.c mime.c parseaddr.c queue.c \
- ratectrl.c readcf.c recipient.c savemail.c sasl.c sfsasl.c \
+ ratectrl.c readcf.c recipient.c savemail.c sasl.c sched.c sfsasl.c \
shmticklib.c sm_resolve.c srvrsmtp.c stab.c stats.c sysexits.c \
timers.c tlsh.c tls.c trace.c udb.c usersmtp.c util.c version.c
BINOWN= root