mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-01 14:45:32 +00:00
postfix-2.12-20150118
This commit is contained in:
committed by
Viktor Dukhovni
parent
07c5e9a196
commit
5c187bc356
110
postfix/HISTORY
110
postfix/HISTORY
@@ -11196,7 +11196,7 @@ Apologies for any names omitted.
|
|||||||
in the anvil server, TLS request rate error message in the
|
in the anvil server, TLS request rate error message in the
|
||||||
smtp server, and documentation, but no changes in code.
|
smtp server, and documentation, but no changes in code.
|
||||||
Files: anvil/anvil.c, smtpd/smtpd.c.
|
Files: anvil/anvil.c, smtpd/smtpd.c.
|
||||||
|
|
||||||
20051013
|
20051013
|
||||||
|
|
||||||
Horror: some systems have basename() and dirname() and some
|
Horror: some systems have basename() and dirname() and some
|
||||||
@@ -19583,8 +19583,8 @@ Apologies for any names omitted.
|
|||||||
smtp/smtp.h, smtp/smtp_rcpt.c.
|
smtp/smtp.h, smtp/smtp_rcpt.c.
|
||||||
|
|
||||||
Logging: the TLS client logged that an "Untrusted" TLS
|
Logging: the TLS client logged that an "Untrusted" TLS
|
||||||
connection was established instead of "Anonymous".
|
connection was established instead of "Anonymous". Viktor
|
||||||
Viktor Dukhovni. File: tls/tls_client.c.
|
Dukhovni. File: tls/tls_client.c.
|
||||||
|
|
||||||
Documentation: new self-signed certificate example and
|
Documentation: new self-signed certificate example and
|
||||||
updated private CA example. File: proto/TLS_README.html.
|
updated private CA example. File: proto/TLS_README.html.
|
||||||
@@ -19662,7 +19662,7 @@ Apologies for any names omitted.
|
|||||||
20140323
|
20140323
|
||||||
|
|
||||||
Feature: initial merge of Debian-style dynamic linking.
|
Feature: initial merge of Debian-style dynamic linking.
|
||||||
Viktor Dukhovni.
|
Viktor Dukhovni.
|
||||||
|
|
||||||
20140406
|
20140406
|
||||||
|
|
||||||
@@ -19755,8 +19755,8 @@ Apologies for any names omitted.
|
|||||||
20140508
|
20140508
|
||||||
|
|
||||||
Cleanup: dynamicmaps.cf is now installed into $daemon_directory
|
Cleanup: dynamicmaps.cf is now installed into $daemon_directory
|
||||||
because the file is shared among Postfix instances just like
|
because the file is shared among Postfix instances just
|
||||||
postfix-files and other files. Files: conf/dynamicmaps.cf,
|
like postfix-files and other files. Files: conf/dynamicmaps.cf,
|
||||||
Makefile.in, conf/postfix-files.
|
Makefile.in, conf/postfix-files.
|
||||||
|
|
||||||
Cleanup: INSTALL is now plain ASCII instead of README format,
|
Cleanup: INSTALL is now plain ASCII instead of README format,
|
||||||
@@ -19807,11 +19807,11 @@ Apologies for any names omitted.
|
|||||||
Support for "make shared=yes" and "make dynamicmaps=yes".
|
Support for "make shared=yes" and "make dynamicmaps=yes".
|
||||||
New plugin_directory parameter for the location of the
|
New plugin_directory parameter for the location of the
|
||||||
dynamicmaps.cf file and for plugins with a relative pathname.
|
dynamicmaps.cf file and for plugins with a relative pathname.
|
||||||
See RELEASE_NOTES and INSTALL for details. Files:
|
See RELEASE_NOTES and INSTALL for details. Files: postfix.c,
|
||||||
postfix.c, mail_params.[hc], dynamicmaps.c, mail_dict.c,
|
mail_params.[hc], dynamicmaps.c, mail_dict.c, makedefs,
|
||||||
makedefs, postfix-files, dynamicmaps.cf, Makefile.in,
|
postfix-files, dynamicmaps.cf, Makefile.in, util/Makefile.in,
|
||||||
util/Makefile.in, global/Makefile.in, postlink, postconf.proto.
|
global/Makefile.in, postlink, postconf.proto. INSTALL.html,
|
||||||
INSTALL.html, RELEASE_NOTES.
|
RELEASE_NOTES.
|
||||||
|
|
||||||
20140523
|
20140523
|
||||||
|
|
||||||
@@ -20243,9 +20243,9 @@ Apologies for any names omitted.
|
|||||||
Cleanup: change extract_addr() API to indicate that an
|
Cleanup: change extract_addr() API to indicate that an
|
||||||
address is parsed in SMTPUTF8 context. File: smtpd/smtpd.c.
|
address is parsed in SMTPUTF8 context. File: smtpd/smtpd.c.
|
||||||
|
|
||||||
Cleanup: shared-library build fixes. Viktor Dukhovni.
|
Cleanup: shared-library build fixes. Viktor Dukhovni. Files:
|
||||||
Files: makedefs, dns/Makefile.in, global/Makefile.in,
|
makedefs, dns/Makefile.in, global/Makefile.in, master/Makefile.in,
|
||||||
master/Makefile.in, tls/Makefile.in, util/Makefile.in.
|
tls/Makefile.in, util/Makefile.in.
|
||||||
|
|
||||||
First general release with SMTPUTF8 support; see RELEASE_NOTES
|
First general release with SMTPUTF8 support; see RELEASE_NOTES
|
||||||
for an initial writeup. The last pre-SMTPUTF8 release is
|
for an initial writeup. The last pre-SMTPUTF8 release is
|
||||||
@@ -20317,8 +20317,8 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20140731
|
20140731
|
||||||
|
|
||||||
Feature: the Postfix SMTP server now logs at the end of
|
Feature: the Postfix SMTP server now logs at the end of a
|
||||||
a session how many times each SMTP command was successfully
|
session how many times each SMTP command was successfully
|
||||||
invoked, followed by the total number of invocations if it
|
invoked, followed by the total number of invocations if it
|
||||||
is different. File: smtpd/smtpd.c.
|
is different. File: smtpd/smtpd.c.
|
||||||
|
|
||||||
@@ -20431,7 +20431,7 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Cleanup: dict_db and dict_lmdb global settings. Files:
|
Cleanup: dict_db and dict_lmdb global settings. Files:
|
||||||
global/mail_params.c, util/dict_open.c.
|
global/mail_params.c, util/dict_open.c.
|
||||||
|
|
||||||
Feature: unionmap, based on contribution by Roel van Meer.
|
Feature: unionmap, based on contribution by Roel van Meer.
|
||||||
Files: mantools/postlink, postconf/postconf.c (manpage),
|
Files: mantools/postlink, postconf/postconf.c (manpage),
|
||||||
proto/DATABASE_README.html, util/dict_open.c, util/dict_union.[hc].
|
proto/DATABASE_README.html, util/dict_open.c, util/dict_union.[hc].
|
||||||
@@ -20461,9 +20461,9 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20140927
|
20140927
|
||||||
|
|
||||||
Cleanup: specify { name = value } in per-Milter settings, to support
|
Cleanup: specify { name = value } in per-Milter settings,
|
||||||
space around the "=" or comma/space within the value. Files:
|
to support space around the "=" or comma/space within the
|
||||||
global/attr_over.[hc].
|
value. Files: global/attr_over.[hc].
|
||||||
|
|
||||||
Cleanup: "postconf -n" now only shows config_directory when
|
Cleanup: "postconf -n" now only shows config_directory when
|
||||||
an override is in effect (environment, -c or -o).
|
an override is in effect (environment, -c or -o).
|
||||||
@@ -20504,15 +20504,14 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Cleanup: force LANG=C to prevent groff from outputting
|
Cleanup: force LANG=C to prevent groff from outputting
|
||||||
non-ASCII cruft into the HTML-ized manpages. Files:
|
non-ASCII cruft into the HTML-ized manpages. Files:
|
||||||
html/Makefile.in, proto/Makefile.in, many HTML output
|
html/Makefile.in, proto/Makefile.in, many HTML output files.
|
||||||
files.
|
|
||||||
|
|
||||||
20140929
|
20140929
|
||||||
|
|
||||||
Cleanup: the table-driven code for per-Milter and per-policy
|
Cleanup: the table-driven code for per-Milter and per-policy
|
||||||
overrides now updates arbitrary variables, so that it can also
|
overrides now updates arbitrary variables, so that it can
|
||||||
be used for, say, TLS policies. Files: global/attr_override.[hc],
|
also be used for, say, TLS policies. Files:
|
||||||
smtpd/smtpd_check.c, milter/milter.c.
|
global/attr_override.[hc], smtpd/smtpd_check.c, milter/milter.c.
|
||||||
|
|
||||||
Documentation: support for "{ argument with whitespace }"
|
Documentation: support for "{ argument with whitespace }"
|
||||||
in master(5) and pipe(8). Files: proto/master, src/pipe/pipe.c.
|
in master(5) and pipe(8). Files: proto/master, src/pipe/pipe.c.
|
||||||
@@ -20524,12 +20523,12 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20141001
|
20141001
|
||||||
|
|
||||||
Safety: backwards-compatibility safety net that forces Postfix
|
Safety: backwards-compatibility safety net that forces
|
||||||
to run with backwards-compatible default settings after an
|
Postfix to run with backwards-compatible default settings
|
||||||
upgrade to a newer Postfix version. Postfix logs all uses
|
after an upgrade to a newer Postfix version. Postfix logs
|
||||||
of those backwards-compatible default settings so that the
|
all uses of those backwards-compatible default settings so
|
||||||
system administator can determine whether or not some
|
that the system administator can determine whether or not
|
||||||
backwards-compatible default settings need to be made
|
some backwards-compatible default settings need to be made
|
||||||
permanent in main.cf or master.cf. All this is controlled
|
permanent in main.cf or master.cf. All this is controlled
|
||||||
with a new compatibility_level parameter, default value 0.
|
with a new compatibility_level parameter, default value 0.
|
||||||
Files: global/mail_params.[hc], trivial-rewrite/rewrite.c,
|
Files: global/mail_params.[hc], trivial-rewrite/rewrite.c,
|
||||||
@@ -20556,9 +20555,9 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20141003
|
20141003
|
||||||
|
|
||||||
Workaround: kludge for multiple paragraphs of text in indented
|
Workaround: kludge for multiple paragraphs of text in
|
||||||
paragraphs. Files: mantools/postconf2html, mantools/postconf2man,
|
indented paragraphs. Files: mantools/postconf2html,
|
||||||
proto/Makefile.in, proto/postconf.proto
|
mantools/postconf2man, proto/Makefile.in, proto/postconf.proto
|
||||||
|
|
||||||
20141005
|
20141005
|
||||||
|
|
||||||
@@ -20605,8 +20604,9 @@ Apologies for any names omitted.
|
|||||||
a new COMPATIBILITY_README document. Files: proto/postconf.proto,
|
a new COMPATIBILITY_README document. Files: proto/postconf.proto,
|
||||||
proto/COMPATIBILITY_README.html html/index.html.
|
proto/COMPATIBILITY_README.html html/index.html.
|
||||||
|
|
||||||
Documentation: update the conf/main.cf compatibility_level setting
|
Documentation: update the conf/main.cf compatibility_level
|
||||||
for new Postfix installs, and updated a reminder in mail_params.h.
|
setting for new Postfix installs, and updated a reminder
|
||||||
|
in mail_params.h.
|
||||||
|
|
||||||
20141010
|
20141010
|
||||||
|
|
||||||
@@ -20898,7 +20898,7 @@ Apologies for any names omitted.
|
|||||||
about that later. Files: smtpd/smtpd_check.c, smtp/smtp_addr.c,
|
about that later. Files: smtpd/smtpd_check.c, smtp/smtp_addr.c,
|
||||||
dns/dns.h, dns/dns_lookup.c.
|
dns/dns.h, dns/dns_lookup.c.
|
||||||
|
|
||||||
Cleanup: eliminate TLS state duplication from state->tls
|
Cleanup: eliminate TLS state duplication from state->tls
|
||||||
to session->tls. Viktor Dukhovni. Files: src/smtp/smtp.h,
|
to session->tls. Viktor Dukhovni. Files: src/smtp/smtp.h,
|
||||||
src/smtp/smtp_connect.c, src/smtp/smtp_proto.c,
|
src/smtp/smtp_connect.c, src/smtp/smtp_proto.c,
|
||||||
src/smtp/smtp_reuse.c, src/smtp/smtp_session.c.
|
src/smtp/smtp_reuse.c, src/smtp/smtp_session.c.
|
||||||
@@ -21011,8 +21011,8 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20141208
|
20141208
|
||||||
|
|
||||||
Bugfix (introduced: 20141207): in new #ifdef, && should be ||.
|
Bugfix (introduced: 20141207): in new #ifdef, && should be
|
||||||
File: smtpd.c.
|
||. File: smtpd.c.
|
||||||
|
|
||||||
20141210
|
20141210
|
||||||
|
|
||||||
@@ -21180,7 +21180,7 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Cleanup: instead of making up new names, use a consistent
|
Cleanup: instead of making up new names, use a consistent
|
||||||
CA_ prefix for macros that implement compile-time argument
|
CA_ prefix for macros that implement compile-time argument
|
||||||
typechecks for non-protocol attribute-value APIs. This
|
typechecks for non-protocol attribute-value APIs. This
|
||||||
transformation and its verification are mechanical.
|
transformation and its verification are mechanical.
|
||||||
|
|
||||||
Bugfix (introduced: Postfix 1.1, but latent before 2.12):
|
Bugfix (introduced: Postfix 1.1, but latent before 2.12):
|
||||||
@@ -21204,11 +21204,11 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20141228
|
20141228
|
||||||
|
|
||||||
Cleanup: the IDNA conversion routines now accept both
|
Cleanup: the IDNA conversion routines now accept both ASCII
|
||||||
ASCII and UTF8 inputs. The functions als verify that
|
and UTF8 inputs. The functions als verify that either their
|
||||||
either their result is a valid ASCII domain name or that
|
result is a valid ASCII domain name or that it converts
|
||||||
it converts into a valid ASCII domain name. Files:
|
into a valid ASCII domain name. Files: util/midna.c,
|
||||||
util/midna.c, util/midna_test.in, util/midna_test.ref.
|
util/midna_test.in, util/midna_test.ref.
|
||||||
|
|
||||||
20141230
|
20141230
|
||||||
|
|
||||||
@@ -21238,9 +21238,10 @@ Apologies for any names omitted.
|
|||||||
byte values, and UTF-8 case folding. As recommended at
|
byte values, and UTF-8 case folding. As recommended at
|
||||||
http://www.w3.org/International/wiki/Case_folding for
|
http://www.w3.org/International/wiki/Case_folding for
|
||||||
caseless string comparison, this uses the en_US locale to
|
caseless string comparison, this uses the en_US locale to
|
||||||
avoid surprises. The implementatin handles
|
avoid surprises. The implementatin handles the entire RFC
|
||||||
the entire RFC 3629 Unicode range (code points U+0000..U+10FFFF
|
3629 Unicode range (code points U+0000..U+10FFFF including
|
||||||
including surrogates) and is chroot(2) safe. Files: casefold.c, stringops.h.
|
surrogates) and is chroot(2) safe. Files: casefold.c,
|
||||||
|
stringops.h.
|
||||||
|
|
||||||
Infrastructure: revised the midna_domain_to_ascii and
|
Infrastructure: revised the midna_domain_to_ascii and
|
||||||
midna_domain_to_utf8 domain name conversion functions after
|
midna_domain_to_utf8 domain name conversion functions after
|
||||||
@@ -21412,3 +21413,16 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Cleanup: missing " in \%s\" in postscreen(8) fatal error
|
Cleanup: missing " in \%s\" in postscreen(8) fatal error
|
||||||
messages. Iain Hibbert. File: postconf/postconf_master.c.
|
messages. Iain Hibbert. File: postconf/postconf_master.c.
|
||||||
|
|
||||||
|
20150118
|
||||||
|
|
||||||
|
Bugfix (introduced: 20140731): when a connection timed out
|
||||||
|
before any command was received, the Postfix SMTP server
|
||||||
|
"disconnect from" logging would show the content of the
|
||||||
|
last SMTP server response (421 4.4.2 $myhostname error:
|
||||||
|
timeout exceeded) instead of per-command statistics, because
|
||||||
|
there were no statistics to report. The Postfix SMTP server
|
||||||
|
now always logs the total number of commands (commands=x/y)
|
||||||
|
even when the client did not send any. This helps logfile
|
||||||
|
analyzers to recognize sessions without commands. File:
|
||||||
|
smtpd/smtpd.c.
|
||||||
|
@@ -151,9 +151,11 @@ provide ETRN service for that domain, then the system administrator should make
|
|||||||
the backwards-compatible setting "relay_domains = $mydestination" permanent in
|
the backwards-compatible setting "relay_domains = $mydestination" permanent in
|
||||||
main.cf:
|
main.cf:
|
||||||
|
|
||||||
# ppoossttccoonnff rreellaayy__ddoommaaiinnss==$$mmyyddeessttiinnaattiioonn
|
# ppoossttccoonnff ''rreellaayy__ddoommaaiinnss==$$mmyyddeessttiinnaattiioonn''
|
||||||
# ppoossttffiixx rreellooaadd
|
# ppoossttffiixx rreellooaadd
|
||||||
|
|
||||||
|
Note: quotes are required as indicated above.
|
||||||
|
|
||||||
Instead of $mydestination, it may be better to specify an explicit list of
|
Instead of $mydestination, it may be better to specify an explicit list of
|
||||||
domain names.
|
domain names.
|
||||||
|
|
||||||
|
@@ -8,6 +8,12 @@ Wish list:
|
|||||||
|
|
||||||
Things to do after the stable release:
|
Things to do after the stable release:
|
||||||
|
|
||||||
|
postconf -P: emit '{ name = value }' when editing/adding a
|
||||||
|
parameter whose new value contains whitespace.
|
||||||
|
|
||||||
|
In release-notes add commands=x/y logging to the command
|
||||||
|
statistics.
|
||||||
|
|
||||||
UTF8 DNS[BW]L domain name.
|
UTF8 DNS[BW]L domain name.
|
||||||
|
|
||||||
Consolidate maps flags in mail_params.h instead of having
|
Consolidate maps flags in mail_params.h instead of having
|
||||||
|
@@ -253,11 +253,13 @@ administrator should make the backwards-compatible setting
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<pre>
|
||||||
# <b>postconf <a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a></b>
|
# <b>postconf '<a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a>'</b>
|
||||||
# <b>postfix reload</b>
|
# <b>postfix reload</b>
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
<p> Note: quotes are required as indicated above. </p>
|
||||||
|
|
||||||
<p> Instead of $<a href="postconf.5.html#mydestination">mydestination</a>, it may be better to specify an
|
<p> Instead of $<a href="postconf.5.html#mydestination">mydestination</a>, it may be better to specify an
|
||||||
explicit list of domain names. </p>
|
explicit list of domain names. </p>
|
||||||
|
|
||||||
|
@@ -253,11 +253,13 @@ administrator should make the backwards-compatible setting
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<pre>
|
||||||
# <b>postconf relay_domains=$mydestination</b>
|
# <b>postconf 'relay_domains=$mydestination'</b>
|
||||||
# <b>postfix reload</b>
|
# <b>postfix reload</b>
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
<p> Note: quotes are required as indicated above. </p>
|
||||||
|
|
||||||
<p> Instead of $mydestination, it may be better to specify an
|
<p> Instead of $mydestination, it may be better to specify an
|
||||||
explicit list of domain names. </p>
|
explicit list of domain names. </p>
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||||
* patchlevel; they change the release date only.
|
* patchlevel; they change the release date only.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20150117"
|
#define MAIL_RELEASE_DATE "20150118"
|
||||||
#define MAIL_VERSION_NUMBER "2.12"
|
#define MAIL_VERSION_NUMBER "2.12"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
|
@@ -228,6 +228,12 @@
|
|||||||
/* .IP "\fB-v\fR"
|
/* .IP "\fB-v\fR"
|
||||||
/* Enable verose Postfix logging. Specify more than once to increase
|
/* Enable verose Postfix logging. Specify more than once to increase
|
||||||
/* the level of verbose logging.
|
/* the level of verbose logging.
|
||||||
|
/* .IP "\fB-w\fR"
|
||||||
|
/* Enable outgoing TLS wrapper mode, or SMTPS support. This is typically
|
||||||
|
/* provided on port 465 by servers that are compatible with the ad-hoc
|
||||||
|
/* SMTP in SSL protocol, rather than the standard STARTTLS protocol.
|
||||||
|
/* The destination \fIdomain\fR:\fIport\fR should of course provide such
|
||||||
|
/* a service.
|
||||||
/* .IP "[\fBinet:\fR]\fIdomain\fR[:\fIport\fR]"
|
/* .IP "[\fBinet:\fR]\fIdomain\fR[:\fIport\fR]"
|
||||||
/* Connect via TCP to domain \fIdomain\fR, port \fIport\fR. The default
|
/* Connect via TCP to domain \fIdomain\fR, port \fIport\fR. The default
|
||||||
/* port is \fBsmtp\fR (or 24 with LMTP). With SMTP an MX lookup is
|
/* port is \fBsmtp\fR (or 24 with LMTP). With SMTP an MX lookup is
|
||||||
@@ -421,6 +427,7 @@ typedef struct STATE {
|
|||||||
VSTRING *buffer; /* Response buffer */
|
VSTRING *buffer; /* Response buffer */
|
||||||
VSTREAM *stream; /* Open connection */
|
VSTREAM *stream; /* Open connection */
|
||||||
int level; /* TLS security level */
|
int level; /* TLS security level */
|
||||||
|
int wrapper_mode; /* SMTPS support */
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
char *mdalg; /* fingerprint digest algorithm */
|
char *mdalg; /* fingerprint digest algorithm */
|
||||||
char *CAfile; /* Trusted public CAs */
|
char *CAfile; /* Trusted public CAs */
|
||||||
@@ -547,6 +554,33 @@ static char *exception_text(int except)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* greeting - read server's 220 greeting */
|
||||||
|
|
||||||
|
static int greeting(STATE *state)
|
||||||
|
{
|
||||||
|
VSTREAM *stream = state->stream;
|
||||||
|
int except;
|
||||||
|
RESPONSE *resp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare for disaster.
|
||||||
|
*/
|
||||||
|
smtp_stream_setup(stream, conn_tmout, 1);
|
||||||
|
if ((except = vstream_setjmp(stream)) != 0) {
|
||||||
|
msg_info("%s while reading server greeting", exception_text(except));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read and parse the server's SMTP greeting banner.
|
||||||
|
*/
|
||||||
|
if (((resp = response(state, 1))->code / 100) != 2) {
|
||||||
|
msg_info("SMTP service not available: %d %s", resp->code, resp->str);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/* ehlo - send EHLO/LHLO */
|
/* ehlo - send EHLO/LHLO */
|
||||||
|
|
||||||
static RESPONSE *ehlo(STATE *state)
|
static RESPONSE *ehlo(STATE *state)
|
||||||
@@ -647,26 +681,27 @@ static int starttls(STATE *state)
|
|||||||
VSTREAM *stream = state->stream;
|
VSTREAM *stream = state->stream;
|
||||||
TLS_CLIENT_START_PROPS tls_props;
|
TLS_CLIENT_START_PROPS tls_props;
|
||||||
|
|
||||||
/* SMTP stream with deadline timeouts */
|
if (state->wrapper_mode == 0) {
|
||||||
smtp_stream_setup(stream, smtp_tmout, 1);
|
/* SMTP stream with deadline timeouts */
|
||||||
if ((except = vstream_setjmp(stream)) != 0) {
|
smtp_stream_setup(stream, smtp_tmout, 1);
|
||||||
msg_fatal("%s while sending STARTTLS", exception_text(except));
|
if ((except = vstream_setjmp(stream)) != 0) {
|
||||||
return (1);
|
msg_fatal("%s while sending STARTTLS", exception_text(except));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
command(state, state->pass == 1, "STARTTLS");
|
||||||
|
|
||||||
|
resp = response(state, state->pass == 1);
|
||||||
|
if (resp->code / 100 != 2) {
|
||||||
|
msg_info("STARTTLS rejected: %d %s", resp->code, resp->str);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Discard any plain-text data that may be piggybacked after the
|
||||||
|
* server's 220 STARTTLS reply. Should we abort the session instead?
|
||||||
|
*/
|
||||||
|
vstream_fpurge(stream, VSTREAM_PURGE_READ);
|
||||||
}
|
}
|
||||||
command(state, state->pass == 1, "STARTTLS");
|
|
||||||
|
|
||||||
resp = response(state, state->pass == 1);
|
|
||||||
if (resp->code / 100 != 2) {
|
|
||||||
msg_info("STARTTLS rejected: %d %s", resp->code, resp->str);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Discard any plain-text data that may be piggybacked after the server's
|
|
||||||
* 220 STARTTLS reply. Should we abort the session instead?
|
|
||||||
*/
|
|
||||||
vstream_fpurge(stream, VSTREAM_PURGE_READ);
|
|
||||||
|
|
||||||
#define ADD_EXCLUDE(vstr, str) \
|
#define ADD_EXCLUDE(vstr, str) \
|
||||||
do { \
|
do { \
|
||||||
if (*(str)) \
|
if (*(str)) \
|
||||||
@@ -718,6 +753,9 @@ static int starttls(STATE *state)
|
|||||||
state->stream = 0;
|
state->stream = 0;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
if (state->wrapper_mode && greeting(state) != 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
if (state->pass == 1) {
|
if (state->pass == 1) {
|
||||||
ehlo(state);
|
ehlo(state);
|
||||||
if (!TLS_CERT_IS_PRESENT(state->tls_context))
|
if (!TLS_CERT_IS_PRESENT(state->tls_context))
|
||||||
@@ -743,42 +781,27 @@ static int doproto(STATE *state)
|
|||||||
int except;
|
int except;
|
||||||
int n;
|
int n;
|
||||||
char *lines;
|
char *lines;
|
||||||
char *words;
|
char *words = 0;
|
||||||
char *word;
|
char *word;
|
||||||
|
|
||||||
/*
|
if (!state->wrapper_mode) {
|
||||||
* Prepare for disaster.
|
if (greeting(state) != 0)
|
||||||
*/
|
return (1);
|
||||||
smtp_stream_setup(stream, conn_tmout, 1);
|
if ((resp = ehlo(state)) == 0)
|
||||||
if ((except = vstream_setjmp(stream)) != 0)
|
return (1);
|
||||||
msg_fatal("%s while reading server greeting", exception_text(except));
|
|
||||||
|
|
||||||
/*
|
lines = resp->str;
|
||||||
* Read and parse the server's SMTP greeting banner.
|
for (n = 0; (words = mystrtok(&lines, "\n")) != 0; ++n) {
|
||||||
*/
|
if ((word = mystrtok(&words, " \t=")) != 0) {
|
||||||
if (((resp = response(state, 1))->code / 100) != 2) {
|
if (n == 0)
|
||||||
msg_info("SMTP service not available: %d %s", resp->code, resp->str);
|
state->helo = mystrdup(word);
|
||||||
return (1);
|
if (strcasecmp(word, "STARTTLS") == 0)
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
/*
|
|
||||||
* Send the standard greeting with our hostname
|
|
||||||
*/
|
|
||||||
if ((resp = ehlo(state)) == 0)
|
|
||||||
return (1);
|
|
||||||
|
|
||||||
lines = resp->str;
|
|
||||||
for (n = 0; (words = mystrtok(&lines, "\n")) != 0; ++n) {
|
|
||||||
if ((word = mystrtok(&words, " \t=")) != 0) {
|
|
||||||
if (n == 0)
|
|
||||||
state->helo = mystrdup(word);
|
|
||||||
if (strcasecmp(word, "STARTTLS") == 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
if (words && state->tls_ctx)
|
if ((state->wrapper_mode || words) && state->tls_ctx)
|
||||||
if (starttls(state))
|
if (starttls(state))
|
||||||
return (1);
|
return (1);
|
||||||
#endif
|
#endif
|
||||||
@@ -793,7 +816,6 @@ static int doproto(STATE *state)
|
|||||||
}
|
}
|
||||||
command(state, 1, "QUIT");
|
command(state, 1, "QUIT");
|
||||||
(void) response(state, 1);
|
(void) response(state, 1);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1191,7 +1213,7 @@ static int dane_host_level(STATE *state, DNS_RR *addr)
|
|||||||
int level = state->level;
|
int level = state->level;
|
||||||
|
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
if (level == TLS_LEV_DANE) {
|
if (TLS_DANE_BASED(level)) {
|
||||||
if (state->mx == 0 || state->mx->dnssec_valid) {
|
if (state->mx == 0 || state->mx->dnssec_valid) {
|
||||||
if (state->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE))
|
if (state->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE))
|
||||||
tls_dane_verbose(1);
|
tls_dane_verbose(1);
|
||||||
@@ -1214,7 +1236,8 @@ static int dane_host_level(STATE *state, DNS_RR *addr)
|
|||||||
HNAME(addr), ntohs(state->port));
|
HNAME(addr), ntohs(state->port));
|
||||||
level = TLS_LEV_INVALID;
|
level = TLS_LEV_INVALID;
|
||||||
} else if (tls_dane_notfound(state->ddane)
|
} else if (tls_dane_notfound(state->ddane)
|
||||||
|| tls_dane_unusable(state->ddane)) {
|
|| tls_dane_unusable(state->ddane)
|
||||||
|
|| level == TLS_LEV_DANE_ONLY) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("no %sTLSA records found, "
|
msg_info("no %sTLSA records found, "
|
||||||
"resorting to \"secure\"",
|
"resorting to \"secure\"",
|
||||||
@@ -1223,7 +1246,7 @@ static int dane_host_level(STATE *state, DNS_RR *addr)
|
|||||||
level = TLS_LEV_SECURE;
|
level = TLS_LEV_SECURE;
|
||||||
} else if (!TLS_DANE_HASTA(state->ddane)
|
} else if (!TLS_DANE_HASTA(state->ddane)
|
||||||
&& !TLS_DANE_HASEE(state->ddane)) {
|
&& !TLS_DANE_HASEE(state->ddane)) {
|
||||||
msg_panic("empty DANE match list");
|
msg_panic("DANE activated with no TLSA records to match");
|
||||||
} else {
|
} else {
|
||||||
if (state->match)
|
if (state->match)
|
||||||
argv_free(state->match);
|
argv_free(state->match);
|
||||||
@@ -1531,7 +1554,7 @@ static void usage(void)
|
|||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
fprintf(stderr, "usage: %s %s \\\n\t%s \\\n\t%s \\\n\t%s"
|
fprintf(stderr, "usage: %s %s \\\n\t%s \\\n\t%s \\\n\t%s"
|
||||||
" destination [match ...]\n", var_procname,
|
" destination [match ...]\n", var_procname,
|
||||||
"[-acCfSv] [-t conn_tmout] [-T cmd_tmout] [-L logopts]",
|
"[-acCfSvw] [-t conn_tmout] [-T cmd_tmout] [-L logopts]",
|
||||||
"[-h host_lookup] [-l level] [-d mdalg] [-g grade] [-p protocols]",
|
"[-h host_lookup] [-l level] [-d mdalg] [-g grade] [-p protocols]",
|
||||||
"[-A tafile] [-F CAfile.pem] [-P CApath/] [-m count] [-r delay]",
|
"[-A tafile] [-F CAfile.pem] [-P CApath/] [-m count] [-r delay]",
|
||||||
"[-o name=value]");
|
"[-o name=value]");
|
||||||
@@ -1594,6 +1617,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
|
|||||||
state->pass = 1;
|
state->pass = 1;
|
||||||
state->reconnect = -1;
|
state->reconnect = -1;
|
||||||
state->max_reconnect = 5;
|
state->max_reconnect = 5;
|
||||||
|
state->wrapper_mode = 0;
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
state->protocols = mystrdup("!SSLv2");
|
state->protocols = mystrdup("!SSLv2");
|
||||||
state->grade = mystrdup("medium");
|
state->grade = mystrdup("medium");
|
||||||
@@ -1603,7 +1627,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
|
|||||||
|
|
||||||
#define OPTS "a:ch:o:St:T:v"
|
#define OPTS "a:ch:o:St:T:v"
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
#define TLSOPTS "A:Cd:fF:g:l:L:m:p:P:r:"
|
#define TLSOPTS "A:Cd:fF:g:l:L:m:p:P:r:w"
|
||||||
|
|
||||||
state->mdalg = mystrdup("sha1");
|
state->mdalg = mystrdup("sha1");
|
||||||
state->CApath = mystrdup("");
|
state->CApath = mystrdup("");
|
||||||
@@ -1692,6 +1716,9 @@ static void parse_options(STATE *state, int argc, char *argv[])
|
|||||||
case 'r':
|
case 'r':
|
||||||
state->reconnect = atoi(optarg);
|
state->reconnect = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'w':
|
||||||
|
state->wrapper_mode = 1;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1725,10 +1752,9 @@ static void parse_options(STATE *state, int argc, char *argv[])
|
|||||||
state->level = tls_level_lookup(state->options.level);
|
state->level = tls_level_lookup(state->options.level);
|
||||||
|
|
||||||
switch (state->level) {
|
switch (state->level) {
|
||||||
case TLS_LEV_DANE_ONLY:
|
|
||||||
state->level = TLS_LEV_DANE;
|
|
||||||
break;
|
|
||||||
case TLS_LEV_NONE:
|
case TLS_LEV_NONE:
|
||||||
|
if (state->wrapper_mode)
|
||||||
|
msg_fatal("SSL wrapper mode requires that TLS not be disabled");
|
||||||
return;
|
return;
|
||||||
case TLS_LEV_INVALID:
|
case TLS_LEV_INVALID:
|
||||||
msg_fatal("Invalid TLS level \"%s\"", state->options.level);
|
msg_fatal("Invalid TLS level \"%s\"", state->options.level);
|
||||||
@@ -1741,8 +1767,8 @@ static void parse_options(STATE *state, int argc, char *argv[])
|
|||||||
* required for DANE support.
|
* required for DANE support.
|
||||||
*/
|
*/
|
||||||
tls_init(state);
|
tls_init(state);
|
||||||
if (state->level == TLS_LEV_DANE && !tls_dane_avail()) {
|
if (TLS_DANE_BASED(state->level) && !tls_dane_avail()) {
|
||||||
msg_warn("The \"dane\" TLS security level is not available");
|
msg_warn("DANE TLS support is not available, resorting to \"secure\"");
|
||||||
state->level = TLS_LEV_SECURE;
|
state->level = TLS_LEV_SECURE;
|
||||||
}
|
}
|
||||||
state->tls_bio = 0;
|
state->tls_bio = 0;
|
||||||
@@ -1780,6 +1806,7 @@ static void parse_match(STATE *state, int argc, char *argv[])
|
|||||||
state->mdalg, *argv++, "");
|
state->mdalg, *argv++, "");
|
||||||
break;
|
break;
|
||||||
case TLS_LEV_DANE:
|
case TLS_LEV_DANE:
|
||||||
|
case TLS_LEV_DANE_ONLY:
|
||||||
state->match = argv_alloc(2);
|
state->match = argv_alloc(2);
|
||||||
argv_add(state->match, "nexthop", "hostname", ARGV_END);
|
argv_add(state->match, "nexthop", "hostname", ARGV_END);
|
||||||
break;
|
break;
|
||||||
|
@@ -437,6 +437,7 @@ static void set_cipher_grade(SMTP_TLS_POLICY *tls)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TLS_LEV_DANE:
|
case TLS_LEV_DANE:
|
||||||
|
case TLS_LEV_DANE_ONLY:
|
||||||
case TLS_LEV_FPRINT:
|
case TLS_LEV_FPRINT:
|
||||||
case TLS_LEV_VERIFY:
|
case TLS_LEV_VERIFY:
|
||||||
case TLS_LEV_SECURE:
|
case TLS_LEV_SECURE:
|
||||||
@@ -534,7 +535,7 @@ static void *policy_create(const char *unused_key, void *context)
|
|||||||
* "dane-only" changes to "dane" once we obtain the requisite TLSA
|
* "dane-only" changes to "dane" once we obtain the requisite TLSA
|
||||||
* records.
|
* records.
|
||||||
*/
|
*/
|
||||||
if (tls->level == TLS_LEV_DANE || tls->level == TLS_LEV_DANE_ONLY)
|
if (TLS_DANE_BASED(tls->level))
|
||||||
dane_init(tls, iter);
|
dane_init(tls, iter);
|
||||||
if (tls->level == TLS_LEV_INVALID)
|
if (tls->level == TLS_LEV_INVALID)
|
||||||
return ((void *) tls);
|
return ((void *) tls);
|
||||||
@@ -563,6 +564,7 @@ static void *policy_create(const char *unused_key, void *context)
|
|||||||
case TLS_LEV_MAY:
|
case TLS_LEV_MAY:
|
||||||
case TLS_LEV_ENCRYPT:
|
case TLS_LEV_ENCRYPT:
|
||||||
case TLS_LEV_DANE:
|
case TLS_LEV_DANE:
|
||||||
|
case TLS_LEV_DANE_ONLY:
|
||||||
break;
|
break;
|
||||||
case TLS_LEV_FPRINT:
|
case TLS_LEV_FPRINT:
|
||||||
if (tls->dane == 0)
|
if (tls->dane == 0)
|
||||||
@@ -844,7 +846,6 @@ static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
|
|||||||
} else if (!TLS_DANE_HASEE(dane))
|
} else if (!TLS_DANE_HASEE(dane))
|
||||||
msg_panic("empty DANE match list");
|
msg_panic("empty DANE match list");
|
||||||
tls->dane = dane;
|
tls->dane = dane;
|
||||||
tls->level = TLS_LEV_DANE;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5132,7 +5132,13 @@ static void smtpd_proto(SMTPD_STATE *state)
|
|||||||
static char *smtpd_format_cmd_stats(VSTRING *buf)
|
static char *smtpd_format_cmd_stats(VSTRING *buf)
|
||||||
{
|
{
|
||||||
SMTPD_CMD *cmdp;
|
SMTPD_CMD *cmdp;
|
||||||
|
int all_success = 0;
|
||||||
|
int all_total = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log the statistics. Note that this loop produces no output when no
|
||||||
|
* command was received. We address that after the loop.
|
||||||
|
*/
|
||||||
VSTRING_RESET(buf);
|
VSTRING_RESET(buf);
|
||||||
for (cmdp = smtpd_cmd_table; /* see below */ ; cmdp++) {
|
for (cmdp = smtpd_cmd_table; /* see below */ ; cmdp++) {
|
||||||
if (cmdp->total_count > 0) {
|
if (cmdp->total_count > 0) {
|
||||||
@@ -5141,10 +5147,22 @@ static char *smtpd_format_cmd_stats(VSTRING *buf)
|
|||||||
cmdp->success_count);
|
cmdp->success_count);
|
||||||
if (cmdp->success_count != cmdp->total_count)
|
if (cmdp->success_count != cmdp->total_count)
|
||||||
vstring_sprintf_append(buf, "/%d", cmdp->total_count);
|
vstring_sprintf_append(buf, "/%d", cmdp->total_count);
|
||||||
|
all_success += cmdp->success_count;
|
||||||
|
all_total += cmdp->total_count;
|
||||||
}
|
}
|
||||||
if (cmdp->name == 0)
|
if (cmdp->name == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log total numbers, so that logfile analyzers will see something even
|
||||||
|
* if the above loop produced no output. When no commands were received
|
||||||
|
* log "0/0" to simplify the identification of abnormal sessions: any
|
||||||
|
* statistics with [0-9]/ indicate that there was a problem.
|
||||||
|
*/
|
||||||
|
vstring_sprintf_append(buf, " commands=%d", all_success);
|
||||||
|
if (all_success != all_total || all_total == 0)
|
||||||
|
vstring_sprintf_append(buf, "/%d", all_total);
|
||||||
return (lowercase(STR(buf)));
|
return (lowercase(STR(buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,6 +53,8 @@
|
|||||||
#define TLS_MUST_MATCH(l) ((l) > TLS_LEV_ENCRYPT)
|
#define TLS_MUST_MATCH(l) ((l) > TLS_LEV_ENCRYPT)
|
||||||
#define TLS_MUST_TRUST(l) ((l) >= TLS_LEV_DANE)
|
#define TLS_MUST_TRUST(l) ((l) >= TLS_LEV_DANE)
|
||||||
#define TLS_MUST_PKIX(l) ((l) >= TLS_LEV_VERIFY)
|
#define TLS_MUST_PKIX(l) ((l) >= TLS_LEV_VERIFY)
|
||||||
|
#define TLS_OPPORTUNISTIC(l) ((l) == TLS_LEV_MAY || (l) == TLS_LEV_DANE)
|
||||||
|
#define TLS_DANE_BASED(l) ((l) == TLS_LEV_DANE || (l) == TLS_LEV_DANE_ONLY)
|
||||||
|
|
||||||
extern const NAME_CODE tls_level_table[];
|
extern const NAME_CODE tls_level_table[];
|
||||||
|
|
||||||
|
@@ -827,10 +827,10 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
/*
|
/*
|
||||||
* When certificate verification is required, log trust chain validation
|
* When certificate verification is required, log trust chain validation
|
||||||
* errors even when disabled by default for opportunistic sessions. For
|
* errors even when disabled by default for opportunistic sessions. For
|
||||||
* "dane" this only applies when using trust-anchor associations.
|
* DANE this only applies when using trust-anchor associations.
|
||||||
*/
|
*/
|
||||||
if (TLS_MUST_TRUST(props->tls_level)
|
if (TLS_MUST_TRUST(props->tls_level)
|
||||||
&& (props->tls_level != TLS_LEV_DANE || TLS_DANE_HASTA(props->dane)))
|
&& (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane)))
|
||||||
log_mask |= TLS_LOG_UNTRUSTED;
|
log_mask |= TLS_LOG_UNTRUSTED;
|
||||||
|
|
||||||
if (log_mask & TLS_LOG_VERBOSE)
|
if (log_mask & TLS_LOG_VERBOSE)
|
||||||
@@ -849,8 +849,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
props->namaddr, props->protocols);
|
props->namaddr, props->protocols);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
/* The DANE level requires SSLv3 or later, not SSLv2. */
|
/* DANE requires SSLv3 or later, not SSLv2. */
|
||||||
if (props->tls_level == TLS_LEV_DANE)
|
if (TLS_DANE_BASED(props->tls_level))
|
||||||
protomask |= TLS_PROTOCOL_SSLv2;
|
protomask |= TLS_PROTOCOL_SSLv2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -945,7 +945,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef TLSEXT_MAXLEN_host_name
|
#ifdef TLSEXT_MAXLEN_host_name
|
||||||
if (props->tls_level == TLS_LEV_DANE
|
if (TLS_DANE_BASED(props->tls_level)
|
||||||
&& strlen(props->host) <= TLSEXT_MAXLEN_host_name) {
|
&& strlen(props->host) <= TLSEXT_MAXLEN_host_name) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -227,7 +227,7 @@ char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
|
|||||||
#if 0
|
#if 0
|
||||||
digest_dane(props->dane, ee); /* See above */
|
digest_dane(props->dane, ee); /* See above */
|
||||||
#endif
|
#endif
|
||||||
digest_string(props->tls_level == TLS_LEV_DANE ? props->host : "");
|
digest_string(TLS_DANE_BASED(props->tls_level) ? props->host : "");
|
||||||
}
|
}
|
||||||
checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
|
checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
|
||||||
EVP_MD_CTX_destroy(mdctx);
|
EVP_MD_CTX_destroy(mdctx);
|
||||||
|
Reference in New Issue
Block a user