mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 09:57:34 +00:00
postfix-2.11-20140104
This commit is contained in:
parent
6ff1c3ac62
commit
4a25a6b519
@ -19462,10 +19462,33 @@ Apologies for any names omitted.
|
||||
Cleanup: DANE support: test script. Viktor Dukhovni. File
|
||||
tls/tls_dane.sh.
|
||||
|
||||
LMDB will not be supported in the stable Postfix 2.11 release.
|
||||
Debugging: test driver for LMDB debugging and stress testing.
|
||||
Shockingly, LMDB terminates the postscreen daemon without
|
||||
logfile record. File: util/dict_cache.c.
|
||||
|
||||
Debugging: test driver to speed up LMDB debugging and stress
|
||||
testing. Shockingly, LMDB terminates the postcreen daemon
|
||||
without logfile record. Fixing this will require changes
|
||||
in LMDB or changes in the way Postfix can use LMDB. File:
|
||||
util/dict_cache.c.
|
||||
Because of the above behavior, LMDB cannot be supported in
|
||||
the stable Postfix 2.11 release.
|
||||
|
||||
20140102
|
||||
|
||||
Bugfix: close the LMDB database cursor's read transaction
|
||||
before writing with MDB_NOLOCK and before changing the
|
||||
database memory map size. File: util/slmdb.c.
|
||||
|
||||
20140103
|
||||
|
||||
Cleanup: eliminated data duplication from the new SMTP_ITERATOR
|
||||
structure to the old SMTP_SESSION structure. The SMTP_ITERATOR
|
||||
structure now maintains the sole copy. Files: smtp/smtp.h,
|
||||
smtp_sasl_auth_cache.c, smtp_reuse.c, smtp_sasl_glue.c,
|
||||
smtp_rcpt.c, smtp_session.c, smtp_chat.c, smtp_proto.c,
|
||||
smtp_connect.c.
|
||||
|
||||
20130104
|
||||
|
||||
Feature: support for optional configuration files
|
||||
"$daemon-directory/postfix-files.d/*". These are processed
|
||||
in sorted order after "$daemon-directory/postfix-files",
|
||||
This avoids breaking "postfix set-permissions" etc. when a
|
||||
Postfix distributions comes in multiple packages. File:
|
||||
conf/post-install.
|
||||
|
@ -82,20 +82,21 @@ element of that group called a "generator". Presently, there are two flavors of
|
||||
|
||||
* PPrriimmee--ffiieelldd ggrroouuppss ((EEDDHH)):: The server needs to be configured with a
|
||||
suitably-large prime and a corresponding "generator". The acronym for
|
||||
forward secrecy over prime fields is EDH or Ephemeral Diffie-Hellman
|
||||
(sometimes also abbreviated as DHE).
|
||||
forward secrecy over prime fields is EDH for Ephemeral Diffie-Hellman (also
|
||||
abbreviated as DHE for Diffie-Hellman Exchange).
|
||||
|
||||
* EElllliippttiicc--ccuurrvvee ggrroouuppss ((EEEECCDDHH)):: The server needs to be configured with a
|
||||
"named curve". These offer better security at lower computational cost than
|
||||
prime field groups, but are not as widely implemented. The acronym for the
|
||||
elliptic curve version is EECDH which is short for Ephemeral Elliptic Curve
|
||||
Diffie-Hellman.
|
||||
Diffie-Hellman (also abbreviated as ECDHE for Elliptic Curve Diffie-Hellman
|
||||
Exchange).
|
||||
|
||||
It is not essential to know what these are, but one does need to know that
|
||||
OpenSSL only supports EECDH as of version 1.0.0. Thus the configuration
|
||||
parameters related to Elliptic Curve forward secrecy are only available when
|
||||
Postfix is linked with OpenSSL 1.0.0 or later (provided EC support has not been
|
||||
disabled by the vendor, as in some versions of RedHat Linux).
|
||||
OpenSSL supports EECDH with version 1.0.0 or later. Thus the configuration
|
||||
parameters related to Elliptic-Curve forward secrecy are available when Postfix
|
||||
is linked with OpenSSL >= 1.0.0 (provided EC support has not been disabled by
|
||||
the vendor, as in some versions of RedHat Linux).
|
||||
|
||||
Elliptic curves used in cryptography are typically identified by a "name" that
|
||||
stands for a set of well-known parameter values, and it is these "names" (or
|
||||
@ -141,9 +142,8 @@ configured overrides.
|
||||
1024 bits long (see the quick-start section for details).
|
||||
|
||||
It turns out that (inadvisably-patched in some Debian releases) Exim SMTP
|
||||
clients enforce a minimum 2048-bit length for the non-export prime. See the
|
||||
quick-start section for the recommended configuration to work around this
|
||||
issue.
|
||||
clients require a >= 2048-bit length for the non-export prime. See the quick-
|
||||
start section for the recommended configuration to work around this issue.
|
||||
|
||||
EEEECCDDHH SSeerrvveerr ssuuppppoorrtt
|
||||
|
||||
@ -198,50 +198,60 @@ a case-by-case basis via the TLS policy table.
|
||||
|
||||
GGeettttiinngg ssttaarrtteedd,, qquuiicckk aanndd ddiirrttyy
|
||||
|
||||
* Postfix 2.6 and 2.7: Enable elliptic-curve support. This is the default
|
||||
with Postfix >= 2.8.
|
||||
EEEECCDDHH CClliieenntt aanndd sseerrvveerr ssuuppppoorrtt ((PPoossttffiixx >>== 22..66 wwiitthh OOppeennSSSSLL >>== 11..00..00))
|
||||
|
||||
/etc/postfix/main.cf:
|
||||
# Postfix 2.6 or 2.7 only. This is default with Postfix 2.8 and
|
||||
later.
|
||||
smtpd_tls_eecdh_grade = strong
|
||||
With Postfix 2.6 and 2.7, enable elliptic-curve support in the Postfix SMTP
|
||||
client and server. This is the default with Postfix >= 2.8.
|
||||
|
||||
* Optionally generate non-default EDH parameters for improved security
|
||||
against pre-computation attacks and for compatibility with Debian-patched
|
||||
EXIM SMTP clients (these require a minimum 2048-bit length for the non-
|
||||
export prime). The parameter files are not secret, after all these
|
||||
parameters are sent to all SMTP clients in the clear. Mode 0644 is fine.
|
||||
/etc/postfix/main.cf:
|
||||
# Postfix 2.6 or 2.7 only. This is default with Postfix 2.8 and later.
|
||||
smtpd_tls_eecdh_grade = strong
|
||||
|
||||
Execute as root (prime group generation can take a few seconds to a few
|
||||
minutes):
|
||||
EEDDHH CClliieenntt ssuuppppoorrtt ((PPoossttffiixx >>== 22..22))
|
||||
|
||||
# cd /etc/postfix
|
||||
# openssl dhparam -out dh512.tmp 512 && mv dh512.tmp dh512.pem
|
||||
# openssl dhparam -out dh1024.tmp 1024 && mv dh1024.tmp dh1024.pem
|
||||
# openssl dhparam -out dh2048.tmp 2048 && mv dh2048.tmp dh2048.pem
|
||||
# chmod 644 dh512.pem dh1024.pem dh2048.pem
|
||||
This space intentionally left blank.
|
||||
|
||||
You can improve security against pre-computation attacks further by
|
||||
regenerating the EDH parameters periodically (an hourly or daily cron job
|
||||
running as root can automate this task).
|
||||
EEDDHH SSeerrvveerr ssuuppppoorrtt ((PPoossttffiixx >>== 22..22))
|
||||
|
||||
Once the parameters are in place, update main.cf as follows:
|
||||
Optionally generate non-default Postfix SMTP server EDH parameters for improved
|
||||
security against pre-computation attacks and for compatibility with Debian-
|
||||
patched Exim SMTP clients that require a >= 2048-bit length for the non-export
|
||||
prime.
|
||||
|
||||
/etc/postfix/main.cf:
|
||||
smtpd_tls_dh1024_param_file = ${config_directory}/dh2048.pem
|
||||
smtpd_tls_dh512_param_file = ${config_directory}/dh512.pem
|
||||
Execute as root (prime group generation can take a few seconds to a few
|
||||
minutes):
|
||||
|
||||
If some of your MSA clients don't support 2048-bit EDH, you may need to
|
||||
adjust the submission entry in master.cf accordingly:
|
||||
# cd /etc/postfix
|
||||
# umask 022
|
||||
# openssl dhparam -out dh512.tmp 512 && mv dh512.tmp dh512.pem
|
||||
# openssl dhparam -out dh1024.tmp 1024 && mv dh1024.tmp dh1024.pem
|
||||
# openssl dhparam -out dh2048.tmp 2048 && mv dh2048.tmp dh2048.pem
|
||||
# chmod 644 dh512.pem dh1024.pem dh2048.pem
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
submission inet n - n - - smtpd
|
||||
# Some submission clients may not yet do 2048-bit EDH, if such
|
||||
# clients use your MSA, configure 1024-bit EDH instead:
|
||||
-o smtpd_tls_dh1024_param_file=${config_directory}/dh1024.pem
|
||||
-o smtpd_tls_security_level=encrypt
|
||||
-o smtpd_sasl_auth_enable=yes
|
||||
...
|
||||
The Postfix SMTP server EDH parameter files are not secret, after all these
|
||||
parameters are sent to all remote SMTP clients in the clear. Mode 0644 is fine.
|
||||
|
||||
You can improve security against pre-computation attacks further by
|
||||
regenerating the Postfix SMTP server EDH parameters periodically (an hourly or
|
||||
daily cron job running the above commands as root can automate this task).
|
||||
|
||||
Once the parameters are in place, update main.cf as follows:
|
||||
|
||||
/etc/postfix/main.cf:
|
||||
smtpd_tls_dh1024_param_file = ${config_directory}/dh2048.pem
|
||||
smtpd_tls_dh512_param_file = ${config_directory}/dh512.pem
|
||||
|
||||
If some of your MSA clients don't support 2048-bit EDH, you may need to adjust
|
||||
the submission entry in master.cf accordingly:
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
submission inet n - n - - smtpd
|
||||
# Some submission clients may not yet do 2048-bit EDH, if such
|
||||
# clients use your MSA, configure 1024-bit EDH instead:
|
||||
-o smtpd_tls_dh1024_param_file=${config_directory}/dh1024.pem
|
||||
-o smtpd_tls_security_level=encrypt
|
||||
-o smtpd_sasl_auth_enable=yes
|
||||
...
|
||||
|
||||
HHooww ccaann II sseeee tthhaatt aa ccoonnnneeccttiioonn hhaass ffoorrwwaarrdd sseeccrreeccyy??
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
X
|
||||
|
||||
PPoossttffiixx SSAASSLL HHoowwttoo
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -40,25 +40,31 @@
|
||||
# Arguments
|
||||
# .IP create-missing
|
||||
# Create missing queue directories with ownerships and permissions
|
||||
# according to the contents of $daemon_directory/postfix-files, using
|
||||
# the mail_owner and setgid_group parameter settings from the command
|
||||
# line, process environment or from the installed main.cf file.
|
||||
# according to the contents of $daemon_directory/postfix-files
|
||||
# and optionally in $daemon_directory/postfix-files.d/*, using
|
||||
# the mail_owner and setgid_group parameter settings from the
|
||||
# command line, process environment or from the installed
|
||||
# main.cf file.
|
||||
#
|
||||
# This is required at Postfix start-up time.
|
||||
# .IP set-permissions
|
||||
# Set all file/directory ownerships and permissions according to the
|
||||
# contents of $daemon_directory/postfix-files, using the mail_owner
|
||||
# and setgid_group parameter settings from the command line, process
|
||||
# environment or from the installed main.cf file. Implies create-missing.
|
||||
# contents of $daemon_directory/postfix-files and optionally
|
||||
# in $daemon_directory/postfix-files.d/*, using the mail_owner
|
||||
# and setgid_group parameter settings from the command line,
|
||||
# process environment or from the installed main.cf file.
|
||||
# Implies create-missing.
|
||||
#
|
||||
# This is required when installing Postfix from a pre-built package,
|
||||
# or when changing the mail_owner or setgid_group installation parameter
|
||||
# settings after Postfix is already installed.
|
||||
# .IP upgrade-permissions
|
||||
# Update ownership and permission of existing files/directories as
|
||||
# specified in $daemon_directory/postfix-files, using the mail_owner
|
||||
# and setgid_group parameter settings from the command line, process
|
||||
# environment or from the installed main.cf file. Implies create-missing.
|
||||
# specified in $daemon_directory/postfix-files and optionally
|
||||
# in $daemon_directory/postfix-files.d/*, using the mail_owner
|
||||
# and setgid_group parameter settings from the command line,
|
||||
# process environment or from the installed main.cf file.
|
||||
# Implies create-missing.
|
||||
#
|
||||
# This is required when upgrading an existing Postfix instance.
|
||||
# .IP upgrade-configuration
|
||||
@ -174,6 +180,7 @@
|
||||
# FILES
|
||||
# $config_directory/main.cf, Postfix installation parameters.
|
||||
# $daemon_directory/postfix-files, installation control file.
|
||||
# $daemon_directory/postfix-files.d/*, optional control files.
|
||||
# $config_directory/install.cf, obsolete configuration file.
|
||||
# LICENSE
|
||||
# .ad
|
||||
@ -437,91 +444,96 @@ test -n "$override" && {
|
||||
# Use file/directory status information in $daemon_directory/postfix-files.
|
||||
|
||||
test -n "$create" && {
|
||||
exec <$daemon_directory/postfix-files || exit 1
|
||||
while IFS=: read path type owner group mode flags junk
|
||||
postfix_files_d=$daemon_directory/postfix-files.d
|
||||
for postfix_file in $daemon_directory/postfix-files \
|
||||
`test -d $postfix_files_d && { find $postfix_files_d -type f | sort; }`
|
||||
do
|
||||
IFS="$BACKUP_IFS"
|
||||
set_permission=
|
||||
# Skip comments. Skip shared files, if updating a secondary instance.
|
||||
case $path in
|
||||
[$]*) case "$update_shared_files" in
|
||||
1) $debug keep non-shared or shared $path;;
|
||||
*) non_shared=
|
||||
for name in $NON_SHARED
|
||||
do
|
||||
case $path in
|
||||
"\$$name"*) non_shared=1; break;;
|
||||
esac
|
||||
done
|
||||
case "$non_shared" in
|
||||
1) $debug keep non-shared $path;;
|
||||
*) $debug skip shared $path; continue;;
|
||||
esac;;
|
||||
esac;;
|
||||
*) continue;;
|
||||
esac
|
||||
# Skip hard links and symbolic links.
|
||||
case $type in
|
||||
[hl]) continue;;
|
||||
[df]) ;;
|
||||
*) echo unknown type $type for $path in $daemon_directory/postfix-files1>&2; exit 1;;
|
||||
esac
|
||||
# Expand $name, and canonicalize null fields.
|
||||
for name in path owner group flags
|
||||
exec <$postfix_file || exit 1
|
||||
while IFS=: read path type owner group mode flags junk
|
||||
do
|
||||
eval junk=\${$name}
|
||||
case $junk in
|
||||
[$]*) eval $name=$junk;;
|
||||
-) eval $name=;;
|
||||
*) ;;
|
||||
IFS="$BACKUP_IFS"
|
||||
set_permission=
|
||||
# Skip comments. Skip shared files, if updating a secondary instance.
|
||||
case $path in
|
||||
[$]*) case "$update_shared_files" in
|
||||
1) $debug keep non-shared or shared $path;;
|
||||
*) non_shared=
|
||||
for name in $NON_SHARED
|
||||
do
|
||||
case $path in
|
||||
"\$$name"*) non_shared=1; break;;
|
||||
esac
|
||||
done
|
||||
case "$non_shared" in
|
||||
1) $debug keep non-shared $path;;
|
||||
*) $debug skip shared $path; continue;;
|
||||
esac;;
|
||||
esac;;
|
||||
*) continue;;
|
||||
esac
|
||||
done
|
||||
# Skip uninstalled files.
|
||||
case $path in
|
||||
no|no/*) continue;;
|
||||
esac
|
||||
# Pick up the flags.
|
||||
case $flags in *u*) upgrade_flag=1;; *) upgrade_flag=;; esac
|
||||
case $flags in *c*) create_flag=1;; *) create_flag=;; esac
|
||||
case $flags in *r*) recursive="-R";; *) recursive=;; esac
|
||||
case $flags in *o*) obsolete_flag=1;; *) obsolete_flag=;; esac
|
||||
case $flags in *[1i]*) test ! -r "$path" -a "$config_directory" != \
|
||||
"$def_config_directory" && continue;; esac
|
||||
# Flag obsolete objects. XXX Solaris 2..9 does not have "test -e".
|
||||
if [ -n "$obsolete_flag" ]
|
||||
then
|
||||
test -r $path -a "$type" != "d" && obsolete="$obsolete $path"
|
||||
continue;
|
||||
else
|
||||
keep_list="$keep_list $path"
|
||||
fi
|
||||
# Create missing directories with proper owner/group/mode settings.
|
||||
if [ -n "$create" -a "$type" = "d" -a -n "$create_flag" -a ! -d "$path" ]
|
||||
then
|
||||
mkdir $path || exit 1
|
||||
set_permission=1
|
||||
# Update all owner/group/mode settings.
|
||||
elif [ -n "$set_perms" ]
|
||||
then
|
||||
set_permission=1
|
||||
# Update obsolete owner/group/mode settings.
|
||||
elif [ -n "$upgrade_perms" -a -n "$upgrade_flag" ]
|
||||
then
|
||||
set_permission=1
|
||||
fi
|
||||
test -n "$set_permission" && {
|
||||
chown $recursive $owner $path || exit 1
|
||||
test -z "$group" || chgrp $recursive $group $path || exit 1
|
||||
# Don't "chmod -R"; queue file status is encoded in mode bits.
|
||||
if [ "$type" = "d" -a -n "$recursive" ]
|
||||
# Skip hard links and symbolic links.
|
||||
case $type in
|
||||
[hl]) continue;;
|
||||
[df]) ;;
|
||||
*) echo unknown type $type for $path in $postfix_file 1>&2; exit 1;;
|
||||
esac
|
||||
# Expand $name, and canonicalize null fields.
|
||||
for name in path owner group flags
|
||||
do
|
||||
eval junk=\${$name}
|
||||
case $junk in
|
||||
[$]*) eval $name=$junk;;
|
||||
-) eval $name=;;
|
||||
*) ;;
|
||||
esac
|
||||
done
|
||||
# Skip uninstalled files.
|
||||
case $path in
|
||||
no|no/*) continue;;
|
||||
esac
|
||||
# Pick up the flags.
|
||||
case $flags in *u*) upgrade_flag=1;; *) upgrade_flag=;; esac
|
||||
case $flags in *c*) create_flag=1;; *) create_flag=;; esac
|
||||
case $flags in *r*) recursive="-R";; *) recursive=;; esac
|
||||
case $flags in *o*) obsolete_flag=1;; *) obsolete_flag=;; esac
|
||||
case $flags in *[1i]*) test ! -r "$path" -a "$config_directory" != \
|
||||
"$def_config_directory" && continue;; esac
|
||||
# Flag obsolete objects. XXX Solaris 2..9 does not have "test -e".
|
||||
if [ -n "$obsolete_flag" ]
|
||||
then
|
||||
find $path -type d -exec chmod $mode "{}" ";"
|
||||
test -r $path -a "$type" != "d" && obsolete="$obsolete $path"
|
||||
continue;
|
||||
else
|
||||
chmod $mode $path
|
||||
fi || exit 1
|
||||
}
|
||||
keep_list="$keep_list $path"
|
||||
fi
|
||||
# Create missing directories with proper owner/group/mode settings.
|
||||
if [ -n "$create" -a "$type" = "d" -a -n "$create_flag" -a ! -d "$path" ]
|
||||
then
|
||||
mkdir $path || exit 1
|
||||
set_permission=1
|
||||
# Update all owner/group/mode settings.
|
||||
elif [ -n "$set_perms" ]
|
||||
then
|
||||
set_permission=1
|
||||
# Update obsolete owner/group/mode settings.
|
||||
elif [ -n "$upgrade_perms" -a -n "$upgrade_flag" ]
|
||||
then
|
||||
set_permission=1
|
||||
fi
|
||||
test -n "$set_permission" && {
|
||||
chown $recursive $owner $path || exit 1
|
||||
test -z "$group" || chgrp $recursive $group $path || exit 1
|
||||
# Don't "chmod -R"; queue file status is encoded in mode bits.
|
||||
if [ "$type" = "d" -a -n "$recursive" ]
|
||||
then
|
||||
find $path -type d -exec chmod $mode "{}" ";"
|
||||
else
|
||||
chmod $mode $path
|
||||
fi || exit 1
|
||||
}
|
||||
done
|
||||
IFS="$BACKUP_IFS"
|
||||
done
|
||||
IFS="$BACKUP_IFS"
|
||||
}
|
||||
|
||||
# Upgrade existing Postfix configuration files if necessary.
|
||||
|
@ -125,24 +125,26 @@ Presently, there are two flavors of "groups" that work with PFS: </p>
|
||||
|
||||
<li> <p> <b> Prime-field groups (EDH):</b> The server needs to be
|
||||
configured with a suitably-large prime and a corresponding "generator".
|
||||
The acronym for forward secrecy over prime fields is EDH or Ephemeral
|
||||
Diffie-Hellman (sometimes also abbreviated as DHE). </p>
|
||||
The acronym for forward secrecy over prime fields is EDH for Ephemeral
|
||||
Diffie-Hellman (also abbreviated as DHE for Diffie-Hellman Exchange).
|
||||
</p>
|
||||
|
||||
<li> <p> <b> Elliptic-curve groups (EECDH): </b> The server needs
|
||||
to be configured with a "named curve". These offer better security
|
||||
at lower computational cost than prime field groups, but are not
|
||||
as widely implemented. The acronym for the elliptic curve version
|
||||
is EECDH which is short for Ephemeral Elliptic Curve Diffie-Hellman.
|
||||
</p>
|
||||
is EECDH which is short for Ephemeral Elliptic Curve Diffie-Hellman
|
||||
(also abbreviated as ECDHE for Elliptic Curve Diffie-Hellman
|
||||
Exchange). </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> It is not essential to know what these are, but one does need
|
||||
to know that OpenSSL only supports EECDH as of version 1.0.0. Thus
|
||||
the configuration parameters related to Elliptic Curve forward secrecy
|
||||
are only available when Postfix is linked with OpenSSL 1.0.0 or
|
||||
later (provided EC support has not been disabled by the vendor, as
|
||||
in some versions of RedHat Linux). </p>
|
||||
to know that OpenSSL supports EECDH with version 1.0.0 or later.
|
||||
Thus the configuration parameters related to Elliptic-Curve forward
|
||||
secrecy are available when Postfix is linked with OpenSSL ≥ 1.0.0
|
||||
(provided EC support has not been disabled by the vendor, as in
|
||||
some versions of RedHat Linux). </p>
|
||||
|
||||
<p> Elliptic curves used in cryptography are typically identified
|
||||
by a "name" that stands for a set of well-known parameter values,
|
||||
@ -200,7 +202,7 @@ parameter file and the prime need not actually be 1024 bits long
|
||||
</ul>
|
||||
|
||||
<p> It turns out that (inadvisably-patched in some Debian releases)
|
||||
Exim SMTP clients enforce a minimum 2048-bit length for the non-export
|
||||
Exim SMTP clients require a ≥ 2048-bit length for the non-export
|
||||
prime. See the <a href="#quick-start">quick-start</a> section for
|
||||
the recommended configuration to work around this issue. </p>
|
||||
|
||||
@ -269,10 +271,12 @@ href="TLS_README.html#client_tls_policy">TLS policy</a> table. </p>
|
||||
|
||||
<h2><a name="quick-start">Getting started, quick and dirty</a></h2>
|
||||
|
||||
<ul>
|
||||
<h3> EECDH Client and server support (Postfix ≥ 2.6 with OpenSSL
|
||||
≥ 1.0.0) </h3>
|
||||
|
||||
<li> <p> Postfix 2.6 and 2.7: Enable elliptic-curve support. This
|
||||
is the default with Postfix ≥ 2.8.
|
||||
<p> With Postfix 2.6 and 2.7, enable elliptic-curve support in the
|
||||
Postfix SMTP client and server. This is the default with Postfix
|
||||
≥ 2.8.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
@ -282,12 +286,16 @@ is the default with Postfix ≥ 2.8.
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<li> <p> Optionally generate non-default EDH parameters for improved
|
||||
security against pre-computation attacks and for compatibility with
|
||||
Debian-patched EXIM SMTP clients (these require a minimum 2048-bit
|
||||
length for the non-export prime). The parameter files are not
|
||||
secret, after all these parameters are sent to all SMTP clients in
|
||||
the clear. Mode 0644 is fine. </p>
|
||||
<h3> EDH Client support (Postfix ≥ 2.2) </h3>
|
||||
|
||||
<p> This space intentionally left blank. </p>
|
||||
|
||||
<h3> EDH Server support (Postfix ≥ 2.2) </h3>
|
||||
|
||||
<p> Optionally generate non-default Postfix SMTP server EDH parameters
|
||||
for improved security against pre-computation attacks and for
|
||||
compatibility with Debian-patched Exim SMTP clients that require a
|
||||
≥ 2048-bit length for the non-export prime. </p>
|
||||
|
||||
<p> Execute as root (prime group generation can take a
|
||||
few seconds to a few minutes): </p>
|
||||
@ -295,6 +303,7 @@ few seconds to a few minutes): </p>
|
||||
<blockquote>
|
||||
<pre>
|
||||
# cd /etc/postfix
|
||||
# umask 022
|
||||
# openssl dhparam -out dh512.tmp 512 && mv dh512.tmp dh512.pem
|
||||
# openssl dhparam -out dh1024.tmp 1024 && mv dh1024.tmp dh1024.pem
|
||||
# openssl dhparam -out dh2048.tmp 2048 && mv dh2048.tmp dh2048.pem
|
||||
@ -302,9 +311,14 @@ few seconds to a few minutes): </p>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> The Postfix SMTP server EDH parameter files are not secret,
|
||||
after all these parameters are sent to all remote SMTP clients in
|
||||
the clear. Mode 0644 is fine. </p>
|
||||
|
||||
<p> You can improve security against pre-computation attacks further
|
||||
by regenerating the EDH parameters periodically (an hourly or daily
|
||||
cron job running as root can automate this task). </p>
|
||||
by regenerating the Postfix SMTP server EDH parameters periodically
|
||||
(an hourly or daily cron job running the above commands as root can
|
||||
automate this task). </p>
|
||||
|
||||
<p> Once the parameters are in place, update <a href="postconf.5.html">main.cf</a> as follows: </p>
|
||||
|
||||
@ -332,8 +346,6 @@ need to adjust the submission entry in <a href="master.5.html">master.cf</a> acc
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2><a name="test">How can I see that a connection has forward
|
||||
secrecy? </a> </h2>
|
||||
|
||||
@ -392,7 +404,7 @@ OpenSSL 1.0.1e. The list is sorted in the default Postfix preference
|
||||
order. It excludes null ciphers that only authenticate and don't
|
||||
encrypt, together with export and low-grade ciphers whose encryption
|
||||
is too weak to offer meaningful secrecy. The first column shows the
|
||||
cipher name, and the second shows the key exchange method. </p>
|
||||
cipher name, and the second shows the key exchange method. </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
@ -1,4 +1,4 @@
|
||||
X<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<head>
|
||||
|
@ -125,24 +125,26 @@ Presently, there are two flavors of "groups" that work with PFS: </p>
|
||||
|
||||
<li> <p> <b> Prime-field groups (EDH):</b> The server needs to be
|
||||
configured with a suitably-large prime and a corresponding "generator".
|
||||
The acronym for forward secrecy over prime fields is EDH or Ephemeral
|
||||
Diffie-Hellman (sometimes also abbreviated as DHE). </p>
|
||||
The acronym for forward secrecy over prime fields is EDH for Ephemeral
|
||||
Diffie-Hellman (also abbreviated as DHE for Diffie-Hellman Exchange).
|
||||
</p>
|
||||
|
||||
<li> <p> <b> Elliptic-curve groups (EECDH): </b> The server needs
|
||||
to be configured with a "named curve". These offer better security
|
||||
at lower computational cost than prime field groups, but are not
|
||||
as widely implemented. The acronym for the elliptic curve version
|
||||
is EECDH which is short for Ephemeral Elliptic Curve Diffie-Hellman.
|
||||
</p>
|
||||
is EECDH which is short for Ephemeral Elliptic Curve Diffie-Hellman
|
||||
(also abbreviated as ECDHE for Elliptic Curve Diffie-Hellman
|
||||
Exchange). </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> It is not essential to know what these are, but one does need
|
||||
to know that OpenSSL only supports EECDH as of version 1.0.0. Thus
|
||||
the configuration parameters related to Elliptic Curve forward secrecy
|
||||
are only available when Postfix is linked with OpenSSL 1.0.0 or
|
||||
later (provided EC support has not been disabled by the vendor, as
|
||||
in some versions of RedHat Linux). </p>
|
||||
to know that OpenSSL supports EECDH with version 1.0.0 or later.
|
||||
Thus the configuration parameters related to Elliptic-Curve forward
|
||||
secrecy are available when Postfix is linked with OpenSSL ≥ 1.0.0
|
||||
(provided EC support has not been disabled by the vendor, as in
|
||||
some versions of RedHat Linux). </p>
|
||||
|
||||
<p> Elliptic curves used in cryptography are typically identified
|
||||
by a "name" that stands for a set of well-known parameter values,
|
||||
@ -200,7 +202,7 @@ parameter file and the prime need not actually be 1024 bits long
|
||||
</ul>
|
||||
|
||||
<p> It turns out that (inadvisably-patched in some Debian releases)
|
||||
Exim SMTP clients enforce a minimum 2048-bit length for the non-export
|
||||
Exim SMTP clients require a ≥ 2048-bit length for the non-export
|
||||
prime. See the <a href="#quick-start">quick-start</a> section for
|
||||
the recommended configuration to work around this issue. </p>
|
||||
|
||||
@ -269,10 +271,12 @@ href="TLS_README.html#client_tls_policy">TLS policy</a> table. </p>
|
||||
|
||||
<h2><a name="quick-start">Getting started, quick and dirty</a></h2>
|
||||
|
||||
<ul>
|
||||
<h3> EECDH Client and server support (Postfix ≥ 2.6 with OpenSSL
|
||||
≥ 1.0.0) </h3>
|
||||
|
||||
<li> <p> Postfix 2.6 and 2.7: Enable elliptic-curve support. This
|
||||
is the default with Postfix ≥ 2.8.
|
||||
<p> With Postfix 2.6 and 2.7, enable elliptic-curve support in the
|
||||
Postfix SMTP client and server. This is the default with Postfix
|
||||
≥ 2.8.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
@ -282,12 +286,16 @@ is the default with Postfix ≥ 2.8.
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<li> <p> Optionally generate non-default EDH parameters for improved
|
||||
security against pre-computation attacks and for compatibility with
|
||||
Debian-patched EXIM SMTP clients (these require a minimum 2048-bit
|
||||
length for the non-export prime). The parameter files are not
|
||||
secret, after all these parameters are sent to all SMTP clients in
|
||||
the clear. Mode 0644 is fine. </p>
|
||||
<h3> EDH Client support (Postfix ≥ 2.2) </h3>
|
||||
|
||||
<p> This space intentionally left blank. </p>
|
||||
|
||||
<h3> EDH Server support (Postfix ≥ 2.2) </h3>
|
||||
|
||||
<p> Optionally generate non-default Postfix SMTP server EDH parameters
|
||||
for improved security against pre-computation attacks and for
|
||||
compatibility with Debian-patched Exim SMTP clients that require a
|
||||
≥ 2048-bit length for the non-export prime. </p>
|
||||
|
||||
<p> Execute as root (prime group generation can take a
|
||||
few seconds to a few minutes): </p>
|
||||
@ -295,6 +303,7 @@ few seconds to a few minutes): </p>
|
||||
<blockquote>
|
||||
<pre>
|
||||
# cd /etc/postfix
|
||||
# umask 022
|
||||
# openssl dhparam -out dh512.tmp 512 && mv dh512.tmp dh512.pem
|
||||
# openssl dhparam -out dh1024.tmp 1024 && mv dh1024.tmp dh1024.pem
|
||||
# openssl dhparam -out dh2048.tmp 2048 && mv dh2048.tmp dh2048.pem
|
||||
@ -302,9 +311,14 @@ few seconds to a few minutes): </p>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> The Postfix SMTP server EDH parameter files are not secret,
|
||||
after all these parameters are sent to all remote SMTP clients in
|
||||
the clear. Mode 0644 is fine. </p>
|
||||
|
||||
<p> You can improve security against pre-computation attacks further
|
||||
by regenerating the EDH parameters periodically (an hourly or daily
|
||||
cron job running as root can automate this task). </p>
|
||||
by regenerating the Postfix SMTP server EDH parameters periodically
|
||||
(an hourly or daily cron job running the above commands as root can
|
||||
automate this task). </p>
|
||||
|
||||
<p> Once the parameters are in place, update main.cf as follows: </p>
|
||||
|
||||
@ -332,8 +346,6 @@ need to adjust the submission entry in master.cf accordingly: </p>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2><a name="test">How can I see that a connection has forward
|
||||
secrecy? </a> </h2>
|
||||
|
||||
@ -392,7 +404,7 @@ OpenSSL 1.0.1e. The list is sorted in the default Postfix preference
|
||||
order. It excludes null ciphers that only authenticate and don't
|
||||
encrypt, together with export and low-grade ciphers whose encryption
|
||||
is too weak to offer meaningful secrecy. The first column shows the
|
||||
cipher name, and the second shows the key exchange method. </p>
|
||||
cipher name, and the second shows the key exchange method. </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
|
@ -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 "20131228"
|
||||
#define MAIL_RELEASE_DATE "20140104"
|
||||
#define MAIL_VERSION_NUMBER "2.11"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -301,9 +301,7 @@ extern HBC_CHECKS *smtp_body_checks; /* limited body checks */
|
||||
|
||||
typedef struct SMTP_SESSION {
|
||||
VSTREAM *stream; /* network connection */
|
||||
char *dest; /* nexthop or fallback */
|
||||
char *host; /* mail exchanger */
|
||||
char *addr; /* mail exchanger */
|
||||
SMTP_ITERATOR *iterator; /* dest, host, addr, port */
|
||||
char *namaddr; /* mail exchanger */
|
||||
char *helo; /* helo response */
|
||||
unsigned port; /* network byte order */
|
||||
|
@ -363,7 +363,8 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session)
|
||||
session->namaddrport, STR(session->buffer));
|
||||
if (var_helpful_warnings)
|
||||
msg_warn("to prevent loss of mail, turn off command pipelining "
|
||||
"for %s with the %s parameter", session->addr,
|
||||
"for %s with the %s parameter",
|
||||
STR(session->iterator->addr),
|
||||
SMTP_X(EHLO_DIS_MAPS));
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ static SMTP_SESSION *smtp_connect_unix(SMTP_ITERATOR *iter, DSN_BUF *why,
|
||||
if (msg_verbose)
|
||||
msg_info("%s: trying: %s...", myname, addr);
|
||||
|
||||
return (smtp_connect_sock(sock, (struct sockaddr *) & sock_un,
|
||||
return (smtp_connect_sock(sock, (struct sockaddr *) &sock_un,
|
||||
sizeof(sock_un), iter, why, sess_flags));
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_ITERATOR *iter, DSN_BUF *why,
|
||||
{
|
||||
const char *myname = "smtp_connect_addr";
|
||||
struct sockaddr_storage ss; /* remote */
|
||||
struct sockaddr *sa = (struct sockaddr *) & ss;
|
||||
struct sockaddr *sa = (struct sockaddr *) &ss;
|
||||
SOCKADDR_SIZE salen = sizeof(ss);
|
||||
MAI_HOSTADDR_STR hostaddr;
|
||||
DNS_RR *addr = iter->rr;
|
||||
@ -274,7 +274,7 @@ static SMTP_SESSION *smtp_connect_addr(SMTP_ITERATOR *iter, DSN_BUF *why,
|
||||
|
||||
/* smtp_connect_sock - connect a socket over some transport */
|
||||
|
||||
static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa,
|
||||
static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr *sa,
|
||||
int salen,
|
||||
SMTP_ITERATOR *iter,
|
||||
DSN_BUF *why,
|
||||
@ -668,7 +668,7 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list,
|
||||
if (*addr_list && SMTP_RCPT_LEFT(state) > 0
|
||||
&& (session = smtp_reuse_nexthop(state, SMTP_KEY_MASK_SCACHE_DEST_LABEL)) != 0) {
|
||||
session_count = 1;
|
||||
smtp_update_addr_list(addr_list, session->addr, session_count);
|
||||
smtp_update_addr_list(addr_list, STR(iter->addr), session_count);
|
||||
if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
|
||||
&& *addr_list == 0)
|
||||
state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
|
||||
@ -726,7 +726,7 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list,
|
||||
SMTP_KEY_MASK_SCACHE_ENDP_LABEL)) != 0) {
|
||||
session->features |= SMTP_FEATURE_BEST_MX;
|
||||
session_count += 1;
|
||||
smtp_update_addr_list(addr_list, session->addr, session_count);
|
||||
smtp_update_addr_list(addr_list, STR(iter->addr), session_count);
|
||||
if (*addr_list == 0)
|
||||
next = 0;
|
||||
if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
|
||||
|
@ -261,6 +261,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
const char *myname = "smtp_helo";
|
||||
SMTP_SESSION *session = state->session;
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
SMTP_ITERATOR *iter = state->iterator;
|
||||
SMTP_RESP *resp;
|
||||
SMTP_RESP fake;
|
||||
int except;
|
||||
@ -322,7 +323,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
STR(resp->dsn_buf)[0] = '4';
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
return (smtp_site_fail(state, session->host, resp,
|
||||
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||
"host %s refused to talk to me: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
@ -350,7 +351,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
if (smtp_pix_bug_maps != 0
|
||||
&& (pix_bug_words =
|
||||
maps_find(smtp_pix_bug_maps,
|
||||
state->session->addr, 0)) != 0) {
|
||||
STR(iter->addr), 0)) != 0) {
|
||||
pix_bug_source = SMTP_X(PIX_BUG_MAPS);
|
||||
} else {
|
||||
pix_bug_words = var_smtp_pix_bug_words;
|
||||
@ -415,7 +416,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
smtp_chat_cmd(session, "EHLO %s", var_smtp_helo_name);
|
||||
if ((resp = smtp_chat_resp(session))->code / 100 != 2) {
|
||||
if (resp->code == 421)
|
||||
return (smtp_site_fail(state, session->host, resp,
|
||||
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||
"host %s refused to talk to me: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
@ -427,7 +428,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
where = "performing the HELO handshake";
|
||||
smtp_chat_cmd(session, "HELO %s", var_smtp_helo_name);
|
||||
if ((resp = smtp_chat_resp(session))->code / 100 != 2)
|
||||
return (smtp_site_fail(state, session->host, resp,
|
||||
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||
"host %s refused to talk to me: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
@ -436,7 +437,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
where = "performing the LHLO handshake";
|
||||
smtp_chat_cmd(session, "LHLO %s", var_smtp_helo_name);
|
||||
if ((resp = smtp_chat_resp(session))->code / 100 != 2)
|
||||
return (smtp_site_fail(state, session->host, resp,
|
||||
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||
"host %s refused to talk to me: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
@ -454,12 +455,12 @@ int smtp_helo(SMTP_STATE *state)
|
||||
*/
|
||||
if (smtp_ehlo_dis_maps == 0
|
||||
|| (ehlo_words = maps_find(smtp_ehlo_dis_maps,
|
||||
state->session->addr, 0)) == 0)
|
||||
STR(iter->addr), 0)) == 0)
|
||||
ehlo_words = var_smtp_ehlo_dis_words;
|
||||
if (smtp_ehlo_dis_maps && smtp_ehlo_dis_maps->error) {
|
||||
msg_warn("%s: %s map lookup error for %s",
|
||||
session->state->request->queue_id,
|
||||
smtp_ehlo_dis_maps->title, state->session->addr);
|
||||
smtp_ehlo_dis_maps->title, STR(iter->addr));
|
||||
vstream_longjmp(session->stream, SMTP_ERR_DATA);
|
||||
}
|
||||
discard_mask = ehlo_mask(ehlo_words);
|
||||
@ -643,7 +644,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
if ((session->features & SMTP_FEATURE_STARTTLS) &&
|
||||
var_smtp_tls_note_starttls_offer &&
|
||||
session->tls->level <= TLS_LEV_NONE)
|
||||
msg_info("Host offered STARTTLS: [%s]", session->host);
|
||||
msg_info("Host offered STARTTLS: [%s]", STR(iter->host));
|
||||
|
||||
/*
|
||||
* Decide whether or not to send STARTTLS.
|
||||
@ -690,7 +691,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
*/
|
||||
session->features &= ~SMTP_FEATURE_STARTTLS;
|
||||
if (TLS_REQUIRED(session->tls->level))
|
||||
return (smtp_site_fail(state, session->host, resp,
|
||||
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||
"TLS is required, but host %s refused to start TLS: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
@ -739,6 +740,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
static int smtp_start_tls(SMTP_STATE *state)
|
||||
{
|
||||
SMTP_SESSION *session = state->session;
|
||||
SMTP_ITERATOR *iter = state->iterator;
|
||||
TLS_CLIENT_START_PROPS tls_props;
|
||||
VSTRING *serverid;
|
||||
SMTP_RESP fake;
|
||||
@ -805,7 +807,7 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
timeout = var_smtp_starttls_tmout,
|
||||
tls_level = session->tls->level,
|
||||
nexthop = session->tls_nexthop,
|
||||
host = session->host,
|
||||
host = STR(iter->host),
|
||||
namaddr = session->namaddrport,
|
||||
serverid = vstring_str(serverid),
|
||||
helo = session->helo,
|
||||
@ -1142,6 +1144,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
const char *myname = "smtp_loop";
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
SMTP_SESSION *session = state->session;
|
||||
SMTP_ITERATOR *iter = state->iterator;
|
||||
SMTP_RESP *resp;
|
||||
RECIPIENT *rcpt;
|
||||
VSTRING *next_command = vstring_alloc(100);
|
||||
@ -1652,7 +1655,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
*/
|
||||
case SMTP_STATE_MAIL:
|
||||
if (resp->code / 100 != 2) {
|
||||
smtp_mesg_fail(state, session->host, resp,
|
||||
smtp_mesg_fail(state, STR(iter->host), resp,
|
||||
"host %s said: %s (in reply to %s)",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " "),
|
||||
@ -1724,7 +1727,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
smtp_rcpt_done(state, resp, rcpt);
|
||||
}
|
||||
} else {
|
||||
smtp_rcpt_fail(state, rcpt, session->host, resp,
|
||||
smtp_rcpt_fail(state, rcpt, STR(iter->host), resp,
|
||||
"host %s said: %s (in reply to %s)",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " "),
|
||||
@ -1746,7 +1749,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
case SMTP_STATE_DATA:
|
||||
if (resp->code / 100 != 3) {
|
||||
if (nrcpt > 0)
|
||||
smtp_mesg_fail(state, session->host, resp,
|
||||
smtp_mesg_fail(state, STR(iter->host), resp,
|
||||
"host %s said: %s (in reply to %s)",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " "),
|
||||
@ -1770,7 +1773,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
if (smtp_mode) {
|
||||
if (nrcpt > 0) {
|
||||
if (resp->code / 100 != 2) {
|
||||
smtp_mesg_fail(state, session->host, resp,
|
||||
smtp_mesg_fail(state, STR(iter->host), resp,
|
||||
"host %s said: %s (in reply to %s)",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " "),
|
||||
@ -1797,7 +1800,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
rcpt = request->rcpt_list.info
|
||||
+ survivors[recv_done++];
|
||||
if (resp->code / 100 != 2) {
|
||||
smtp_rcpt_fail(state, rcpt, session->host, resp,
|
||||
smtp_rcpt_fail(state, rcpt, STR(iter->host), resp,
|
||||
"host %s said: %s (in reply to %s)",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " "),
|
||||
|
@ -132,6 +132,7 @@ void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt)
|
||||
{
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
SMTP_SESSION *session = state->session;
|
||||
SMTP_ITERATOR *iter = state->iterator;
|
||||
DSN_BUF *why = state->why;
|
||||
const char *dsn_action = "relayed";
|
||||
int status;
|
||||
@ -162,7 +163,7 @@ void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt)
|
||||
*
|
||||
* Note: the DSN action is ignored in case of address probes.
|
||||
*/
|
||||
dsb_update(why, resp->dsn, dsn_action, DSB_MTYPE_DNS, session->host,
|
||||
dsb_update(why, resp->dsn, dsn_action, DSB_MTYPE_DNS, STR(iter->host),
|
||||
DSB_DTYPE_SMTP, resp->str, "%s", resp->str);
|
||||
|
||||
status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
|
||||
|
@ -155,6 +155,7 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
|
||||
const char *label)
|
||||
{
|
||||
const char *myname = "smtp_reuse_common";
|
||||
SMTP_ITERATOR *iter = state->iterator;
|
||||
SMTP_SESSION *session;
|
||||
|
||||
/*
|
||||
@ -200,7 +201,7 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
|
||||
/*
|
||||
* Update the list of used cached addresses.
|
||||
*/
|
||||
htable_enter(state->cache_used, session->addr, (char *) 0);
|
||||
htable_enter(state->cache_used, STR(iter->addr), (char *) 0);
|
||||
|
||||
return (session);
|
||||
}
|
||||
|
@ -230,11 +230,12 @@ static int smtp_sasl_auth_cache_valid_value(SMTP_SASL_AUTH_CACHE *auth_cache,
|
||||
int smtp_sasl_auth_cache_find(SMTP_SASL_AUTH_CACHE *auth_cache,
|
||||
const SMTP_SESSION *session)
|
||||
{
|
||||
SMTP_ITERATOR *iter = session->iterator;
|
||||
char *key;
|
||||
const char *entry;
|
||||
int valid = 0;
|
||||
|
||||
key = smtp_sasl_auth_cache_make_key(session->host, session->sasl_username);
|
||||
key = smtp_sasl_auth_cache_make_key(STR(iter->host), session->sasl_username);
|
||||
if ((entry = dict_get(auth_cache->dict, key)) != 0)
|
||||
if ((valid = smtp_sasl_auth_cache_valid_value(auth_cache, entry,
|
||||
session->sasl_passwd)) == 0)
|
||||
@ -255,10 +256,11 @@ void smtp_sasl_auth_cache_store(SMTP_SASL_AUTH_CACHE *auth_cache,
|
||||
const SMTP_SESSION *session,
|
||||
const SMTP_RESP *resp)
|
||||
{
|
||||
SMTP_ITERATOR *iter = session->iterator;
|
||||
char *key;
|
||||
char *value;
|
||||
|
||||
key = smtp_sasl_auth_cache_make_key(session->host, session->sasl_username);
|
||||
key = smtp_sasl_auth_cache_make_key(STR(iter->host), session->sasl_username);
|
||||
value = smtp_sasl_auth_cache_make_value(session->sasl_passwd,
|
||||
resp->dsn, resp->str);
|
||||
dict_put(auth_cache->dict, key, value);
|
||||
|
@ -158,6 +158,7 @@ int smtp_sasl_passwd_lookup(SMTP_SESSION *session)
|
||||
{
|
||||
const char *myname = "smtp_sasl_passwd_lookup";
|
||||
SMTP_STATE *state = session->state;
|
||||
SMTP_ITERATOR *iter = session->iterator;
|
||||
const char *value;
|
||||
char *passwd;
|
||||
|
||||
@ -187,10 +188,10 @@ int smtp_sasl_passwd_lookup(SMTP_SESSION *session)
|
||||
state->request->sender, (char **) 0)) != 0)
|
||||
|| (smtp_sasl_passwd_map->error == 0
|
||||
&& (value = maps_find(smtp_sasl_passwd_map,
|
||||
session->host, 0)) != 0)
|
||||
STR(iter->host), 0)) != 0)
|
||||
|| (smtp_sasl_passwd_map->error == 0
|
||||
&& (value = maps_find(smtp_sasl_passwd_map,
|
||||
session->dest, 0)) != 0)) {
|
||||
STR(iter->dest), 0)) != 0)) {
|
||||
if (session->sasl_username)
|
||||
myfree(session->sasl_username);
|
||||
session->sasl_username = mystrdup(value);
|
||||
@ -200,7 +201,7 @@ int smtp_sasl_passwd_lookup(SMTP_SESSION *session)
|
||||
session->sasl_passwd = mystrdup(passwd ? passwd : "");
|
||||
if (msg_verbose)
|
||||
msg_info("%s: host `%s' user `%s' pass `%s'",
|
||||
myname, session->host,
|
||||
myname, STR(iter->host),
|
||||
session->sasl_username, session->sasl_passwd);
|
||||
return (1);
|
||||
} else if (smtp_sasl_passwd_map->error) {
|
||||
@ -210,7 +211,7 @@ int smtp_sasl_passwd_lookup(SMTP_SESSION *session)
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: no auth info found (sender=`%s', host=`%s')",
|
||||
myname, state->request->sender, session->host);
|
||||
myname, state->request->sender, STR(iter->host));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
@ -284,6 +285,7 @@ void smtp_sasl_start(SMTP_SESSION *session, const char *sasl_opts_name,
|
||||
const char *sasl_opts_val)
|
||||
{
|
||||
XSASL_CLIENT_CREATE_ARGS create_args;
|
||||
SMTP_ITERATOR *iter = session->iterator;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("starting new SASL client");
|
||||
@ -291,7 +293,7 @@ void smtp_sasl_start(SMTP_SESSION *session, const char *sasl_opts_name,
|
||||
XSASL_CLIENT_CREATE(smtp_sasl_impl, &create_args,
|
||||
stream = session->stream,
|
||||
service = var_procname,
|
||||
server_name = session->host,
|
||||
server_name = STR(iter->host),
|
||||
security_options = sasl_opts_val)) == 0)
|
||||
msg_fatal("SASL per-connection initialization failed");
|
||||
session->sasl_reply = vstring_alloc(20);
|
||||
@ -302,6 +304,7 @@ void smtp_sasl_start(SMTP_SESSION *session, const char *sasl_opts_name,
|
||||
int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why)
|
||||
{
|
||||
const char *myname = "smtp_sasl_authenticate";
|
||||
SMTP_ITERATOR *iter = session->iterator;
|
||||
SMTP_RESP *resp;
|
||||
const char *mechanism;
|
||||
int result;
|
||||
@ -330,9 +333,9 @@ int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why)
|
||||
if (var_smtp_sasl_auth_soft_bounce && resp_dsn[0] == '5')
|
||||
resp_dsn[0] = '4';
|
||||
dsb_update(why, resp_dsn, DSB_DEF_ACTION, DSB_MTYPE_DNS,
|
||||
session->host, var_procname, resp_str,
|
||||
STR(iter->host), var_procname, resp_str,
|
||||
"SASL [CACHED] authentication failed; server %s said: %s",
|
||||
session->host, resp_str);
|
||||
STR(iter->host), resp_str);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
@ -416,7 +419,7 @@ int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why)
|
||||
if (var_smtp_sasl_auth_soft_bounce && resp->code / 100 == 5)
|
||||
STR(resp->dsn_buf)[0] = '4';
|
||||
dsb_update(why, resp->dsn, DSB_DEF_ACTION,
|
||||
DSB_MTYPE_DNS, session->host,
|
||||
DSB_MTYPE_DNS, STR(iter->host),
|
||||
var_procname, resp->str,
|
||||
"SASL authentication failed; server %s said: %s",
|
||||
session->namaddr, resp->str);
|
||||
|
@ -123,16 +123,13 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, SMTP_ITERATOR *iter,
|
||||
time_t start, int flags)
|
||||
{
|
||||
SMTP_SESSION *session;
|
||||
const char *dest = STR(iter->dest);
|
||||
const char *host = STR(iter->host);
|
||||
const char *addr = STR(iter->addr);
|
||||
unsigned port = iter->port;
|
||||
|
||||
session = (SMTP_SESSION *) mymalloc(sizeof(*session));
|
||||
session->stream = stream;
|
||||
session->dest = mystrdup(dest);
|
||||
session->host = mystrdup(host);
|
||||
session->addr = mystrdup(addr);
|
||||
session->iterator = iter;
|
||||
session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
|
||||
session->helo = 0;
|
||||
session->port = port;
|
||||
@ -191,9 +188,6 @@ void smtp_session_free(SMTP_SESSION *session)
|
||||
#endif
|
||||
if (session->stream)
|
||||
vstream_fclose(session->stream);
|
||||
myfree(session->dest);
|
||||
myfree(session->host);
|
||||
myfree(session->addr);
|
||||
myfree(session->namaddr);
|
||||
myfree(session->namaddrport);
|
||||
if (session->helo)
|
||||
@ -221,6 +215,7 @@ void smtp_session_free(SMTP_SESSION *session)
|
||||
int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
|
||||
VSTRING *endp_prop)
|
||||
{
|
||||
SMTP_ITERATOR *iter = session->iterator;
|
||||
int fd;
|
||||
|
||||
/*
|
||||
@ -238,7 +233,7 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
|
||||
*
|
||||
*/
|
||||
vstring_sprintf(dest_prop, "%s\n%s\n%s\n%u",
|
||||
session->dest, session->host, session->addr,
|
||||
STR(iter->dest), STR(iter->host), STR(iter->addr),
|
||||
session->features & SMTP_FEATURE_DESTINATION_MASK);
|
||||
|
||||
/*
|
||||
|
@ -19,7 +19,7 @@ INCL =
|
||||
LIB = libtls.a
|
||||
TESTPROG= tls_dh tls_mgr tls_rsa tls_dane
|
||||
|
||||
LIBS = ../../lib/libglobal.a ../../lib/libutil.a ../../lib/libdns.a
|
||||
LIBS = ../../lib/libdns.a ../../lib/libglobal.a ../../lib/libutil.a
|
||||
LIB_DIR = ../../lib
|
||||
INC_DIR = ../../include
|
||||
MAKES =
|
||||
|
@ -705,11 +705,11 @@ const char *dict_cache_name(DICT_CACHE *cp)
|
||||
"\n\treset (discard pending requests)" \
|
||||
"\n\trun (execute pending requests in interleaved order)" \
|
||||
"\n\n\tTo add a pending request:" \
|
||||
"\n\tquery <key-prefix> <count> (negative to reverse order)" \
|
||||
"\n\tupdate <key-prefix> <count> (negative to reverse order)" \
|
||||
"\n\tdelete <key-prefix> <count> (negative to reverse order)" \
|
||||
"\n\tpurge <key-prefix>" \
|
||||
"\n\tcount <key-prefix>"
|
||||
"\n\tquery <key-suffix> <count> (negative to reverse order)" \
|
||||
"\n\tupdate <key-suffix> <count> (negative to reverse order)" \
|
||||
"\n\tdelete <key-suffix> <count> (negative to reverse order)" \
|
||||
"\n\tpurge <key-suffix>" \
|
||||
"\n\tcount <key-suffix>"
|
||||
|
||||
/*
|
||||
* For realism, open the cache with the same flags as postscreen(8) and
|
||||
@ -725,7 +725,7 @@ typedef struct DICT_CACHE_SREQ {
|
||||
int flags; /* per-request: reverse, purge */
|
||||
char *cmd; /* command for status report */
|
||||
void (*action) (struct DICT_CACHE_SREQ *, DICT_CACHE *, VSTRING *);
|
||||
char *prefix; /* key prefix */
|
||||
char *suffix; /* key suffix */
|
||||
int done; /* progress indicator */
|
||||
int todo; /* number of entries to process */
|
||||
int first_next; /* first/next */
|
||||
@ -772,9 +772,9 @@ static void make_tagged_key(VSTRING *bp, DICT_CACHE_SREQ *cp)
|
||||
msg_panic("make_tagged_key: bad done count: %d", cp->done);
|
||||
if (cp->todo < 1)
|
||||
msg_panic("make_tagged_key: bad todo count: %d", cp->todo);
|
||||
vstring_sprintf(bp, "%s-%d", cp->prefix,
|
||||
vstring_sprintf(bp, "%d-%s",
|
||||
(cp->flags & DICT_CACHE_SREQ_FLAG_REVERSE) ?
|
||||
cp->todo - cp->done - 1 : cp->done);
|
||||
cp->todo - cp->done - 1 : cp->done, cp->suffix);
|
||||
}
|
||||
|
||||
/* create_requests - create request list */
|
||||
@ -793,7 +793,7 @@ static DICT_CACHE_TEST *create_requests(int count)
|
||||
cp->flags = 0;
|
||||
cp->cmd = 0;
|
||||
cp->action = 0;
|
||||
cp->prefix = 0;
|
||||
cp->suffix = 0;
|
||||
cp->todo = 0;
|
||||
cp->first_next = DICT_SEQ_FUN_FIRST;
|
||||
}
|
||||
@ -815,9 +815,9 @@ static void reset_requests(DICT_CACHE_TEST *tp)
|
||||
cp->cmd = 0;
|
||||
}
|
||||
cp->action = 0;
|
||||
if (cp->prefix) {
|
||||
myfree(cp->prefix);
|
||||
cp->prefix = 0;
|
||||
if (cp->suffix) {
|
||||
myfree(cp->suffix);
|
||||
cp->suffix = 0;
|
||||
}
|
||||
cp->todo = 0;
|
||||
cp->first_next = DICT_SEQ_FUN_FIRST;
|
||||
@ -876,8 +876,11 @@ static void show_status(DICT_CACHE_TEST *tp, DICT_CACHE *dp)
|
||||
#endif
|
||||
vstream_printf("cache\t%s\n", dp ? dp->name : "(none)");
|
||||
|
||||
vstream_printf("%s\t%s\t%s\t%s\t%s\t%s\n",
|
||||
"cmd", "dir", "prefix", "count", "done", "first/next");
|
||||
if (tp->used == 0)
|
||||
vstream_printf("No pending requests\n");
|
||||
else
|
||||
vstream_printf("%s\t%s\t%s\t%s\t%s\t%s\n",
|
||||
"cmd", "dir", "suffix", "count", "done", "first/next");
|
||||
|
||||
for (cp = tp->job_list; cp < tp->job_list + tp->used; cp++)
|
||||
if (cp->todo > 0)
|
||||
@ -885,7 +888,7 @@ static void show_status(DICT_CACHE_TEST *tp, DICT_CACHE *dp)
|
||||
cp->cmd,
|
||||
(cp->flags & DICT_CACHE_SREQ_FLAG_REVERSE) ?
|
||||
"reverse" : "forward",
|
||||
cp->prefix ? cp->prefix : "(null)", cp->todo,
|
||||
cp->suffix ? cp->suffix : "(null)", cp->todo,
|
||||
cp->done, cp->first_next);
|
||||
}
|
||||
|
||||
@ -936,21 +939,21 @@ static void delete_action(DICT_CACHE_SREQ *cp, DICT_CACHE *dp, VSTRING *bp)
|
||||
cp->done += 1;
|
||||
}
|
||||
|
||||
/* iter_action - iterate over cache and act on entries with given prefix */
|
||||
/* iter_action - iterate over cache and act on entries with given suffix */
|
||||
|
||||
static void iter_action(DICT_CACHE_SREQ *cp, DICT_CACHE *dp, VSTRING *bp)
|
||||
{
|
||||
const char *cache_key;
|
||||
const char *cache_val;
|
||||
const char *what;
|
||||
int len;
|
||||
const char *suffix;
|
||||
|
||||
if (dict_cache_sequence(dp, cp->first_next, &cache_key, &cache_val) == 0) {
|
||||
if (strcmp(cache_key, cache_val) != 0)
|
||||
msg_warn("value \"%s\" differs from key \"%s\"",
|
||||
cache_val, cache_key);
|
||||
len = strlen(cp->prefix);
|
||||
if (strncmp(cache_key, cp->prefix, len) == 0 && cache_key[len] == '-') {
|
||||
suffix = cache_key + strspn(cache_key, "0123456789");
|
||||
if (suffix[0] == '-' && strcmp(suffix + 1, cp->suffix) == 0) {
|
||||
cp->done += 1;
|
||||
cp->todo = cp->done + 1; /* XXX */
|
||||
if ((cp->flags & DICT_CACHE_SREQ_FLAG_PURGE)
|
||||
@ -967,7 +970,7 @@ static void iter_action(DICT_CACHE_SREQ *cp, DICT_CACHE *dp, VSTRING *bp)
|
||||
if (dp->error)
|
||||
msg_warn("%s error after %d: %m", what, cp->done);
|
||||
else
|
||||
vstream_printf("prefix=%s %s=%d\n", cp->prefix, what, cp->done);
|
||||
vstream_printf("suffix=%s %s=%d\n", cp->suffix, what, cp->done);
|
||||
cp->todo = 0;
|
||||
}
|
||||
}
|
||||
@ -1001,7 +1004,7 @@ static void add_request(DICT_CACHE_TEST *tp, ARGV *argv)
|
||||
int req_flags;
|
||||
int count;
|
||||
char *cmd = argv->argv[0];
|
||||
char *prefix = (argv->argc > 1 ? argv->argv[1] : 0);
|
||||
char *suffix = (argv->argc > 1 ? argv->argv[1] : 0);
|
||||
char *todo = (argv->argc > 2 ? argv->argv[2] : "1"); /* XXX */
|
||||
|
||||
if (tp->used >= tp->size) {
|
||||
@ -1034,8 +1037,8 @@ static void add_request(DICT_CACHE_TEST *tp, ARGV *argv)
|
||||
cp = tp->job_list + tp->used;
|
||||
cp->cmd = mystrdup(cmd);
|
||||
cp->action = rp->action;
|
||||
if (prefix)
|
||||
cp->prefix = mystrdup(prefix);
|
||||
if (suffix)
|
||||
cp->suffix = mystrdup(suffix);
|
||||
cp->done = 0;
|
||||
cp->flags = req_flags;
|
||||
cp->todo = count;
|
||||
|
@ -82,7 +82,8 @@
|
||||
/*
|
||||
/* slmdb_cursor_get() is an mdb_cursor_get() wrapper with
|
||||
/* automatic error recovery. The result value is an LMDB
|
||||
/* status code (zero in case of success).
|
||||
/* status code (zero in case of success). This wrapper supports
|
||||
/* only one cursor per database.
|
||||
/*
|
||||
/* slmdb_fd() returns the file descriptor for the specified
|
||||
/* database. This may be used for file status queries or
|
||||
@ -198,6 +199,8 @@
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@ -256,6 +259,80 @@
|
||||
return (status); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* We must close the cursor's read transaction before writing to the
|
||||
* database with MDB_NOLOCK, and before changing the memory map size. Our
|
||||
* database iterator saves the key under the last cursor position, and
|
||||
* restores the cursor if needed. This supports only one cursor per
|
||||
* database.
|
||||
*/
|
||||
|
||||
/* slmdb_cursor_close - close cursor and its read transaction */
|
||||
|
||||
static void slmdb_cursor_close(SLMDB *slmdb)
|
||||
{
|
||||
MDB_txn *txn;
|
||||
|
||||
/*
|
||||
* Close the cursor and its read transaction. We can restore it later
|
||||
* from the saved key information.
|
||||
*/
|
||||
txn = mdb_cursor_txn(slmdb->cursor);
|
||||
mdb_cursor_close(slmdb->cursor);
|
||||
slmdb->cursor = 0;
|
||||
mdb_txn_abort(txn);
|
||||
}
|
||||
|
||||
/* slmdb_saved_key_init - initialize saved key info */
|
||||
|
||||
static void slmdb_saved_key_init(SLMDB *slmdb)
|
||||
{
|
||||
slmdb->saved_key.mv_data = 0;
|
||||
slmdb->saved_key_size = 0;
|
||||
}
|
||||
|
||||
/* slmdb_saved_key_free - destroy saved key info */
|
||||
|
||||
static void slmdb_saved_key_free(SLMDB *slmdb)
|
||||
{
|
||||
free(slmdb->saved_key.mv_data);
|
||||
slmdb->saved_key.mv_data = 0;
|
||||
slmdb->saved_key_size = 0;
|
||||
}
|
||||
|
||||
#define HAVE_SLMDB_SAVED_KEY(s) ((s)->saved_key.mv_data != 0)
|
||||
|
||||
/* slmdb_saved_key_assign - copy the saved key */
|
||||
|
||||
static int slmdb_saved_key_assign(SLMDB *slmdb, MDB_val *key_val)
|
||||
{
|
||||
|
||||
/*
|
||||
* Extend the buffer to fit the key, so that we can avoid malloc()
|
||||
* overhead most of the time.
|
||||
*/
|
||||
if (slmdb->saved_key_size < key_val->mv_size) {
|
||||
if (slmdb->saved_key.mv_data == 0)
|
||||
slmdb->saved_key.mv_data = malloc(key_val->mv_size);
|
||||
else
|
||||
slmdb->saved_key.mv_data =
|
||||
realloc(slmdb->saved_key.mv_data, key_val->mv_size);
|
||||
if (slmdb->saved_key.mv_data == 0) {
|
||||
slmdb->saved_key_size = 0;
|
||||
return (ENOMEM);
|
||||
} else {
|
||||
slmdb->saved_key_size = key_val->mv_size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the key under the cursor.
|
||||
*/
|
||||
memcpy(slmdb->saved_key.mv_data, key_val->mv_data, key_val->mv_size);
|
||||
slmdb->saved_key.mv_size = key_val->mv_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* slmdb_prepare - LMDB-specific (re)initialization before actual access */
|
||||
|
||||
static int slmdb_prepare(SLMDB *slmdb)
|
||||
@ -295,6 +372,13 @@ static int slmdb_recover(SLMDB *slmdb, int status)
|
||||
{
|
||||
MDB_envinfo info;
|
||||
|
||||
/*
|
||||
* Close the cursor and its read transaction before changing the memory
|
||||
* map size. We can restore it later with the saved key information.
|
||||
*/
|
||||
if (slmdb->cursor != 0)
|
||||
slmdb_cursor_close(slmdb);
|
||||
|
||||
/*
|
||||
* Recover bulk transactions only if they can be restarted. Limit the
|
||||
* number of recovery attempts per slmdb(3) API request.
|
||||
@ -456,6 +540,15 @@ int slmdb_put(SLMDB *slmdb, MDB_val *mdb_key,
|
||||
else if ((status = slmdb_txn_begin(slmdb, 0, &txn)) != 0)
|
||||
SLMDB_API_RETURN(slmdb, status);
|
||||
|
||||
/*
|
||||
* Before doing a non-bulk write transaction in MDB_NOLOCK mode, close a
|
||||
* cursor and its read transaction. We can restore it later with the
|
||||
* saved key information.
|
||||
*/
|
||||
if (slmdb->cursor != 0 && slmdb->txn == 0
|
||||
&& (slmdb->lmdb_flags & MDB_NOLOCK))
|
||||
slmdb_cursor_close(slmdb);
|
||||
|
||||
/*
|
||||
* Do the update.
|
||||
*/
|
||||
@ -493,6 +586,15 @@ int slmdb_del(SLMDB *slmdb, MDB_val *mdb_key)
|
||||
else if ((status = slmdb_txn_begin(slmdb, 0, &txn)) != 0)
|
||||
SLMDB_API_RETURN(slmdb, status);
|
||||
|
||||
/*
|
||||
* Before doing a non-bulk write transaction in MDB_NOLOCK mode, close a
|
||||
* cursor and its read transaction. We can restore it later with the
|
||||
* saved key information.
|
||||
*/
|
||||
if (slmdb->cursor != 0 && slmdb->txn == 0
|
||||
&& (slmdb->lmdb_flags & MDB_NOLOCK))
|
||||
slmdb_cursor_close(slmdb);
|
||||
|
||||
/*
|
||||
* Do the update.
|
||||
*/
|
||||
@ -527,13 +629,27 @@ int slmdb_cursor_get(SLMDB *slmdb, MDB_val *mdb_key,
|
||||
* Open a read transaction and cursor if needed.
|
||||
*/
|
||||
if (slmdb->cursor == 0) {
|
||||
slmdb_txn_begin(slmdb, MDB_RDONLY, &txn);
|
||||
if ((status = slmdb_txn_begin(slmdb, MDB_RDONLY, &txn)) != 0)
|
||||
SLMDB_API_RETURN(slmdb, status);
|
||||
if ((status = mdb_cursor_open(txn, slmdb->dbi, &slmdb->cursor)) != 0) {
|
||||
mdb_txn_abort(txn);
|
||||
if ((status = slmdb_recover(slmdb, status)) == 0)
|
||||
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
|
||||
SLMDB_API_RETURN(slmdb, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the cursor to the saved key position.
|
||||
*/
|
||||
if (HAVE_SLMDB_SAVED_KEY(slmdb) && op != MDB_FIRST) {
|
||||
if ((status = mdb_cursor_get(slmdb->cursor, &slmdb->saved_key,
|
||||
(MDB_val *) 0, MDB_SET)) != 0) {
|
||||
slmdb_cursor_close(slmdb);
|
||||
if ((status = slmdb_recover(slmdb, status)) == 0)
|
||||
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
|
||||
SLMDB_API_RETURN(slmdb, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -541,15 +657,20 @@ int slmdb_cursor_get(SLMDB *slmdb, MDB_val *mdb_key,
|
||||
*/
|
||||
status = mdb_cursor_get(slmdb->cursor, mdb_key, mdb_value, op);
|
||||
|
||||
/*
|
||||
* Save the cursor position. This can fail only with ENOMEM.
|
||||
*/
|
||||
if (status == 0)
|
||||
status = slmdb_saved_key_assign(slmdb, mdb_key);
|
||||
|
||||
/*
|
||||
* Handle end-of-database or other error.
|
||||
*/
|
||||
if (status != 0) {
|
||||
else {
|
||||
if (status == MDB_NOTFOUND) {
|
||||
txn = mdb_cursor_txn(slmdb->cursor);
|
||||
mdb_cursor_close(slmdb->cursor);
|
||||
mdb_txn_abort(txn);
|
||||
slmdb->cursor = 0;
|
||||
slmdb_cursor_close(slmdb);
|
||||
if (HAVE_SLMDB_SAVED_KEY(slmdb))
|
||||
slmdb_saved_key_free(slmdb);
|
||||
} else {
|
||||
if ((status = slmdb_recover(slmdb, status)) == 0)
|
||||
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
|
||||
@ -613,14 +734,17 @@ int slmdb_close(SLMDB *slmdb)
|
||||
/*
|
||||
* Clean up after an unfinished sequence() operation.
|
||||
*/
|
||||
if (slmdb->cursor) {
|
||||
MDB_txn *txn = mdb_cursor_txn(slmdb->cursor);
|
||||
if (slmdb->cursor != 0)
|
||||
slmdb_cursor_close(slmdb);
|
||||
|
||||
mdb_cursor_close(slmdb->cursor);
|
||||
mdb_txn_abort(txn);
|
||||
}
|
||||
mdb_env_close(slmdb->env);
|
||||
|
||||
/*
|
||||
* Clean up the saved key position.
|
||||
*/
|
||||
if (HAVE_SLMDB_SAVED_KEY(slmdb))
|
||||
slmdb_saved_key_free(slmdb);
|
||||
|
||||
SLMDB_API_RETURN(slmdb, status);
|
||||
}
|
||||
|
||||
@ -703,6 +827,7 @@ int slmdb_open(SLMDB *slmdb, const char *path, int open_flags,
|
||||
slmdb->dbi = dbi;
|
||||
slmdb->db_fd = db_fd;
|
||||
slmdb->cursor = 0;
|
||||
slmdb_saved_key_init(slmdb);
|
||||
slmdb->api_retry_count = 0;
|
||||
slmdb->bulk_retry_count = 0;
|
||||
slmdb->api_retry_limit = SLMDB_DEF_API_RETRY_LIMIT;
|
||||
@ -718,4 +843,20 @@ int slmdb_open(SLMDB *slmdb, const char *path, int open_flags,
|
||||
return (status);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Implementation-dependent workaround to debug LMDB assert() failures. The
|
||||
* code below prevents daemons from disappearing without logfile record.
|
||||
*/
|
||||
#ifdef LMDB_ASSERT_WORKAROUND
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void __assert(const char *func, const char *file, int line, const char *text)
|
||||
{
|
||||
msg_panic("Assertion failed: %s, function %s, file %s, line %d.",
|
||||
text, func, file, line);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -31,6 +31,9 @@
|
||||
#define SLMDB_JMP_BUF sigjmp_buf
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All data structure members are private.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t curr_limit; /* database soft size limit */
|
||||
int size_incr; /* database expansion factor */
|
||||
@ -43,6 +46,8 @@ typedef struct {
|
||||
MDB_txn *txn; /* bulk transaction */
|
||||
int db_fd; /* database file handle */
|
||||
MDB_cursor *cursor; /* iterator */
|
||||
MDB_val saved_key; /* saved cursor key buffer */
|
||||
size_t saved_key_size; /* saved cursor key buffer size */
|
||||
void (*longjmp_fn) (void *, int);/* exception handling */
|
||||
void (*notify_fn) (void *, int,...); /* workaround notification */
|
||||
void *cb_context; /* call-back context */
|
||||
|
Loading…
x
Reference in New Issue
Block a user