2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-31 06:05:37 +00:00

postfix-3.4-20181113

This commit is contained in:
Wietse Venema
2018-11-13 00:00:00 -05:00
committed by Viktor Dukhovni
parent 17000226f6
commit 93be1eb79b
20 changed files with 933 additions and 166 deletions

View File

@@ -23758,3 +23758,30 @@ Apologies for any names omitted.
util/dict.c, util/dict.h, util/dict_cidr.c, util/dict_file.c,
util/dict_inline.c, util/dict_pcre.c, util/dict_random.c,
util/dict_regexp.c, util/dict_static.c.
20181106
Bugfix (introduced: 3.0): smtpd_discard_ehlo_keywords could
not disable "SMTPUTF8". because the lookup table was using
"EHLO_MASK_SMTPUTF8" instead. File: global/ehlo_mask.c.
Documentation: the postmap(1) manpage no longer refers to
compatibility with Sendmail's makemap command. File:
postmap/postmap.c.
Cleanup: don't use ssize_t for boolean result. File:
global/smtp_stream.c. Memory leak: the Berkeley DB client
leaked a small amount of memory asfter failing to open a
table. File: util/dict_db.c.
Cleanup: memory leak caused by missing dbenv->close() call
after failing to open a Berkeley DB table. File: util/dict_db.c.
20181112
Improved logging of TLS 1.3 summary information, and improved
reporting of the same info in Received: message headers.
Viktor Dukhovni. Files: proto/FORWARD_SECRECY_README.html,
smtpd/smtpd.c, tls/tls.h, tls/tls_client.c, tls/tls_misc.c,
tls/tls_proxy.h, tls/tls_proxy_context_print.c,
tls/tls_proxy_context_scan.c, tls/tls_server.c.

View File

@@ -294,7 +294,8 @@ verification status.
* With "smtp_tls_loglevel = 1" and "smtpd_tls_loglevel = 1", the Postfix SMTP
client and server will log TLS connection information to the maillog file.
The general logfile format is:
The general logfile format is shown below. With TLS 1.3 there may be
additional properties logged after the cipher name and bits.
postfix/smtp[process-id]: Untrusted TLS connection established
to host.example.com[192.168.0.2]:25: TLSv1 with cipher cipher-name
@@ -307,7 +308,8 @@ verification status.
* With "smtpd_tls_received_header = yes", the Postfix SMTP server will record
TLS connection information in the Received: header in the form of comments
(text inside parentheses). The general format depends on the
smtpd_tls_ask_ccert setting:
smtpd_tls_ask_ccert setting. With TLS 1.3 there may be additional
properties logged after the cipher name and bits.
Received: from host.example.com (host.example.com [192.168.0.2])
(using TLSv1 with cipher cipher-name
@@ -320,6 +322,47 @@ verification status.
(actual-key-size/raw-key-size bits))
(No client certificate requested)
TLS 1.3 examples. Some of the new attributes may not appear when not
applicable or not available in an older versions of the OpenSSL library.
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256
bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
server-digest SHA256)
(No client certificate requested)
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256
bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256)
(Client CN "example.org", Issuer "example.org" (not verified))
o The "key-exchange" attribute records the type of "Diffie-Hellman" group
used for key agreement. Possible values include "DHE", "ECDHE",
"X25519" and "X448". With "DHE", the bit size of the prime will be
reported in parentheses after the algorithm name, with "ECDHE", the
curve name.
o The "server-signature" attribute shows the public key signature
algorithm used by the server. With "RSA-PSS", the bit size of the
modulus will be reported in parentheses. With "ECDSA", the curve name.
If, for example, the server has both an RSA and an ECDSA private key
and certificate, it will be possible to track which one was used for a
given connection.
o The new "server-digest" attribute records the digest algorithm used by
the server to prepare handshake messages for signing. The Ed25519 and
Ed448 signature algorithms do not make use of such a digest, so no
"server-digest" will be shown for these signature algorithms.
o When a client certificate is requested with "smtpd_tls_ask_ccert" and
the client uses a TLS client-certificate, the "client-signature" and
"client-digest" attributes will record the corresponding properties of
the client's TLS handshake signature.
The next sections will explain what cipher-name, key-size, and peer
verification status information to expect.
@@ -361,6 +404,51 @@ The actual key length and raw algorithm key length are generally the same with
non-export ciphers, but may they differ for the legacy export ciphers where the
actual key is artificially shortened.
Starting with TLS 1.3 the cipher name no longer contains enough information to
determine which forward-secrecy scheme was employed, but TLS 1.3 aallwwaayyss uses
forward-secrecy. On the client side, up-to-date Postfix releases log additional
information for TLS 1.3 connections, reporting the signature and key exchange
algorithms. Two examples below (the long single line messages are folded across
multiple lines for readability):
postfix/smtp[process-id]:
Untrusted TLS connection established to 127.0.0.1[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256
client-signature ECDSA (P-256) client-digest SHA256
postfix/smtp[process-id]:
Untrusted TLS connection established to 127.0.0.1[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange ECDHE (P-256) server-signature ECDSA (P-256) server-digest
SHA256
In the above connections, the "key-exchange" value records the "Diffie-Hellman"
algorithm used for key agreement. The "server-signature" value records the
public key algoritm used by the server to sign the key exchange. The "server-
digest" value records any hash algorithm used to prepare the data for signing.
With "ED25519" and "ED448", no separate hash algorithm is used.
Examples of Postfix SMTP server logging:
postfix/smtpd[process-id]:
Untrusted TLS connection established from localhost[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256
client-signature ECDSA (P-256) client-digest SHA256
postfix/smtpd[process-id]:
Anonymous TLS connection established from localhost[127.0.0.1]:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
server-signature RSA-PSS (2048 bits) server-digest SHA256
postfix/smtpd[process-id]:
Anonymous TLS connection established from localhost[127.0.0.1]:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
server-signature ED25519
WWhhaatt ddoo ""AAnnoonnyymmoouuss"",, ""UUnnttrruusstteedd"",, eettcc.. iinn PPoossttffiixx llooggggiinngg mmeeaann??
The verification levels below are subject to man-in-the-middle attacks to

View File

@@ -1,18 +1,15 @@
Wish list:
In dict_db.h, call dbenv->close() before bailing out
with a surrogate map.
With DICT_FLAG_RHS_IS_FILE, should dict_update() open a
file? base64-encode the value?
In smtpd(8) and postscreen(8), set the ehlo_discard_mask
to ~0 so that STARTTLS, BDAT, DSN, etc. won't work.
to ~0 so that STARTTLS, BDAT, DSN, etc. work only for clients
that send EHLO.
In postscreen, don't fork after 'postfix reload' when
psc_check_queue_length (and psc_post_queue_length?) is zero.
In smtp_stream.c, replace `ssize_t err' with `int err'.
In ehlo_mask.c, replace "EHLO_MASK_SMTPUTF8" with "SMTPUTF8".
With smtpd_reject_footer=$foo in master.cf, and foo defined
in main.cf, postconf complains about an unused setting in
main.cf. Note that "postconf -Px" will expand $name in

View File

@@ -397,7 +397,9 @@ peer certificate or public-key verification status. </p>
<li> <p> With "<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a> = 1" and "<a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a> = 1",
the Postfix SMTP client and server will log TLS connection information
to the maillog file. The general logfile format is: </p>
to the maillog file. The general logfile format is shown below.
With TLS 1.3 there may be additional properties logged after the
cipher name and bits. </p>
<blockquote>
<pre>
@@ -414,7 +416,8 @@ from host.example.com[192.168.0.2]: TLSv1 with cipher <i>cipher-name</i>
<li> <p> With "<a href="postconf.5.html#smtpd_tls_received_header">smtpd_tls_received_header</a> = yes", the Postfix SMTP
server will record TLS connection information in the Received:
header in the form of comments (text inside parentheses). The general
format depends on the <a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> setting:
format depends on the <a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> setting. With TLS 1.3 there
may be additional properties logged after the cipher name and bits. </p>
<blockquote>
<pre>
@@ -430,6 +433,46 @@ Received: from host.example.com (host.example.com [192.168.0.2])
</pre>
</blockquote>
<p> TLS 1.3 examples. Some of the new attributes may not appear when not
applicable or not available in an older versions of the OpenSSL library. </p>
<blockquote>
<pre>
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256)
(No client certificate requested)
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256)
(Client CN "example.org", Issuer "example.org" (not verified))
</pre>
</blockquote>
<ul>
<li> <p> The "key-exchange" attribute records the type of "Diffie-Hellman"
group used for key agreement. Possible values include "DHE", "ECDHE", "X25519"
and "X448". With "DHE", the bit size of the prime will be reported in
parentheses after the algorithm name, with "ECDHE", the curve name. </p>
<li> <p> The "server-signature" attribute shows the public key signature
algorithm used by the server. With "RSA-PSS", the bit size of the modulus will
be reported in parentheses. With "ECDSA", the curve name. If, for example,
the server has both an RSA and an ECDSA private key and certificate, it will be
possible to track which one was used for a given connection. </p>
<li> <p> The new "server-digest" attribute records the digest algorithm used by
the server to prepare handshake messages for signing. The Ed25519 and Ed448
signature algorithms do not make use of such a digest, so no "server-digest"
will be shown for these signature algorithms. </p>
<li> <p> When a client certificate is requested with "<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a>" and
the client uses a TLS client-certificate, the "client-signature" and
"client-digest" attributes will record the corresponding properties of the
client's TLS handshake signature. </p> </ul>
</ul>
<p> The next sections will explain what <i>cipher-name</i>,
@@ -481,6 +524,58 @@ are generally the same with non-export ciphers, but may they
differ for the legacy export ciphers where the actual key
is artificially shortened. </p>
<p> Starting with TLS 1.3 the cipher name no longer contains enough
information to determine which forward-secrecy scheme was employed,
but TLS 1.3 <b>always</b> uses forward-secrecy. On the client side,
up-to-date Postfix releases log additional information for TLS 1.3
connections, reporting the signature and key exchange algorithms.
Two examples below (the long single line messages are folded across
multiple lines for readability): </p>
<blockquote>
<pre>
postfix/smtp[<i>process-id</i>]:
Untrusted TLS connection established to 127.0.0.1[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256
postfix/smtp[<i>process-id</i>]:
Untrusted TLS connection established to 127.0.0.1[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange ECDHE (P-256) server-signature ECDSA (P-256) server-digest SHA256
</pre>
</blockquote>
<p> In the above connections, the "key-exchange" value records the
"Diffie-Hellman" algorithm used for key agreement. The "server-signature" value
records the public key algoritm used by the server to sign the key exchange.
The "server-digest" value records any hash algorithm used to prepare the data
for signing. With "ED25519" and "ED448", no separate hash algorithm is used.
</p>
<p> Examples of Postfix SMTP server logging: </p>
<blockquote>
<pre>
postfix/smtpd[<i>process-id</i>]:
Untrusted TLS connection established from localhost[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256
postfix/smtpd[<i>process-id</i>]:
Anonymous TLS connection established from localhost[127.0.0.1]:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
server-signature RSA-PSS (2048 bits) server-digest SHA256
postfix/smtpd[<i>process-id</i>]:
Anonymous TLS connection established from localhost[127.0.0.1]:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
server-signature ED25519
</pre>
</blockquote>
<h2><a name="status"> What do "Anonymous", "Untrusted", etc. in
Postfix logging mean? </a> </h2>

View File

@@ -15,16 +15,13 @@ POSTMAP(1) POSTMAP(1)
<b>DESCRIPTION</b>
The <a href="postmap.1.html"><b>postmap</b>(1)</a> command creates or queries one or more Postfix lookup
tables, or updates an existing one. The input and output file formats
are expected to be compatible with:
tables, or updates an existing one.
<b>makemap</b> <i>file</i><b>_</b><i>type file</i><b>_</b><i>name</i> &lt; <i>file</i><b>_</b><i>name</i>
If the result files do not exist they will be created with the same
If the result files do not exist they will be created with the same
group and other read permissions as their source file.
While the table update is in progress, signal delivery is postponed,
and an exclusive, advisory, lock is placed on the entire table, in
While the table update is in progress, signal delivery is postponed,
and an exclusive, advisory, lock is placed on the entire table, in
order to avoid surprises in spectator processes.
<b>INPUT FILE FORMAT</b>
@@ -34,153 +31,153 @@ POSTMAP(1) POSTMAP(1)
<i>key</i> whitespace <i>value</i>
<b>o</b> Empty lines and whitespace-only lines are ignored, as are lines
<b>o</b> Empty lines and whitespace-only lines are ignored, as are lines
whose first non-whitespace character is a `#'.
<b>o</b> A logical line starts with non-whitespace text. A line that
<b>o</b> A logical line starts with non-whitespace text. A line that
starts with whitespace continues a logical line.
The <i>key</i> and <i>value</i> are processed as is, except that surrounding white
space is stripped off. Whitespace in lookup keys is supported as of
The <i>key</i> and <i>value</i> are processed as is, except that surrounding white
space is stripped off. Whitespace in lookup keys is supported as of
Postfix 3.2.
When the <b>-F</b> option is given, the <i>value</i> must specify a filename;
<a href="postmap.1.html"><b>postmap</b>(1)</a> will store the base64-encoded content of that file instead
When the <b>-F</b> option is given, the <i>value</i> must specify a filename;
<a href="postmap.1.html"><b>postmap</b>(1)</a> will store the base64-encoded content of that file instead
of the <i>value</i> itself.
When the <i>key</i> specifies email address information, the localpart should
When the <i>key</i> specifies email address information, the localpart should
be enclosed with double quotes if required by <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a>. For example, an
address localpart that contains ";", or a localpart that starts or ends
with ".".
By default the lookup key is mapped to lowercase to make the lookups
By default the lookup key is mapped to lowercase to make the lookups
case insensitive; as of Postfix 2.3 this case folding happens only with
tables whose lookup keys are fixed-case strings such as <a href="DATABASE_README.html#types">btree</a>:, <a href="DATABASE_README.html#types">dbm</a>: or
<a href="DATABASE_README.html#types">hash</a>:. With earlier versions, the lookup key is folded even with tables
where a lookup field can match both upper and lower case text, such as
<a href="regexp_table.5.html">regexp</a>: and <a href="pcre_table.5.html">pcre</a>:. This resulted in loss of information with $<i>number</i>
where a lookup field can match both upper and lower case text, such as
<a href="regexp_table.5.html">regexp</a>: and <a href="pcre_table.5.html">pcre</a>:. This resulted in loss of information with $<i>number</i>
substitutions.
<b>COMMAND-LINE ARGUMENTS</b>
<b>-b</b> Enable message body query mode. When reading lookup keys from
standard input with "<b>-q -</b>", process the input as if it is an
email message in <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> format. Each line of body content
<b>-b</b> Enable message body query mode. When reading lookup keys from
standard input with "<b>-q -</b>", process the input as if it is an
email message in <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> format. Each line of body content
becomes one lookup key.
By default, the <b>-b</b> option starts generating lookup keys at the
first non-header line, and stops when the end of the message is
reached. To simulate <a href="header_checks.5.html"><b>body_checks</b>(5)</a> processing, enable MIME
parsing with <b>-m</b>. With this, the <b>-b</b> option generates no
body-style lookup keys for attachment MIME headers and for
By default, the <b>-b</b> option starts generating lookup keys at the
first non-header line, and stops when the end of the message is
reached. To simulate <a href="header_checks.5.html"><b>body_checks</b>(5)</a> processing, enable MIME
parsing with <b>-m</b>. With this, the <b>-b</b> option generates no
body-style lookup keys for attachment MIME headers and for
attached message/* headers.
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
ables UTF-8 syntax checks on query keys and lookup results.
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
ables UTF-8 syntax checks on query keys and lookup results.
Specify the <b>-U</b> option to force UTF-8 syntax checks anyway.
This feature is available in Postfix version 2.6 and later.
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
Read the <a href="postconf.5.html"><b>main.cf</b></a> configuration file in the named directory
Read the <a href="postconf.5.html"><b>main.cf</b></a> configuration file in the named directory
instead of the default configuration directory.
<b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one entry per map.
The exit status is zero when the requested information was
<b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one entry per map.
The exit status is zero when the requested information was
found.
If a key value of <b>-</b> is specified, the program reads key values
from the standard input stream. The exit status is zero when at
If a key value of <b>-</b> is specified, the program reads key values
from the standard input stream. The exit status is zero when at
least one of the requested keys was found.
<b>-f</b> Do not fold the lookup key to lower case while creating or
<b>-f</b> Do not fold the lookup key to lower case while creating or
querying a table.
With Postfix version 2.3 and later, this option has no effect
With Postfix version 2.3 and later, this option has no effect
for regular expression tables. There, case folding is controlled
by appending a flag to a pattern.
<b>-F</b> When creating a map from source file, replace each value with
the base64-encoded content of the named file. When querying a
<b>-F</b> When creating a map from source file, replace each value with
the base64-encoded content of the named file. When querying a
map, or listing a map, base64-decode each value.
<b>-h</b> Enable message header query mode. When reading lookup keys from
standard input with "<b>-q -</b>", process the input as if it is an
email message in <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> format. Each logical header line
becomes one lookup key. A multi-line header becomes one lookup
<b>-h</b> Enable message header query mode. When reading lookup keys from
standard input with "<b>-q -</b>", process the input as if it is an
email message in <a href="http://tools.ietf.org/html/rfc5322">RFC 5322</a> format. Each logical header line
becomes one lookup key. A multi-line header becomes one lookup
key with one or more embedded newline characters.
By default, the <b>-h</b> option generates lookup keys until the first
non-header line is reached. To simulate <a href="header_checks.5.html"><b>header_checks</b>(5)</a> pro-
cessing, enable MIME parsing with <b>-m</b>. With this, the <b>-h</b> option
also generates header-style lookup keys for attachment MIME
By default, the <b>-h</b> option generates lookup keys until the first
non-header line is reached. To simulate <a href="header_checks.5.html"><b>header_checks</b>(5)</a> pro-
cessing, enable MIME parsing with <b>-m</b>. With this, the <b>-h</b> option
also generates header-style lookup keys for attachment MIME
headers and for attached message/* headers.
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
ables UTF-8 syntax checks on query keys and lookup results.
NOTE: with "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", the <b>-b</b> option option dis-
ables UTF-8 syntax checks on query keys and lookup results.
Specify the <b>-U</b> option to force UTF-8 syntax checks anyway.
This feature is available in Postfix version 2.6 and later.
<b>-i</b> Incremental mode. Read entries from standard input and do not
truncate an existing database. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> creates a
<b>-i</b> Incremental mode. Read entries from standard input and do not
truncate an existing database. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> creates a
new database from the entries in <b>file_name</b>.
<b>-m</b> Enable MIME parsing with "<b>-b</b>" and "<b>-h</b>".
This feature is available in Postfix version 2.6 and later.
<b>-N</b> Include the terminating null character that terminates lookup
keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is the
<b>-N</b> Include the terminating null character that terminates lookup
keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is the
default for the host operating system.
<b>-n</b> Don't include the terminating null character that terminates
lookup keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is
<b>-n</b> Don't include the terminating null character that terminates
lookup keys and values. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> does whatever is
the default for the host operating system.
<b>-o</b> Do not release root privileges when processing a non-root input
file. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> drops root privileges and runs as
<b>-o</b> Do not release root privileges when processing a non-root input
file. By default, <a href="postmap.1.html"><b>postmap</b>(1)</a> drops root privileges and runs as
the source file owner instead.
<b>-p</b> Do not inherit the file access permissions from the input file
when creating a new file. Instead, create a new file with
<b>-p</b> Do not inherit the file access permissions from the input file
when creating a new file. Instead, create a new file with
default access permissions (mode 0644).
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and write the first value
found to the standard output stream. The exit status is zero
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and write the first value
found to the standard output stream. The exit status is zero
when the requested information was found.
Note: this performs a single query with the key as specified,
and does not make iterative queries with substrings of the key
as described for <a href="access.5.html">access(5)</a>, <a href="canonical.5.html">canonical(5)</a>, <a href="transport.5.html">transport(5)</a>, <a href="virtual.5.html">vir-</a>
Note: this performs a single query with the key as specified,
and does not make iterative queries with substrings of the key
as described for <a href="access.5.html">access(5)</a>, <a href="canonical.5.html">canonical(5)</a>, <a href="transport.5.html">transport(5)</a>, <a href="virtual.5.html">vir-</a>
<a href="virtual.5.html">tual(5)</a> and other Postfix table-driven features.
If a key value of <b>-</b> is specified, the program reads key values
from the standard input stream and writes one line of <i>key value</i>
If a key value of <b>-</b> is specified, the program reads key values
from the standard input stream and writes one line of <i>key value</i>
output for each key that was found. The exit status is zero when
at least one of the requested keys was found.
<b>-r</b> When updating a table, do not complain about attempts to update
<b>-r</b> When updating a table, do not complain about attempts to update
existing entries, and make those updates anyway.
<b>-s</b> Retrieve all database elements, and write one line of <i>key value</i>
output for each element. The elements are printed in database
order, which is not necessarily the same as the original input
<b>-s</b> Retrieve all database elements, and write one line of <i>key value</i>
output for each element. The elements are printed in database
order, which is not necessarily the same as the original input
order.
This feature is available in Postfix version 2.2 and later, and
This feature is available in Postfix version 2.2 and later, and
is not available for all database types.
<b>-u</b> Disable UTF-8 support. UTF-8 support is enabled by default when
"<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes". It requires that keys and values are
<b>-u</b> Disable UTF-8 support. UTF-8 support is enabled by default when
"<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes". It requires that keys and values are
valid UTF-8 strings.
<b>-U</b> With "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = yes", force UTF-8 syntax checks with the
<b>-b</b> and <b>-h</b> options.
<b>-v</b> Enable verbose logging for debugging purposes. Multiple <b>-v</b>
<b>-v</b> Enable verbose logging for debugging purposes. Multiple <b>-v</b>
options make the software increasingly verbose.
<b>-w</b> When updating a table, do not complain about attempts to update
<b>-w</b> When updating a table, do not complain about attempts to update
existing entries, and ignore those attempts.
Arguments:
@@ -192,32 +189,32 @@ POSTMAP(1) POSTMAP(1)
The <a href="postmap.1.html"><b>postmap</b>(1)</a> command can query any supported file type, but it
can create only the following file types:
<b>btree</b> The output file is a btree file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
This is available on systems with support for <b>db</b> data-
<b>btree</b> The output file is a btree file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
This is available on systems with support for <b>db</b> data-
bases.
<b>cdb</b> The output consists of one file, named <i>file</i><b>_</b><i>name</i><b>.cdb</b>.
This is available on systems with support for <b>cdb</b> data-
<b>cdb</b> The output consists of one file, named <i>file</i><b>_</b><i>name</i><b>.cdb</b>.
This is available on systems with support for <b>cdb</b> data-
bases.
<b>dbm</b> The output consists of two files, named <i>file</i><b>_</b><i>name</i><b>.pag</b> and
<i>file</i><b>_</b><i>name</i><b>.dir</b>. This is available on systems with support
for <b>dbm</b> databases.
<b>hash</b> The output file is a hashed file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
This is available on systems with support for <b>db</b> data-
<b>hash</b> The output file is a hashed file, named <i>file</i><b>_</b><i>name</i><b>.db</b>.
This is available on systems with support for <b>db</b> data-
bases.
<b>fail</b> A table that reliably fails all requests. The lookup ta-
ble name is used for logging only. This table exists to
<b>fail</b> A table that reliably fails all requests. The lookup ta-
ble name is used for logging only. This table exists to
simplify Postfix error tests.
<b>sdbm</b> The output consists of two files, named <i>file</i><b>_</b><i>name</i><b>.pag</b> and
<i>file</i><b>_</b><i>name</i><b>.dir</b>. This is available on systems with support
for <b>sdbm</b> databases.
When no <i>file</i><b>_</b><i>type</i> is specified, the software uses the database
type specified via the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
When no <i>file</i><b>_</b><i>type</i> is specified, the software uses the database
type specified via the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
parameter.
<i>file</i><b>_</b><i>name</i>
@@ -226,11 +223,11 @@ POSTMAP(1) POSTMAP(1)
<b>DIAGNOSTICS</b>
Problems are logged to the standard error stream and to <b>syslogd</b>(8). No
output means that no problems were detected. Duplicate entries are
output means that no problems were detected. Duplicate entries are
skipped and are flagged with a warning.
<a href="postmap.1.html"><b>postmap</b>(1)</a> terminates with zero exit status in case of success (includ-
ing successful "<b>postmap -q</b>" lookup) and terminates with non-zero exit
ing successful "<b>postmap -q</b>" lookup) and terminates with non-zero exit
status in case of failure.
<b>ENVIRONMENT</b>
@@ -241,12 +238,12 @@ POSTMAP(1) POSTMAP(1)
Enable verbose logging for debugging purposes.
<b>CONFIGURATION PARAMETERS</b>
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro-
gram. The text below provides only a parameter summary. See <a href="postconf.5.html"><b>post-</b></a>
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro-
gram. The text below provides only a parameter summary. See <a href="postconf.5.html"><b>post-</b></a>
<a href="postconf.5.html"><b>conf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
The per-table I/O buffer size for programs that create Berkeley
The per-table I/O buffer size for programs that create Berkeley
DB hash or btree tables.
<b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
@@ -254,7 +251,7 @@ POSTMAP(1) POSTMAP(1)
hash or btree tables.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
figuration files.
<b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
@@ -262,19 +259,19 @@ POSTMAP(1) POSTMAP(1)
and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
<b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
The list of environment parameters that a privileged Postfix
process will import from a non-Postfix parent process, or
The list of environment parameters that a privileged Postfix
process will import from a non-Postfix parent process, or
name=value environment overrides.
<b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
Enable preliminary SMTPUTF8 support for the protocols described
Enable preliminary SMTPUTF8 support for the protocols described
in <a href="http://tools.ietf.org/html/rfc6531">RFC 6531</a>..6533.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
A prefix that is prepended to the process name in syslog
A prefix that is prepended to the process name in syslog
records, so that, for example, "smtpd" becomes "prefix/smtpd".
<b>SEE ALSO</b>

View File

@@ -16,12 +16,7 @@ Postfix lookup table management
.ad
.fi
The \fBpostmap\fR(1) command creates or queries one or more Postfix
lookup tables, or updates an existing one. The input and output
file formats are expected to be compatible with:
.nf
\fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR
.fi
lookup tables, or updates an existing one.
If the result files do not exist they will be created with the
same group and other read permissions as their source file.

View File

@@ -397,7 +397,9 @@ peer certificate or public-key verification status. </p>
<li> <p> With "smtp_tls_loglevel = 1" and "smtpd_tls_loglevel = 1",
the Postfix SMTP client and server will log TLS connection information
to the maillog file. The general logfile format is: </p>
to the maillog file. The general logfile format is shown below.
With TLS 1.3 there may be additional properties logged after the
cipher name and bits. </p>
<blockquote>
<pre>
@@ -414,7 +416,8 @@ from host.example.com[192.168.0.2]: TLSv1 with cipher <i>cipher-name</i>
<li> <p> With "smtpd_tls_received_header = yes", the Postfix SMTP
server will record TLS connection information in the Received:
header in the form of comments (text inside parentheses). The general
format depends on the smtpd_tls_ask_ccert setting:
format depends on the smtpd_tls_ask_ccert setting. With TLS 1.3 there
may be additional properties logged after the cipher name and bits. </p>
<blockquote>
<pre>
@@ -430,6 +433,46 @@ Received: from host.example.com (host.example.com [192.168.0.2])
</pre>
</blockquote>
<p> TLS 1.3 examples. Some of the new attributes may not appear when not
applicable or not available in an older versions of the OpenSSL library. </p>
<blockquote>
<pre>
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256)
(No client certificate requested)
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256)
(Client CN "example.org", Issuer "example.org" (not verified))
</pre>
</blockquote>
<ul>
<li> <p> The "key-exchange" attribute records the type of "Diffie-Hellman"
group used for key agreement. Possible values include "DHE", "ECDHE", "X25519"
and "X448". With "DHE", the bit size of the prime will be reported in
parentheses after the algorithm name, with "ECDHE", the curve name. </p>
<li> <p> The "server-signature" attribute shows the public key signature
algorithm used by the server. With "RSA-PSS", the bit size of the modulus will
be reported in parentheses. With "ECDSA", the curve name. If, for example,
the server has both an RSA and an ECDSA private key and certificate, it will be
possible to track which one was used for a given connection. </p>
<li> <p> The new "server-digest" attribute records the digest algorithm used by
the server to prepare handshake messages for signing. The Ed25519 and Ed448
signature algorithms do not make use of such a digest, so no "server-digest"
will be shown for these signature algorithms. </p>
<li> <p> When a client certificate is requested with "smtpd_tls_ask_ccert" and
the client uses a TLS client-certificate, the "client-signature" and
"client-digest" attributes will record the corresponding properties of the
client's TLS handshake signature. </p> </ul>
</ul>
<p> The next sections will explain what <i>cipher-name</i>,
@@ -481,6 +524,58 @@ are generally the same with non-export ciphers, but may they
differ for the legacy export ciphers where the actual key
is artificially shortened. </p>
<p> Starting with TLS 1.3 the cipher name no longer contains enough
information to determine which forward-secrecy scheme was employed,
but TLS 1.3 <b>always</b> uses forward-secrecy. On the client side,
up-to-date Postfix releases log additional information for TLS 1.3
connections, reporting the signature and key exchange algorithms.
Two examples below (the long single line messages are folded across
multiple lines for readability): </p>
<blockquote>
<pre>
postfix/smtp[<i>process-id</i>]:
Untrusted TLS connection established to 127.0.0.1[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256
postfix/smtp[<i>process-id</i>]:
Untrusted TLS connection established to 127.0.0.1[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange ECDHE (P-256) server-signature ECDSA (P-256) server-digest SHA256
</pre>
</blockquote>
<p> In the above connections, the "key-exchange" value records the
"Diffie-Hellman" algorithm used for key agreement. The "server-signature" value
records the public key algoritm used by the server to sign the key exchange.
The "server-digest" value records any hash algorithm used to prepare the data
for signing. With "ED25519" and "ED448", no separate hash algorithm is used.
</p>
<p> Examples of Postfix SMTP server logging: </p>
<blockquote>
<pre>
postfix/smtpd[<i>process-id</i>]:
Untrusted TLS connection established from localhost[127.0.0.1]:25:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature ECDSA (P-256) client-digest SHA256
postfix/smtpd[<i>process-id</i>]:
Anonymous TLS connection established from localhost[127.0.0.1]:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
server-signature RSA-PSS (2048 bits) server-digest SHA256
postfix/smtpd[<i>process-id</i>]:
Anonymous TLS connection established from localhost[127.0.0.1]:
TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
server-signature ED25519
</pre>
</blockquote>
<h2><a name="status"> What do "Anonymous", "Untrusted", etc. in
Postfix logging mean? </a> </h2>

View File

@@ -83,6 +83,7 @@ static const NAME_MASK ehlo_mask_table[] = {
"ENHANCEDSTATUSCODES", EHLO_MASK_ENHANCEDSTATUSCODES,
"DSN", EHLO_MASK_DSN,
"EHLO_MASK_SMTPUTF8", EHLO_MASK_SMTPUTF8,
"SMTPUTF8", EHLO_MASK_SMTPUTF8,
"CHUNKING", EHLO_MASK_CHUNKING,
"SILENT-DISCARD", EHLO_MASK_SILENT, /* XXX In-band signaling */
0,

View File

@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20181105"
#define MAIL_RELEASE_DATE "20181113"
#define MAIL_VERSION_NUMBER "3.4"
#ifdef SNAPSHOT

View File

@@ -429,7 +429,7 @@ int smtp_get_noexcept(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags
void smtp_fputs(const char *cp, ssize_t todo, VSTREAM *stream)
{
ssize_t err;
int err;
if (todo < 0)
msg_panic("smtp_fputs: negative todo %ld", (long) todo);
@@ -454,7 +454,7 @@ void smtp_fputs(const char *cp, ssize_t todo, VSTREAM *stream)
void smtp_fwrite(const char *cp, ssize_t todo, VSTREAM *stream)
{
ssize_t err;
int err;
if (todo < 0)
msg_panic("smtp_fwrite: negative todo %ld", (long) todo);

View File

@@ -10,12 +10,7 @@
/* [\fIfile_type\fR:]\fIfile_name\fR ...
/* DESCRIPTION
/* The \fBpostmap\fR(1) command creates or queries one or more Postfix
/* lookup tables, or updates an existing one. The input and output
/* file formats are expected to be compatible with:
/*
/* .nf
/* \fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR
/* .fi
/* lookup tables, or updates an existing one.
/*
/* If the result files do not exist they will be created with the
/* same group and other read permissions as their source file.

View File

@@ -3307,12 +3307,70 @@ static void common_pre_message_handling(SMTPD_STATE *state,
#ifdef USE_TLS
if (var_smtpd_tls_received_header && state->tls_context) {
out_fprintf(out_stream, REC_TYPE_NORM,
"\t(using %s with cipher %s (%d/%d bits))",
state->tls_context->protocol,
state->tls_context->cipher_name,
state->tls_context->cipher_usebits,
state->tls_context->cipher_algbits);
int cont = 0;
vstring_sprintf(state->buffer,
"\t(using %s with cipher %s (%d/%d bits)",
state->tls_context->protocol,
state->tls_context->cipher_name,
state->tls_context->cipher_usebits,
state->tls_context->cipher_algbits);
if (state->tls_context->kex_name && *state->tls_context->kex_name) {
out_record(out_stream, REC_TYPE_NORM, STR(state->buffer),
LEN(state->buffer));
vstring_sprintf(state->buffer, "\t key-exchange %s",
state->tls_context->kex_name);
if (state->tls_context->kex_curve
&& *state->tls_context->kex_curve)
vstring_sprintf_append(state->buffer, " (%s)",
state->tls_context->kex_curve);
else if (state->tls_context->kex_bits > 0)
vstring_sprintf_append(state->buffer, " (%d bits)",
state->tls_context->kex_bits);
cont = 1;
}
if (state->tls_context->locl_sig_name
&& *state->tls_context->locl_sig_name) {
if (cont) {
vstring_sprintf_append(state->buffer, " server-signature %s",
state->tls_context->locl_sig_name);
} else {
out_record(out_stream, REC_TYPE_NORM, STR(state->buffer),
LEN(state->buffer));
vstring_sprintf(state->buffer, "\t server-signature %s",
state->tls_context->locl_sig_name);
}
if (state->tls_context->locl_sig_curve
&& *state->tls_context->locl_sig_curve)
vstring_sprintf_append(state->buffer, " (%s)",
state->tls_context->locl_sig_curve);
else if (state->tls_context->locl_sig_bits > 0)
vstring_sprintf_append(state->buffer, " (%d bits)",
state->tls_context->locl_sig_bits);
if (state->tls_context->locl_sig_dgst
&& *state->tls_context->locl_sig_dgst)
vstring_sprintf_append(state->buffer, " server-digest %s",
state->tls_context->locl_sig_dgst);
}
if (state->tls_context->peer_sig_name
&& *state->tls_context->peer_sig_name) {
out_record(out_stream, REC_TYPE_NORM, STR(state->buffer),
LEN(state->buffer));
vstring_sprintf(state->buffer, "\t client-signature %s",
state->tls_context->peer_sig_name);
if (state->tls_context->peer_sig_curve
&& *state->tls_context->peer_sig_curve)
vstring_sprintf_append(state->buffer, " (%s)",
state->tls_context->peer_sig_curve);
else if (state->tls_context->peer_sig_bits > 0)
vstring_sprintf_append(state->buffer, " (%d bits)",
state->tls_context->peer_sig_bits);
if (state->tls_context->peer_sig_dgst
&& *state->tls_context->peer_sig_dgst)
vstring_sprintf_append(state->buffer, " client-digest %s",
state->tls_context->peer_sig_dgst);
}
out_fprintf(out_stream, REC_TYPE_NORM, "%s)", STR(state->buffer));
if (TLS_CERT_IS_PRESENT(state->tls_context)) {
peer_CN = VSTRING_STRDUP(state->tls_context->peer_CN);
comment_sanitize(peer_CN);

View File

@@ -112,6 +112,30 @@ extern const char *str_tls_level(int);
/* Backwards compatibility with OpenSSL < 1.1.1 */
#if OPENSSL_VERSION_NUMBER < 0x1010100fUL
#define SSL_CTX_set_num_tickets(ctx, num) ((void)0)
#endif
/*-
* Backwards compatibility with OpenSSL < 1.1.1a (or some later version).
*
* The client-only interface SSL_get_server_tmp_key() is slated to be made to
* work on both client and server, and renamed to SSL_get_peer_tmp_key(), with
* the original name left behind as an alias. We'll use the new name if/when
* available.
*
* XXX: Set corresponding OpenSSL version floor below when OpenSSL pull
* request:
*
* <https://github.com/openssl/openssl/pull/7608>
*
* is merged, perhaps in the upcoming 1.1.1a release (at which point the XXX
* part of this comment can be deleted).
*/
#if OPENSSL_VERSION_NUMBER < 0x1010101fUL
#undef SSL_get_signature_nid
#define SSL_get_signature_nid(ssl, pnid) (NID_undef)
#define tls_get_peer_dh_pubkey SSL_get_server_tmp_key
#else
#define tls_get_peer_dh_pubkey SSL_get_peer_tmp_key
#endif
/* SSL_CIPHER_get_name() got constified in 0.9.7g */
@@ -239,6 +263,17 @@ typedef struct {
const char *cipher_name;
int cipher_usebits;
int cipher_algbits;
const char *kex_name; /* shared key-exchange algorithm */
const char *kex_curve; /* shared key-exchange ECDHE curve */
int kex_bits; /* shared FFDHE key exchange bits */
const char *locl_sig_name; /* local signature key algorithm */
const char *locl_sig_curve; /* local ECDSA curve name */
int locl_sig_bits; /* local RSA signature key bits */
const char *locl_sig_dgst; /* local signature digest */
const char *peer_sig_name; /* peer's signature key algorithm */
const char *peer_sig_curve; /* peer's ECDSA curve name */
int peer_sig_bits; /* peer's RSA signature key bits */
const char *peer_sig_dgst; /* peer's signature digest */
/* Private. */
SSL *con;
char *cache_type; /* tlsmgr(8) cache type if enabled */
@@ -378,7 +413,8 @@ extern void tls_param_init(void);
#endif
/*
* OpenSSL 1.1.1 does not define a TXT macro for TLS 1.3, so we roll our own.
* OpenSSL 1.1.1 does not define a TXT macro for TLS 1.3, so we roll our
* own.
*/
#define TLS_PROTOCOL_TXT_TLSV1_3 "TLSv1.3"
@@ -433,7 +469,12 @@ extern const NAME_CODE tls_cipher_grade_table[];
extern const char *tls_set_ciphers(TLS_APPL_STATE *, const char *,
const char *, const char *);
#endif
/*
* Populate TLS context with TLS 1.3-related signature parameters.
*/
extern void tls_get_signature_params(TLS_SESS_STATE *);
#endif /* TLS_INTERNAL */
/*
* tls_client.c

View File

@@ -860,6 +860,62 @@ static void verify_extract_print(TLS_SESS_STATE *TLScontext, X509 *peercert,
TLS_CERT_FLAG_TRUSTED | TLS_CERT_FLAG_MATCHED;
}
/* log_summary - TLS loglevel 1 one-liner, embellished with TLS 1.3 details */
static void log_summary(TLS_SESS_STATE *TLScontext,
const TLS_CLIENT_START_PROPS *props)
{
VSTRING *msg = vstring_alloc(100);
vstring_sprintf(msg, "%s TLS connection established to %s: %s"
" with cipher %s (%d/%d bits)",
!TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" :
TLS_CERT_IS_SECURED(TLScontext) ? "Verified" :
TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
props->namaddr, TLScontext->protocol,
TLScontext->cipher_name, TLScontext->cipher_usebits,
TLScontext->cipher_algbits);
if (TLScontext->kex_name && *TLScontext->kex_name) {
vstring_sprintf_append(msg, " key-exchange %s",
TLScontext->kex_name);
if (TLScontext->kex_curve && *TLScontext->kex_curve)
vstring_sprintf_append(msg, " (%s)",
TLScontext->kex_curve);
else if (TLScontext->kex_bits > 0)
vstring_sprintf_append(msg, " (%d bits)",
TLScontext->kex_bits);
}
if (TLScontext->peer_sig_name && *TLScontext->peer_sig_name) {
vstring_sprintf_append(msg, " server-signature %s",
TLScontext->peer_sig_name);
if (TLScontext->peer_sig_curve && *TLScontext->peer_sig_curve)
vstring_sprintf_append(msg, " (%s)",
TLScontext->peer_sig_curve);
else if (TLScontext->peer_sig_bits > 0)
vstring_sprintf_append(msg, " (%d bits)",
TLScontext->peer_sig_bits);
if (TLScontext->peer_sig_dgst && *TLScontext->peer_sig_dgst)
vstring_sprintf_append(msg, " server-digest %s",
TLScontext->peer_sig_dgst);
}
if (TLScontext->locl_sig_name && *TLScontext->locl_sig_name) {
vstring_sprintf_append(msg, " client-signature %s",
TLScontext->locl_sig_name);
if (TLScontext->locl_sig_curve && *TLScontext->locl_sig_curve)
vstring_sprintf_append(msg, " (%s)",
TLScontext->locl_sig_curve);
else if (TLScontext->locl_sig_bits > 0)
vstring_sprintf_append(msg, " (%d bits)",
TLScontext->locl_sig_bits);
if (TLScontext->locl_sig_dgst && *TLScontext->locl_sig_dgst)
vstring_sprintf_append(msg, " client-digest %s",
TLScontext->locl_sig_dgst);
}
msg_info("%s", vstring_str(msg));
vstring_free(msg);
}
/*
* This is the actual startup routine for the connection. We expect that the
* buffers are flushed and the "220 Ready to start TLS" was received by us,
@@ -1191,17 +1247,10 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
&& !TLS_NEVER_SECURED(props->tls_level))
TLScontext->peer_status |= TLS_CERT_FLAG_SECURED;
/*
* All the key facts in a single log entry.
*/
tls_get_signature_params(TLScontext);
if (TLScontext->log_mask & TLS_LOG_SUMMARY)
msg_info("%s TLS connection established to %s: %s with cipher %s "
"(%d/%d bits)",
!TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" :
TLS_CERT_IS_SECURED(TLScontext) ? "Verified" :
TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
TLScontext->cipher_usebits, TLScontext->cipher_algbits);
log_summary(TLScontext, props);
tls_int_seed();

View File

@@ -62,6 +62,9 @@
/* int grade;
/* const char *exclusions;
/*
/* void tls_get_signature_params(TLScontext)
/* TLS_SESS_STATE *TLScontext;
/*
/* void tls_print_errors()
/*
/* void tls_info_callback(ssl, where, ret)
@@ -143,6 +146,12 @@
/* When the input is invalid, tls_set_ciphers() logs a warning with
/* the specified context, and returns a null pointer result.
/*
/* tls_get_signature_params() updates the "TLScontext" with handshake
/* signature parameters pertaining to TLS 1.3, where the ciphersuite
/* no longer describes the asymmetric algorithms employed in the
/* handshake, which are negotiated separately. This function
/* has no effect for TLS 1.2 and earlier.
/*
/* tls_print_errors() queries the OpenSSL error stack,
/* logs the error messages, and clears the error stack.
/*
@@ -362,15 +371,16 @@ static const LONG_NAME_MASK ssl_bug_tweaks[] = {
NAMEBUG(TLSEXT_PADDING),
#if 0
/*
* XXX: New with OpenSSL 1.1.1, this is turned on implicitly in SSL_CTX_new()
* and is not included in SSL_OP_ALL. Allowing users to disable this would
* thus a code change that would clearing bug work-around bits in SSL_CTX,
* after setting SSL_OP_ALL. Since this is presumably required for TLS 1.3 on
* today's Internet, the code change will be done separately later. For now
* this implicit bug work-around cannot be disabled via supported Postfix
* mechanisms.
*/
/*
* XXX: New with OpenSSL 1.1.1, this is turned on implicitly in
* SSL_CTX_new() and is not included in SSL_OP_ALL. Allowing users to
* disable this would thus be a code change that would require clearing
* bug work-around bits in SSL_CTX, after setting SSL_OP_ALL. Since this
* is presumably required for TLS 1.3 on today's Internet, the code
* change will be done separately later. For now this implicit bug
* work-around cannot be disabled via supported Postfix mechanisms.
*/
#ifndef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
#define SSL_OP_ENABLE_MIDDLEBOX_COMPAT 0
#endif
@@ -825,6 +835,175 @@ const char *tls_set_ciphers(TLS_APPL_STATE *app_ctx, const char *context,
return (app_ctx->cipher_list = mystrdup(new_list));
}
/* tls_get_signature_params - TLS 1.3 signature details */
void tls_get_signature_params(TLS_SESS_STATE *TLScontext)
{
const char *kex_name = 0;
const char *kex_curve = 0;
const char *locl_sig_name = 0;
const char *locl_sig_curve = 0;
const char *locl_sig_dgst = 0;
const char *peer_sig_name = 0;
const char *peer_sig_curve = 0;
const char *peer_sig_dgst = 0;
#if OPENSSL_VERSION_NUMBER >= 0x1010100fUL && defined(TLS1_3_VERSION)
#ifndef OPENSSL_NO_EC
EC_KEY *eckey;
#endif
int nid;
int got_kex_key;
SSL *ssl = TLScontext->con;
X509 *cert;
EVP_PKEY *pkey = 0;
if (SSL_version(ssl) != TLS1_3_VERSION)
return;
if (tls_get_peer_dh_pubkey(ssl, &pkey)) {
switch (nid = EVP_PKEY_id(pkey)) {
default:
kex_name = OBJ_nid2sn(EVP_PKEY_type(nid));
break;
case EVP_PKEY_DH:
kex_name = "DHE";
TLScontext->kex_bits = EVP_PKEY_bits(pkey);
break;
#ifndef OPENSSL_NO_EC
case EVP_PKEY_EC:
kex_name = "ECDHE";
eckey = EVP_PKEY_get0_EC_KEY(pkey);
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
kex_curve = EC_curve_nid2nist(nid);
if (!kex_curve)
kex_curve = OBJ_nid2sn(nid);
break;
#endif
}
EVP_PKEY_free(pkey);
}
/*
* On the client end, the certificate may be preset, but not used, so we
* check via SSL_get_signature_nid(). This means that local signature
* data on clients requires at least 1.1.1a.
*/
if (SSL_is_server(ssl) || SSL_get_signature_nid(ssl, &nid))
cert = SSL_get_certificate(ssl);
else
cert = 0;
/* Signature algorithms for the local end of the connection */
if (cert) {
pkey = X509_get0_pubkey(cert);
/*
* Override the built-in name for the "ECDSA" algorithms OID, with
* the more familiar name. For "RSA" keys report "RSA-PSS", which
* must be used with TLS 1.3.
*/
if ((nid = EVP_PKEY_type(EVP_PKEY_id(pkey))) != NID_undef) {
switch (nid) {
default:
locl_sig_name = OBJ_nid2sn(nid);
break;
case EVP_PKEY_RSA:
/* For RSA, TLS 1.3 mandates PSS signatures */
locl_sig_name = "RSA-PSS";
TLScontext->locl_sig_bits = EVP_PKEY_bits(pkey);
break;
#ifndef OPENSSL_NO_EC
case EVP_PKEY_EC:
locl_sig_name = "ECDSA";
eckey = EVP_PKEY_get0_EC_KEY(pkey);
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
locl_sig_curve = EC_curve_nid2nist(nid);
if (!locl_sig_curve)
locl_sig_curve = OBJ_nid2sn(nid);
break;
#endif
}
}
/*
* With Ed25519 and Ed448 there is no pre-signature digest, but the
* accessor does not fail, rather we get NID_undef.
*/
if (SSL_get_signature_nid(ssl, &nid) && nid != NID_undef)
locl_sig_dgst = OBJ_nid2sn(nid);
}
/* Signature algorithms for the peer end of the connection */
if ((cert = SSL_get_peer_certificate(ssl)) != 0) {
pkey = X509_get0_pubkey(cert);
/*
* Override the built-in name for the "ECDSA" algorithms OID, with
* the more familiar name. For "RSA" keys report "RSA-PSS", which
* must be used with TLS 1.3.
*/
if ((nid = EVP_PKEY_type(EVP_PKEY_id(pkey))) != NID_undef) {
switch (nid) {
default:
peer_sig_name = OBJ_nid2sn(nid);
break;
case EVP_PKEY_RSA:
/* For RSA, TLS 1.3 mandates PSS signatures */
peer_sig_name = "RSA-PSS";
TLScontext->peer_sig_bits = EVP_PKEY_bits(pkey);
break;
#ifndef OPENSSL_NO_EC
case EVP_PKEY_EC:
peer_sig_name = "ECDSA";
eckey = EVP_PKEY_get0_EC_KEY(pkey);
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
peer_sig_curve = EC_curve_nid2nist(nid);
if (!peer_sig_curve)
peer_sig_curve = OBJ_nid2sn(nid);
break;
#endif
}
}
/*
* With Ed25519 and Ed448 there is no pre-signature digest, but the
* accessor does not fail, rather we get NID_undef.
*/
if (SSL_get_peer_signature_nid(ssl, &nid) && nid != NID_undef)
peer_sig_dgst = OBJ_nid2sn(nid);
}
#endif /* OPENSSL_VERSION_NUMBER >=
* 0x1010100fUL &&
* defined(TLS1_3_VERSION) */
if (kex_name) {
TLScontext->kex_name = mystrdup(kex_name);
if (kex_curve)
TLScontext->kex_curve = mystrdup(kex_curve);
}
if (locl_sig_name) {
TLScontext->locl_sig_name = mystrdup(locl_sig_name);
if (locl_sig_curve)
TLScontext->locl_sig_curve = mystrdup(locl_sig_curve);
if (locl_sig_dgst)
TLScontext->locl_sig_dgst = mystrdup(locl_sig_dgst);
}
if (peer_sig_name) {
TLScontext->peer_sig_name = mystrdup(peer_sig_name);
if (peer_sig_curve)
TLScontext->peer_sig_curve = mystrdup(peer_sig_curve);
if (peer_sig_dgst)
TLScontext->peer_sig_dgst = mystrdup(peer_sig_dgst);
}
}
/* tls_alloc_app_context - allocate TLS application context */
TLS_APPL_STATE *tls_alloc_app_context(SSL_CTX *ssl_ctx, int log_mask)
@@ -892,6 +1071,14 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
TLScontext->peer_pkey_fprint = 0;
TLScontext->protocol = 0;
TLScontext->cipher_name = 0;
TLScontext->kex_name = 0;
TLScontext->kex_curve = 0;
TLScontext->locl_sig_name = 0;
TLScontext->locl_sig_curve = 0;
TLScontext->locl_sig_dgst = 0;
TLScontext->peer_sig_name = 0;
TLScontext->peer_sig_curve = 0;
TLScontext->peer_sig_dgst = 0;
TLScontext->log_mask = log_mask;
TLScontext->namaddr = lowercase(mystrdup(namaddr));
TLScontext->mdalg = 0; /* Alias for props->mdalg */

View File

@@ -106,6 +106,17 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
#define TLS_ATTR_CIPHER_NAME "cipher_name"
#define TLS_ATTR_CIPHER_USEBITS "cipher_usebits"
#define TLS_ATTR_CIPHER_ALGBITS "cipher_algbits"
#define TLS_ATTR_KEX_NAME "key_exchange"
#define TLS_ATTR_KEX_CURVE "key_exchange_curve"
#define TLS_ATTR_KEX_BITS "key_exchange_bits"
#define TLS_ATTR_LOCL_SIG_NAME "locl_signature"
#define TLS_ATTR_LOCL_SIG_CURVE "locl_signature_curve"
#define TLS_ATTR_LOCL_SIG_BITS "locl_signature_bits"
#define TLS_ATTR_LOCL_SIG_DGST "locl_signature_digest"
#define TLS_ATTR_PEER_SIG_NAME "peer_signature"
#define TLS_ATTR_PEER_SIG_CURVE "peer_signature_curve"
#define TLS_ATTR_PEER_SIG_BITS "peer_signature_bits"
#define TLS_ATTR_PEER_SIG_DGST "peer_signature_digest"
/*
* TLS_SERVER_INIT_PROPS attributes.

View File

@@ -80,6 +80,28 @@ int tls_proxy_context_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
tp->cipher_usebits),
SEND_ATTR_INT(TLS_ATTR_CIPHER_ALGBITS,
tp->cipher_algbits),
SEND_ATTR_STR(TLS_ATTR_KEX_NAME,
STRING_OR_EMPTY(tp->kex_name)),
SEND_ATTR_STR(TLS_ATTR_KEX_CURVE,
STRING_OR_EMPTY(tp->kex_curve)),
SEND_ATTR_INT(TLS_ATTR_KEX_BITS,
tp->kex_bits),
SEND_ATTR_STR(TLS_ATTR_LOCL_SIG_NAME,
STRING_OR_EMPTY(tp->locl_sig_name)),
SEND_ATTR_STR(TLS_ATTR_LOCL_SIG_CURVE,
STRING_OR_EMPTY(tp->locl_sig_curve)),
SEND_ATTR_INT(TLS_ATTR_LOCL_SIG_BITS,
tp->locl_sig_bits),
SEND_ATTR_STR(TLS_ATTR_LOCL_SIG_DGST,
STRING_OR_EMPTY(tp->locl_sig_dgst)),
SEND_ATTR_STR(TLS_ATTR_PEER_SIG_NAME,
STRING_OR_EMPTY(tp->peer_sig_name)),
SEND_ATTR_STR(TLS_ATTR_PEER_SIG_CURVE,
STRING_OR_EMPTY(tp->peer_sig_curve)),
SEND_ATTR_INT(TLS_ATTR_PEER_SIG_BITS,
tp->peer_sig_bits),
SEND_ATTR_STR(TLS_ATTR_PEER_SIG_DGST,
STRING_OR_EMPTY(tp->peer_sig_dgst)),
ATTR_TYPE_END);
/* Do not flush the stream. */
return (ret);

View File

@@ -78,6 +78,14 @@ int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
VSTRING *peer_pkey_fprint = vstring_alloc(60); /* 60 for SHA-1 */
VSTRING *protocol = vstring_alloc(25);
VSTRING *cipher_name = vstring_alloc(25);
VSTRING *kex_name = vstring_alloc(25);
VSTRING *kex_curve = vstring_alloc(25);
VSTRING *locl_sig_name = vstring_alloc(25);
VSTRING *locl_sig_curve = vstring_alloc(25);
VSTRING *locl_sig_dgst = vstring_alloc(25);
VSTRING *peer_sig_name = vstring_alloc(25);
VSTRING *peer_sig_curve = vstring_alloc(25);
VSTRING *peer_sig_dgst = vstring_alloc(25);
if (msg_verbose)
msg_info("begin tls_proxy_context_scan");
@@ -99,6 +107,17 @@ int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
&tls_context->cipher_usebits),
RECV_ATTR_INT(TLS_ATTR_CIPHER_ALGBITS,
&tls_context->cipher_algbits),
RECV_ATTR_STR(TLS_ATTR_KEX_NAME, kex_name),
RECV_ATTR_STR(TLS_ATTR_KEX_CURVE, kex_curve),
RECV_ATTR_INT(TLS_ATTR_KEX_BITS, &tls_context->kex_bits),
RECV_ATTR_STR(TLS_ATTR_LOCL_SIG_NAME, locl_sig_name),
RECV_ATTR_STR(TLS_ATTR_LOCL_SIG_CURVE, locl_sig_curve),
RECV_ATTR_INT(TLS_ATTR_LOCL_SIG_BITS, &tls_context->locl_sig_bits),
RECV_ATTR_STR(TLS_ATTR_LOCL_SIG_DGST, locl_sig_dgst),
RECV_ATTR_STR(TLS_ATTR_PEER_SIG_NAME, peer_sig_name),
RECV_ATTR_STR(TLS_ATTR_PEER_SIG_CURVE, peer_sig_curve),
RECV_ATTR_INT(TLS_ATTR_PEER_SIG_BITS, &tls_context->peer_sig_bits),
RECV_ATTR_STR(TLS_ATTR_PEER_SIG_DGST, peer_sig_dgst),
ATTR_TYPE_END);
/* Always construct a well-formed structure. */
tls_context->peer_CN = vstring_export(peer_CN);
@@ -107,7 +126,15 @@ int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
tls_context->peer_pkey_fprint = vstring_export(peer_pkey_fprint);
tls_context->protocol = vstring_export(protocol);
tls_context->cipher_name = vstring_export(cipher_name);
ret = (ret == 9 ? 1 : -1);
tls_context->kex_name = vstring_export(kex_name);
tls_context->kex_curve = vstring_export(kex_curve);
tls_context->locl_sig_name = vstring_export(locl_sig_name);
tls_context->locl_sig_curve = vstring_export(locl_sig_curve);
tls_context->locl_sig_dgst = vstring_export(locl_sig_dgst);
tls_context->peer_sig_name = vstring_export(peer_sig_name);
tls_context->peer_sig_curve = vstring_export(peer_sig_curve);
tls_context->peer_sig_dgst = vstring_export(peer_sig_dgst);
ret = (ret == 20 ? 1 : -1);
if (ret != 1) {
tls_proxy_context_free(tls_context);
tls_context = 0;
@@ -134,6 +161,22 @@ void tls_proxy_context_free(TLS_SESS_STATE *tls_context)
myfree((void *) tls_context->protocol);
if (tls_context->cipher_name)
myfree((void *) tls_context->cipher_name);
if (tls_context->kex_name)
myfree((void *) tls_context->kex_name);
if (tls_context->kex_curve)
myfree((void *) tls_context->kex_curve);
if (tls_context->locl_sig_name)
myfree((void *) tls_context->locl_sig_name);
if (tls_context->locl_sig_curve)
myfree((void *) tls_context->locl_sig_curve);
if (tls_context->locl_sig_dgst)
myfree((void *) tls_context->locl_sig_dgst);
if (tls_context->peer_sig_name)
myfree((void *) tls_context->peer_sig_name);
if (tls_context->peer_sig_curve)
myfree((void *) tls_context->peer_sig_curve);
if (tls_context->peer_sig_dgst)
myfree((void *) tls_context->peer_sig_dgst);
myfree((void *) tls_context);
}

View File

@@ -345,6 +345,60 @@ static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
#endif
/* log_summary - TLS loglevel 1 one-liner, embellished with TLS 1.3 details */
static void log_summary(TLS_SESS_STATE *TLScontext)
{
VSTRING *msg = vstring_alloc(100);
vstring_sprintf(msg, "%s TLS connection established from %s: %s"
" with cipher %s (%d/%d bits)",
!TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" :
TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
TLScontext->namaddr, TLScontext->protocol,
TLScontext->cipher_name, TLScontext->cipher_usebits,
TLScontext->cipher_algbits);
if (TLScontext->kex_name && *TLScontext->kex_name) {
vstring_sprintf_append(msg, " key-exchange %s",
TLScontext->kex_name);
if (TLScontext->kex_curve && *TLScontext->kex_curve)
vstring_sprintf_append(msg, " (%s)",
TLScontext->kex_curve);
else if (TLScontext->kex_bits > 0)
vstring_sprintf_append(msg, " (%d bits)",
TLScontext->kex_bits);
}
if (TLScontext->locl_sig_name && *TLScontext->locl_sig_name) {
vstring_sprintf_append(msg, " server-signature %s",
TLScontext->locl_sig_name);
if (TLScontext->locl_sig_curve && *TLScontext->locl_sig_curve)
vstring_sprintf_append(msg, " (%s)",
TLScontext->locl_sig_curve);
else if (TLScontext->locl_sig_bits > 0)
vstring_sprintf_append(msg, " (%d bits)",
TLScontext->locl_sig_bits);
if (TLScontext->locl_sig_dgst && *TLScontext->locl_sig_dgst)
vstring_sprintf_append(msg, " server-digest %s",
TLScontext->locl_sig_dgst);
}
if (TLScontext->peer_sig_name && *TLScontext->peer_sig_name) {
vstring_sprintf_append(msg, " client-signature %s",
TLScontext->peer_sig_name);
if (TLScontext->peer_sig_curve && *TLScontext->peer_sig_curve)
vstring_sprintf_append(msg, " (%s)",
TLScontext->peer_sig_curve);
else if (TLScontext->peer_sig_bits > 0)
vstring_sprintf_append(msg, " (%d bits)",
TLScontext->peer_sig_bits);
if (TLScontext->peer_sig_dgst && *TLScontext->peer_sig_dgst)
vstring_sprintf_append(msg, " client-digest %s",
TLScontext->peer_sig_dgst);
}
msg_info("%s", vstring_str(msg));
vstring_free(msg);
}
/* tls_server_init - initialize the server-side TLS engine */
TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
@@ -504,18 +558,19 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
}
if (ticketable) {
SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_cb);
/*
* OpenSSL 1.1.1 introduces support for TLS 1.3, which can issue more
* than one ticket per handshake. While this may be appropriate for
* communication between browsers and webservers, it is not terribly
* useful for MTAs, many of which other than Postfix don't do TLS
* session caching at all, and Postfix has no mechanism for storing
* multiple session tickets, if more than one sent, the second clobbers
* the first. OpenSSL 1.1.1 servers default to issuing two tickets for
* non-resumption handshakes, we reduce this to one. Our ticket
* decryption callback already (since 2.11) asks OpenSSL to avoid
* issuing new tickets when the presented ticket is re-usable.
*/
/*
* OpenSSL 1.1.1 introduces support for TLS 1.3, which can issue more
* than one ticket per handshake. While this may be appropriate for
* communication between browsers and webservers, it is not terribly
* useful for MTAs, many of which other than Postfix don't do TLS
* session caching at all, and Postfix has no mechanism for storing
* multiple session tickets, if more than one sent, the second
* clobbers the first. OpenSSL 1.1.1 servers default to issuing two
* tickets for non-resumption handshakes, we reduce this to one. Our
* ticket decryption callback already (since 2.11) asks OpenSSL to
* avoid issuing new tickets when the presented ticket is re-usable.
*/
SSL_CTX_set_num_tickets(server_ctx, 1);
}
#endif
@@ -951,15 +1006,16 @@ TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
if (TLScontext->stream != 0)
tls_stream_start(TLScontext->stream, TLScontext);
/*
* With the handshake done, extract TLS 1.3 signature metadata.
*/
tls_get_signature_params(TLScontext);
/*
* All the key facts in a single log entry.
*/
if (TLScontext->log_mask & TLS_LOG_SUMMARY)
msg_info("%s TLS connection established from %s: %s with cipher %s "
"(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous"
: TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
TLScontext->namaddr, TLScontext->protocol, TLScontext->cipher_name,
TLScontext->cipher_usebits, TLScontext->cipher_algbits);
log_summary(TLScontext);
tls_int_seed();

View File

@@ -629,7 +629,7 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
#endif
#if DB_VERSION_MAJOR > 2
DB_ENV *dbenv;
DB_ENV *dbenv = 0;
#endif
@@ -674,12 +674,22 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
* db_open() create a non-existent file for us.
*/
#define LOCK_OPEN_FLAGS(f) ((f) & ~(O_CREAT|O_TRUNC))
#if DB_VERSION_MAJOR <= 2
#define FREE_RETURN(e) do { \
DICT *_dict = (e); if (db) DICT_DB_CLOSE(db); \
if (lock_fd >= 0) (void) close(lock_fd); \
if (db_base_buf) vstring_free(db_base_buf); \
if (db_path) myfree(db_path); return (_dict); \
} while (0)
#else
#define FREE_RETURN(e) do { \
DICT *_dict = (e); if (db) DICT_DB_CLOSE(db); \
if (dbenv) dbenv->close(dbenv, 0); \
if (lock_fd >= 0) (void) close(lock_fd); \
if (db_base_buf) vstring_free(db_base_buf); \
if (db_path) myfree(db_path); return (_dict); \
} while (0)
#endif
if (dict_flags & DICT_FLAG_LOCK) {
if ((lock_fd = open(db_path, LOCK_OPEN_FLAGS(open_flags), 0644)) < 0) {