]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.11-20130927
authorWietse Venema <wietse@porcupine.org>
Fri, 27 Sep 2013 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 28 Sep 2013 02:18:29 +0000 (22:18 -0400)
41 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/INSTALL
postfix/README_FILES/LMDB_README
postfix/README_FILES/SASL_README
postfix/README_FILES/STRESS_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/html/INSTALL.html
postfix/html/LMDB_README.html
postfix/html/SASL_README.html
postfix/html/STRESS_README.html
postfix/html/ldap_table.5.html
postfix/html/postconf.5.html
postfix/html/postscreen.8.html
postfix/man/man5/ldap_table.5
postfix/man/man5/postconf.5
postfix/man/man8/postscreen.8
postfix/mantools/postlink
postfix/proto/INSTALL.html
postfix/proto/LMDB_README.html
postfix/proto/SASL_README.html
postfix/proto/STRESS_README.html
postfix/proto/ldap_table
postfix/proto/postconf.proto
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/postalias/postalias.c
postfix/src/postmap/postmap.c
postfix/src/postscreen/Makefile.in
postfix/src/postscreen/postscreen.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd_check.c
postfix/src/tlsmgr/Makefile.in
postfix/src/util/Makefile.in
postfix/src/util/dict.h
postfix/src/util/dict_alloc.c
postfix/src/util/dict_lmdb.c
postfix/src/util/dict_open.c
postfix/src/util/dict_test.c
postfix/src/util/sys_defs.h

index 8e82ff87a8b72e8492d9925ec3ff1d1a97986ee3..61201ac29a0c869e180b11426464bf724fcbb11b 100644 (file)
@@ -1,3 +1,4 @@
+-TMDB_val
 -TABOUNCE
 -TADDR_MATCH_LIST
 -TADDR_PATTERN
 -TDSN_BUF
 -TDSN_SPLIT
 -TDSN_STAT
--TEC_KEY
 -TEC_GROUP
+-TEC_KEY
 -TEDIT_FILE
 -TEVENT_MASK
 -TEVP_PKEY
 -TMATCH_OPS
 -TMBLOCK
 -TMBOX
+-TMDB_txn
 -TMILTER
 -TMILTER8
 -TMILTERS
 -TWATCHDOG
 -TWATCH_FD
 -TX509
+-TX509V3_CTX
 -TX509_EXTENSION
 -TX509_NAME
 -TX509_STORE_CTX
--TX509V3_CTX
 -TXSASL_CLIENT
 -TXSASL_CLIENT_CREATE_ARGS
 -TXSASL_CLIENT_IMPL
 -Tsasl_secret_t
 -Tsfsistat
 -Tsize_t
+-Tssize_t
 -Tssl_cipher_stack_t
 -Tssl_comp_stack_t
--Tssize_t
 -Ttime_t
 -Tx509_extension_stack_t
 -Tx509_stack_t
index 187107bd414b74630d5632cf75de98c8889c3de4..1e58fa1c9b2c64dabdf8309645f5f846bc865550 100644 (file)
@@ -18719,10 +18719,11 @@ Apologies for any names omitted.
 
 20130615
 
-       Interoperability: turn on SHA-2XX digests by force. This
-       improves interoperability with clients and servers with
-       ancient OpenSSL versions and that that prematurely deploy
-       SHA-2 certificates. Viktor Dukhovni. File: tls/tls_misc.c
+       TLS Interoperability: turn on SHA-2 digests by force.  This
+       improves interoperability with clients and servers that
+       deploy SHA-2 digests without the required support for
+       TLSv1.2-style digest negotiation.  Based on patch by Viktor
+       Dukhovni.  Files: tls/tls_client.c, tls/tls_server.c.
 
 20130616
 
@@ -18912,3 +18913,33 @@ Apologies for any names omitted.
        src/smtp/smtp_addr.h, src/smtp/smtp_connect.c,
        src/smtp/smtp_params.c, src/smtp/smtp_tls_policy.c,
        src/tls/tls.h, src/tls/tls_dane.c.
+
+20130826
+
+       Documentation: re-ordered STRESS_README, now that all
+       supported releases have stress-adaptive behavior built in.
+       File: proto/STRESS_README.html.
+
+20130903
+
+       Cleanup: made the default_database_type compile-time
+       configurable. Files: util/sys_defs.h, makedefs, proto/INSTALL.
+
+20130916
+
+       Feature: reject_known_sender_login_mismatch, which applies
+       reject_sender_login_mismatch only to MAIL FROM addresses
+       that are known in $smtpd_sender_login_maps. Viktor & Wietse.
+       Files: mantools/postlink, proto/SASL_README.html,
+       proto/postconf.proto, global/mail_params.h, smtpd/smtpd_check.c.
+
+20130927
+
+       Cleanup: no more LMDB "database full" errors.  Postfix now
+       requires LMDB >= 0.9.8 which supports on-the-fly database
+       resizing. When a database becomes full, its size limit is
+       automatically doubled, and other processes automatically
+       pick up the new database size limit.  Files: util/dict.h,
+       util/dict_open.c, util/dict_alloc.c, util/dict_lmdb.c,
+       postmap/postmap.c, postalias/postalias.c, proto/LMDB_README.html,
+       proto/postconf.proto.
index 9ed6a054150362038978f224e775471ad4dd4656..b04f27d7cadf482370ce6b0d396ae927a9170b35 100644 (file)
@@ -194,31 +194,33 @@ IMPORTANT: Be sure to get the quotes right. These details matter a lot.
 
 Parameters whose defaults can be specified in this way are:
 
-     _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
-    |M\bMa\bac\bcr\bro\bo n\bna\bam\bme\be       |d\bde\bef\bfa\bau\bul\blt\bt v\bva\bal\blu\bue\be f\bfo\bor\br|t\bty\byp\bpi\bic\bca\bal\bl d\bde\bef\bfa\bau\bul\blt\bt     |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_COMMAND_DIR  |command_directory|/usr/sbin           |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_CONFIG_DIR   |config_directory |/etc/postfix        |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_DAEMON_DIR   |daemon_directory |/usr/libexec/postfix|
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_DATA_DIR     |data_directory   |/var/lib/postfix    |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_MAILQ_PATH   |mailq_path       |/usr/bin/mailq      |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_HTML_DIR     |html_directory   |no                  |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_MANPAGE_DIR  |manpage_directory|/usr/local/man      |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_NEWALIAS_PATH|newaliases_path  |/usr/bin/newaliases |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_QUEUE_DIR    |queue_directory  |/var/spool/postfix  |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_README_DIR   |readme_directory |no                  |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |DEF_SENDMAIL_PATH|sendmail_path    |/usr/sbin/sendmail  |
-    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+     _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
+    |M\bMa\bac\bcr\bro\bo n\bna\bam\bme\be       |d\bde\bef\bfa\bau\bul\blt\bt v\bva\bal\blu\bue\be f\bfo\bor\br    |t\bty\byp\bpi\bic\bca\bal\bl d\bde\bef\bfa\bau\bul\blt\bt     |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_COMMAND_DIR  |command_directory    |/usr/sbin           |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_CONFIG_DIR   |config_directory     |/etc/postfix        |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_DB_TYPE      |default_database_type|hash                |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_DAEMON_DIR   |daemon_directory     |/usr/libexec/postfix|
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_DATA_DIR     |data_directory       |/var/lib/postfix    |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_MAILQ_PATH   |mailq_path           |/usr/bin/mailq      |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_HTML_DIR     |html_directory       |no                  |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_MANPAGE_DIR  |manpage_directory    |/usr/local/man      |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_NEWALIAS_PATH|newaliases_path      |/usr/bin/newaliases |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_QUEUE_DIR    |queue_directory      |/var/spool/postfix  |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_README_DIR   |readme_directory     |no                  |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |DEF_SENDMAIL_PATH|sendmail_path        |/usr/sbin/sendmail  |
+    |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 
 Note: the data_directory parameter (for caches and pseudo-random numbers) was
 introduced with Postfix version 2.5.
@@ -247,9 +249,11 @@ The following is an extensive list of names and values.
 |                              |at compile time:                              |
 |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 ||                             |Do not build with Berkeley DB support. By     |
-||-DNO_DB                      |default, Berkeley DB support is compiled in on|
-||                             |platforms that are known to support this      |
-||                             |feature.                                      |
+||                             |default, Berkeley DB support is compiled in on|
+||-DNO_DB                      |platforms that are known to support this      |
+||                             |feature. If you override this, then you       |
+||                             |probably should also override DEF_DB_TYPE as  |
+||                             |described in section 4.4.                     |
 |_\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 ||                             |Do not build with Solaris /dev/poll support.  |
 ||-DNO_DEVPOLL                 |By default, /dev/poll support is compiled in  |
index fa7e80eb1c515d0d8d34007bb9ac38971a542705..5d3baeb1714f689cb6c7581c42f68273c2ce92ff 100644 (file)
@@ -4,14 +4,6 @@ P\bPo\bos\bst\btf\bfi\bix\bx O\bOp\bpe\ben\bnL\bLD\bDA\bAP\bP L\bLM\bMD\bDB\bB H\bHo\bow\bwt\bto\bo
 
 I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
 
-    W\bWa\bar\brn\bni\bin\bng\bg:\b: L\bLM\bMD\bDB\bB d\bda\bat\bta\bab\bba\bas\bse\bes\bs h\bha\bav\bve\be a\ba s\bsh\bho\bow\bw-\b-s\bst\bto\bop\bpp\bpe\ber\br b\bbu\bug\bg:\b: t\bth\bhe\bey\by d\bdo\bo n\bno\bot\bt g\bgr\bro\bow\bw b\bbe\bey\byo\bon\bnd\bd a\ba
-    s\bsp\bpe\bec\bci\bif\bfi\bie\bed\bd l\bli\bim\bmi\bit\bt,\b, a\ban\bnd\bd i\bin\bnt\btr\bro\bod\bdu\buc\bce\be a\ba "\b"d\bda\bat\bta\bab\bba\bas\bse\be f\bfu\bul\bll\bl"\b" h\bha\bar\brd\bd e\ber\brr\bro\bor\br c\bco\bon\bnd\bdi\bit\bti\bio\bon\bn t\bth\bha\bat\bt
-    d\bdo\boe\bes\bs n\bno\bot\bt e\bex\bxi\bis\bst\bt w\bwi\bit\bth\bh a\ban\bny\by o\bot\bth\bhe\ber\br P\bPo\bos\bst\btf\bfi\bix\bx d\bda\bat\bta\bab\bba\bas\bse\be t\bty\byp\bpe\be.\b. T\bTh\bhi\bis\bs i\bis\bs a\ba p\bpr\bro\bob\bbl\ble\bem\bm f\bfo\bor\br
-    p\bpr\bro\bog\bgr\bra\bam\bms\bs w\bwh\bho\bos\bse\be d\bda\bat\bta\bab\bba\bas\bse\be g\bgr\bro\bow\bws\bs w\bwi\bit\bth\bh s\bsy\bys\bst\bte\bem\bm l\blo\boa\bad\bd.\b. E\bEx\bxa\bam\bmp\bpl\ble\bes\bs a\bar\bre\be p\bpo\bos\bst\bts\bsc\bcr\bre\bee\ben\bn(\b(8\b8)\b),\b,
-    g\bgr\bre\bey\byl\bli\bis\bst\bti\bin\bng\bg,\b, v\bve\ber\bri\bif\bfy\by(\b(8\b8)\b) a\ban\bnd\bd t\btl\bls\bsm\bmg\bgr\br(\b(8\b8)\b).\b.
-
-    Y\bYo\bou\bu h\bha\bav\bve\be b\bbe\bee\ben\bn w\bwa\bar\brn\bne\bed\bd.\b.
-
 Postfix uses databases of various kinds to store and look up information.
 Postfix databases are specified as "type:name". OpenLDAP LMDB implements the
 Postfix database type "lmdb". The name of a Postfix OpenLDAP LMDB database is
@@ -30,14 +22,14 @@ This document describes:
 
 B\bBu\bui\bil\bld\bdi\bin\bng\bg P\bPo\bos\bst\btf\bfi\bix\bx w\bwi\bit\bth\bh O\bOp\bpe\ben\bnL\bLD\bDA\bAP\bP L\bLM\bMD\bDB\bB s\bsu\bup\bpp\bpo\bor\brt\bt
 
-Postfix normally does not enable OpenLDAP LMDB support. To build Postfix after
-you installed OpenLDAP LMDB from source code, use something like:
+Postfix normally does not enable OpenLDAP LMDB support. To build Postfix with
+OpenLDAP LMDB support, use something like:
 
     % make makefiles CCARGS="-DHAS_LMDB -I/usr/local/include" \
         AUXLIBS="-L/usr/local/lib -llmdb"
     % make
 
-Solaris needs this:
+Solaris may need this:
 
     % make makefiles CCARGS="-DHAS_LMDB -I/usr/local/include" \
         AUXLIBS="-R/usr/local/lib -L/usr/local/lib -llmdb"
@@ -47,12 +39,12 @@ The exact pathnames depend on how OpenLDAP LMDB was installed.
 
 C\bCo\bon\bnf\bfi\big\bgu\bur\bre\be L\bLM\bMD\bDB\bB s\bse\bet\btt\bti\bin\bng\bgs\bs
 
-Postfix provides a configuration parameter that controls how large an OpenLDAP
-LMDB database may grow.
+Postfix provides one configuration parameter that controls OpenLDAP LMDB
+database behavior.
 
-  * lmdb_map_size (default: 16 MBytes per table). This setting controls how
-    large any OpenLDAP LMDB database may grow. It must be set large enough to
-    accommodate the largest table that Postfix will use.
+  * lmdb_map_size (default: 16777216). This setting specifies the initial
+    OpenLDAP LMDB database size limit in bytes. Each time a database becomes
+    full, its size limit is doubled.
 
 M\bMi\bis\bss\bsi\bin\bng\bg p\bpt\bth\bhr\bre\bea\bad\bd l\bli\bib\bbr\bra\bar\bry\by t\btr\bro\bou\bub\bbl\ble\be
 
@@ -72,81 +64,17 @@ information is available at http://highlandsun.com/hyc/mdb/.
 U\bUn\bne\bex\bxp\bpe\bec\bct\bte\bed\bd f\bfa\bai\bil\blu\bur\bre\be m\bmo\bod\bde\bes\bs o\bof\bf P\bPo\bos\bst\btf\bfi\bix\bx L\bLM\bMD\bDB\bB d\bda\bat\bta\bab\bba\bas\bse\bes\bs.\b.
 
 As documented below, conversion to LMDB introduces a number of failure modes
-that don't exist with other Postfix databases.
-
-U\bUn\bne\bex\bxp\bpe\bec\bct\bte\bed\bd p\bpo\bos\bst\btm\bma\bap\bp(\b(1\b1)\b)/\b/p\bpo\bos\bst\bta\bal\bli\bia\bas\bs(\b(1\b1)\b) "\b"d\bda\bat\bta\bab\bba\bas\bse\be f\bfu\bul\bll\bl"\b" e\ber\brr\bro\bor\brs\bs.\b.
-
-Problem:
-    The "postmap lmdb:filename" command fails with an MDB_MAP_FULL error. This
-    problem does not exist with other Postfix databases.
-
-Background:
-    LMDB databases have a hard size limit (configured with the lmdb_map_size
-    configuration parameter).
-
-    When executing "postmap lmdb:filename", the Postfix LMDB database client
-    stores the new data in a transaction which takes up space in addition to
-    the existing data, and commits the transaction when it closes the database.
-    Only then can the space for old data be reused.
-
-Impact:
-    This failure does not affect Postfix availability, because the old data
-    still exists in the database.
-
-Mitigation:
-    When the postmap(1) or postalias(1) command fails with an MDB_MAP_FULL
-    error, it expands the database file size to the current LMDB map size limit
-    before terminating.
-
-    When the postmap(1) or postalias(1) command opens an LMDB file larger than
-    lmdb_map_size/3, it logs a warning and uses a larger size limit instead:
-
-    warning: filename.lmdb: file size 15024128 >= (lmdb map size limit
-    16777216)/3 -- using a larger map size limit
-
-    The two steps above can be used to automate recovery and avoid the need for
-    human intervention. Just repeat "postmap lmdb:filename" (up to some limit).
-    After each failure it will use a 3x larger size limit, and eventually the
-    "database full" error will disappear.
-
-Prevention:
-    Monitor your LMDB files and make sure that lmdb_map_size > 3x the largest
-    LMDB file size.
-
-U\bUn\bne\bex\bxp\bpe\bec\bct\bte\bed\bd P\bPo\bos\bst\btf\bfi\bix\bx d\bda\bae\bem\bmo\bon\bn "\b"d\bda\bat\bta\bab\bba\bas\bse\be f\bfu\bul\bll\bl"\b" e\ber\brr\bro\bor\brs\bs.\b.
-
-Problem:
-    Postfix daemon programs fail with "database full" errors, such as
-    postscreen(8), tlsmgr(8) or verify(8). This problem does not exist with
-    other Postfix databases.
-
-Impact:
-    This failure temporarily affects Postfix availability. The daemon restarts
-    automatically and tries to open the database again as described next.
-
-Mitigation:
-    When a Postfix daemon opens an LMDB file larger than lmdb_map_size/3, it
-    logs a warning and uses a larger size limit instead:
-
-    warning: filename.lmdb: file size 15024128 >= (lmdb map size limit
-    16777216)/3 -- using a larger map size limit
-
-    This can be used to automate recovery and avoid the need for human
-    intervention. Each time the daemon runs into a "database full" error, it
-    restarts and uses a 3x larger size limit. The "database full" error will
-    disappear, at least for a while.
-
-Prevention:
-    Monitor your LMDB files and make sure that lmdb_map_size > 3x the largest
-    LMDB file size.
+that don't exist with other Postfix databases. Some failure modes have been
+eliminated on the course of time. The writeup below reflects the status as of
+of LMDB 0.9.8.
 
 N\bNo\bon\bn-\b-o\bob\bbv\bvi\bio\bou\bus\bs r\bre\bec\bco\bov\bve\ber\bry\by w\bwi\bit\bth\bh p\bpo\bos\bst\btm\bma\bap\bp(\b(1\b1)\b)/\b/p\bpo\bos\bst\bta\bal\bli\bia\bas\bs(\b(1\b1)\b)/\b/t\btl\bls\bsm\bmg\bgr\br(\b(8\b8)\b) f\bfr\bro\bom\bm a\ba c\bco\bor\brr\bru\bup\bpt\bte\bed\bd
 d\bda\bat\bta\bab\bba\bas\bse\be.\b.
 
 Problem:
-    You cannot rebuild a corrupted LMDB database simply by running postmap(1)
-    or postalias(1), or by waiting until the tlsmgr(8) daemon restarts
-    automatically. This problem does not exist with other Postfix databases.
+    You cannot rebuild a corrupted LMDB database simply by re-running postmap
+    (1) or postalias(1), or by waiting until the tlsmgr(8) daemon restarts.
+    This problem does not exist with other Postfix databases.
 
 Background:
     The Postfix LMDB database client does not truncate the database file.
@@ -158,9 +86,9 @@ Impact:
     Postfix does not process mail until someone fixes the problem.
 
 Recovery:
-    First delete the ".lmdb" file by hand, then rebuild the file with the
+    First delete the ".lmdb" file by hand. Then, rebuild the file with the
     postmap(1) or postalias(1) command, or wait until the tlsmgr(8) daemon
-    restarts automatically.
+    restarts.
 
 Prevention:
     Arrange your file systems such that they never run out of free space.
index 309ee9ac48fe9dc3bc1b8229084016b5dae4d9b1..ffd51132e05587e0ffdc7b1aa5da9efdefa1468b 100644 (file)
@@ -896,7 +896,8 @@ With this, the reject_sender_login_mismatch restriction above will reject the
 sender address in the MAIL FROM command if smtpd_sender_login_maps does not
 specify the SMTP client's login name as an owner of that address.
 
-See also reject_authenticated_sender_login_mismatch and
+See also reject_authenticated_sender_login_mismatch,
+reject_known_sender_login_mismatch, and
 reject_unauthenticated_sender_login_mismatch for additional control over the
 SASL login name and the envelope sender.
 
index 8e61d3318ab0547af227049d99192a5c1a4b5a18..7f407a064212679a807d1a10b77d04edc728c35b 100644 (file)
@@ -13,11 +13,11 @@ stress-adaptive behavior, and for earlier Postfix versions that don't.
 Topics covered in this document:
 
   * Symptoms of Postfix SMTP server overload
+  * Automatic stress-adaptive behavior
   * Service more SMTP clients at the same time
   * Spend less time per SMTP client
   * Disconnect suspicious SMTP clients
   * Temporary measures for older Postfix releases
-  * Automatic stress-adaptive behavior
   * Detecting support for stress-adaptive behavior
   * Forcing stress-adaptive behavior on or off
   * Other measures to off-load zombies
@@ -65,13 +65,101 @@ Symptoms of Postfix SMTP server overload are:
     Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
      condition, increase the process count in master.cf or reduce the
      service time per client
+    Oct  3 20:39:27 spike postfix/master[28905]: warning: see
+      http://www.postfix.org/STRESS_README.html for examples of
+      stress-adapting configuration settings
 
 Legitimate mail that doesn't get through during an episode of Postfix SMTP
 server overload is not necessarily lost. It should still arrive once the
 situation returns to normal, as long as the overload condition is temporary.
 
+A\bAu\but\bto\bom\bma\bat\bti\bic\bc s\bst\btr\bre\bes\bss\bs-\b-a\bad\bda\bap\bpt\bti\biv\bve\be b\bbe\beh\bha\bav\bvi\bio\bor\br
+
+Postfix version 2.5 introduces automatic stress-adaptive behavior. It works as
+follows. When a "public" network service such as the SMTP server runs into an
+"all server ports are busy" condition, the Postfix master(8) daemon logs a
+warning, restarts the service (without interrupting existing network sessions),
+and runs the service with "-o stress=yes" on the server process command line:
+
+    80821  ??  S      0:00.24 smtpd -n smtp -t inet -u -c -o stress=yes
+
+Normally, the Postfix master(8) daemon runs such a service with "-o stress=" on
+the command line (i.e. with an empty parameter value):
+
+    83326  ??  S      0:00.28 smtpd -n smtp -t inet -u -c -o stress=
+
+Services that have local access only never have "-o stress" parameters on the
+command line. This includes services internal to Postfix such as the queue
+manager, and services that listen on a loopback interface only, such as after-
+filter SMTP services.
+
+The "stress" parameter value is the key to making main.cf parameter settings
+stress adaptive. The following settings are the default with Postfix 2.6 and
+later.
+
+    1 smtpd_timeout = ${stress?10}${stress:300}s
+    2 smtpd_hard_error_limit = ${stress?1}${stress:20}
+    3 smtpd_junk_command_limit = ${stress?1}${stress:100}
+    4 # Parameters added after Postfix 2.6:
+    5 smtpd_per_record_deadline = ${stress?yes}${stress:no}
+    6 smtpd_starttls_timeout = ${stress?10}${stress:300}s
+    7 address_verify_poll_count = ${stress?1}${stress:3}
+
+Translation:
+
+  * Line 1: under conditions of stress, use an smtpd_timeout value of 10
+    seconds instead of the default 300 seconds. Experience on the postfix-users
+    list from a variety of sysadmins shows that reducing the "normal"
+    smtpd_timeout to 60s is unlikely to affect legitimate clients. However, it
+    is unlikely to become the Postfix default because it's not RFC compliant.
+    Setting smtpd_timeout to 10s or even 5s under stress will still allow most
+    legitimate clients to connect and send mail, but may delay mail from some
+    clients. No mail should be lost, as long as this measure is used only
+    temporarily.
+
+  * Line 2: under conditions of stress, use an smtpd_hard_error_limit of 1
+    instead of the default 20. This helps by disconnecting clients after a
+    single error, giving other clients a chance to connect. However, this may
+    cause significant delays with legitimate mail, such as a mailing list that
+    contains a few no-longer-active user names that didn't bother to
+    unsubscribe. No mail should be lost, as long as this measure is used only
+    temporarily.
+
+  * Line 3: under conditions of stress, use an smtpd_junk_command_limit of 1
+    instead of the default 100. This prevents clients from keeping connections
+    open by repeatedly sending HELO, EHLO, NOOP, RSET, VRFY or ETRN commands.
+
+  * Line 5: under conditions of stress, change the behavior of smtpd_timeout
+    and smtpd_starttls_timeout, from a time limit per read or write system
+    call, to a time limit to send or receive a complete record (an SMTP command
+    line, SMTP response line, SMTP message content line, or TLS protocol
+    message).
+
+  * Line 6: under conditions of stress, reduce the time limit for TLS protocol
+    handshake messages to 10 seconds, from the default value of 300 seconds.
+    See also the smtpd_timeout discussion above.
+
+  * Line 7: under conditions of stress, do not wait up to 6 seconds for the
+    completion of an address verification probe. If the result is not already
+    in the address verification cache, reply immediately with
+    $unverified_recipient_tempfail_action or
+    $unverified_sender_tempfail_action. No mail should be lost, as long as this
+    measure is used only temporarily.
+
+The syntax of ${name?value} and ${name:value} is explained at the beginning of
+the postconf(5) manual page.
+
+NOTE: Please keep in mind that the stress-adaptive feature is a fairly
+desperate measure to keep s\bso\bom\bme\be legitimate mail flowing under overload
+conditions. If a site is reaching the SMTP server process limit when there
+isn't an attack or bot flood occurring, then either the process limit needs to
+be raised or more hardware needs to be added.
+
 S\bSe\ber\brv\bvi\bic\bce\be m\bmo\bor\bre\be S\bSM\bMT\bTP\bP c\bcl\bli\bie\ben\bnt\bts\bs a\bat\bt t\bth\bhe\be s\bsa\bam\bme\be t\bti\bim\bme\be
 
+This section and the ones that follow discuss permanent measures against mail
+server overload.
+
 One measure to avoid the "all server processes busy" condition is to service
 more SMTP clients simultaneously. For this you need to increase the number of
 Postfix SMTP server processes. This will improve the responsiveness for remote
@@ -256,72 +344,6 @@ With these measures, no mail should be lost, as long as these measures are used
 only temporarily. The next section of this document introduces a way to
 automate this process.
 
-A\bAu\but\bto\bom\bma\bat\bti\bic\bc s\bst\btr\bre\bes\bss\bs-\b-a\bad\bda\bap\bpt\bti\biv\bve\be b\bbe\beh\bha\bav\bvi\bio\bor\br
-
-Postfix version 2.5 introduces automatic stress-adaptive behavior. This is also
-available as a source code patch for Postfix versions 2.4 and 2.3 from the
-mirrors listed at http://www.postfix.org/download.html.
-
-It works as follows. When a "public" network service such as the SMTP server
-runs into an "all server ports are busy" condition, the Postfix master(8)
-daemon logs a warning, restarts the service (without interrupting existing
-network sessions), and runs the service with "-o stress=yes" on the server
-process command line:
-
-    80821  ??  S      0:00.24 smtpd -n smtp -t inet -u -c -o stress=yes
-
-Normally, the Postfix master(8) daemon runs such a service with "-o stress=" on
-the command line (i.e. with an empty parameter value):
-
-    83326  ??  S      0:00.28 smtpd -n smtp -t inet -u -c -o stress=
-
-Services that have local access only never have "-o stress" parameters on the
-command line. This includes services internal to Postfix such as the queue
-manager, and services that listen on a loopback interface only, such as after-
-filter SMTP services.
-
-The "stress" parameter value is the key to making main.cf parameter settings
-stress adaptive. The following settings are the default with Postfix 2.6 and
-later. With earlier Postfix versions that have stress-adaptive support, append
-the lines below to the main.cf file and issue a "postfix reload" command:
-
-    1 smtpd_timeout = ${stress?10}${stress:300}s
-    2 smtpd_hard_error_limit = ${stress?1}${stress:20}
-    3 smtpd_junk_command_limit = ${stress?1}${stress:100}
-
-Translation:
-
-  * Line 1: under conditions of stress, use an smtpd_timeout value of 10
-    seconds instead of the default 300 seconds. Experience on the postfix-users
-    list from a variety of sysadmins shows that reducing the "normal"
-    smtpd_timeout to 60s is unlikely to affect legitimate clients. However, it
-    is unlikely to become the Postfix default because it's not RFC compliant.
-    Setting smtpd_timeout to 10s (line 2 below) or even 5s under stress will
-    still allow most legitimate clients to connect and send mail, but may delay
-    mail from some clients. No mail should be lost, as long as this measure is
-    used only temporarily.
-
-  * Line 2: under conditions of stress, use an smtpd_hard_error_limit of 1
-    instead of the default 20. This helps by disconnecting clients after a
-    single error, giving other clients a chance to connect. However, this may
-    cause significant delays with legitimate mail, such as a mailing list that
-    contains a few no-longer-active user names that didn't bother to
-    unsubscribe. No mail should be lost, as long as this measure is used only
-    temporarily.
-
-  * Line 3: under conditions of stress, use an smtpd_junk_command_limit of 1
-    instead of the default 100. This prevents clients from keeping idle
-    connections open by repeatedly sending NOOP or RSET commands.
-
-The syntax of ${name?value} and ${name:value} is explained at the beginning of
-the postconf(5) manual page.
-
-NOTE: Please keep in mind that the stress-adaptive feature is a fairly
-desperate measure to keep s\bso\bom\bme\be legitimate mail flowing under overload
-conditions. If a site is reaching the SMTP server process limit when there
-isn't an attack or bot flood occurring, then either the process limit needs to
-be raised or more hardware needs to be added.
-
 D\bDe\bet\bte\bec\bct\bti\bin\bng\bg s\bsu\bup\bpp\bpo\bor\brt\bt f\bfo\bor\br s\bst\btr\bre\bes\bss\bs-\b-a\bad\bda\bap\bpt\bti\biv\bve\be b\bbe\beh\bha\bav\bvi\bio\bor\br
 
 To find out if your Postfix installation supports stress-adaptive behavior, use
index 4e204ae0d04296ddfc89731d46096e2a7b0f17ff..36443c2933541258bdff1a439310ab4ac6f8e8b3 100644 (file)
@@ -14,6 +14,14 @@ specifies the release date of a stable release or snapshot release.
 If you upgrade from Postfix 2.9 or earlier, read RELEASE_NOTES-2.10
 before proceeding.
 
+Major changes with snapshot 20130927
+====================================
+
+Postfix now handles LMDB "database full" errors automatically. When
+a database becomes full, its size limit is doubled, and other
+processes automatically pick up the new size limit. The lmdb_map_size
+parameter is now mostly irrelevant, and may be removed in the future.
+
 Major changes with snapshot 20130602
 ====================================
 
index 927544ef0220bf56e7f933df99bef8bd4a224466..a40d6cf507f7b35d217b7e143d1a7d571cb95d91 100644 (file)
@@ -16,6 +16,8 @@ Wish list:
        Begin code revision, after DANE support stabilizes.  This
        should be one pass that changes only names and no code.
 
+       recipient_delimiters = $recipient_delimiter for BC
+
        All source code must specify its original author and
        license statement. Some code modules specify Lutz Jaenicke
        as the original author and fall under his liberal license.
index d4fd3a287b326f186210dc51060a2fba2aff6830..22c8d06d4fef153f6370c20c716cf4f3bf4b50de 100644 (file)
@@ -310,6 +310,9 @@ default</th> </tr>
 <tr> <td>DEF_CONFIG_DIR</td> <td><a href="postconf.5.html#config_directory">config_directory</a></td>
 <td>/etc/postfix</td> </tr>
 
+<tr> <td>DEF_DB_TYPE</td> <td><a href="postconf.5.html#default_database_type">default_database_type</a></td>
+<td>hash</td> </tr>
+
 <tr> <td>DEF_DAEMON_DIR</td> <td><a href="postconf.5.html#daemon_directory">daemon_directory</a></td>
 <td>/usr/libexec/postfix</td> </tr>
 
@@ -376,7 +379,9 @@ off Postfix features at compile time:</td> </tr>
 
 <tr> <td> </td> <td> -DNO_DB </td> <td> Do not build with Berkeley
 DB support. By default, Berkeley DB support is compiled in on
-platforms that are known to support this feature.  </td> </tr>
+platforms that are known to support this feature. If you override
+this, then you probably should also override DEF_DB_TYPE as described
+in section 4.4.  </td> </tr>
 
 <tr> <td> </td> <td> -DNO_DEVPOLL </td> <td> Do not build with
 Solaris <tt>/dev/poll</tt> support. By default, <tt>/dev/poll</tt>
index 81d1484dba2bb26dcb39cf9f9a294e7947e11c5e..2c6dbb59756b751becf89c2e811b111372647c12 100644 (file)
 
 <h2>Introduction</h2>
 
-<blockquote> <p> <strong> Warning: LMDB databases have a show-stopper
-bug: they do not grow beyond a specified limit, and introduce a
-"database full" hard error condition that does not exist with any
-other Postfix database type.  This is a problem for programs whose
-database grows with system load. Examples are <a href="postscreen.8.html">postscreen(8)</a>,
-greylisting, <a href="verify.8.html">verify(8)</a> and <a href="tlsmgr.8.html">tlsmgr(8)</a>.  </strong> </p> <p> <strong>
-You have been warned.  </strong> </p> </blockquote>
-
 <p> Postfix uses databases of various kinds to store and look up
 information. Postfix databases are specified as "type:name".
 OpenLDAP LMDB implements the Postfix database type "lmdb".
@@ -52,9 +44,8 @@ don't exist with other Postfix databases. </p>
 
 <h2><a name="with_lmdb">Building Postfix with OpenLDAP LMDB support</a></h2>
 
-<p> Postfix normally does not enable OpenLDAP LMDB support.
-To build Postfix after you installed OpenLDAP LMDB from
-source code, use something like: </p>
+<p> Postfix normally does not enable OpenLDAP LMDB support.  To
+build Postfix with OpenLDAP LMDB support, use something like: </p>
 
 <blockquote>
 <pre>
@@ -64,7 +55,7 @@ source code, use something like: </p>
 </pre>
 </blockquote>
 
-<p> Solaris needs this: </p>
+<p> Solaris may need this: </p>
 
 <blockquote>
 <pre>
@@ -78,15 +69,14 @@ source code, use something like: </p>
 
 <h2><a name="configure">Configure LMDB settings</a></h2>
 
-<p> Postfix provides a configuration parameter that controls how
-large an OpenLDAP LMDB database may grow. </p>
+<p> Postfix provides one configuration parameter that controls 
+OpenLDAP LMDB database behavior. </p>
 
 <ul>
 
-<li> <p> <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a> (default: 16 MBytes per table).  This setting
-controls how large any OpenLDAP LMDB database may grow. It must be
-set large enough to accommodate the largest table that Postfix will
-use. </p>
+<li> <p> <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a> (default: 16777216).  This setting specifies
+the initial OpenLDAP LMDB database size limit in bytes.  Each time
+a database becomes full, its size limit is doubled.  </p>
 
 </ul>
 
@@ -119,15 +109,17 @@ More information is available at
 databases.  </a> </h2>
 
 <p> As documented below, conversion to LMDB introduces a number of
-failure modes that don't exist with other Postfix databases. </p>
+failure modes that don't exist with other Postfix databases.  Some
+failure modes have been eliminated on the course of time.
+The writeup below reflects the status as of of LMDB 0.9.8. </p>
+
+<!--
 
 <p> <strong>Unexpected <a href="postmap.1.html">postmap(1)</a>/<a href="postalias.1.html">postalias(1)</a> "database full"
 errors.  </strong></p>
 
 <dl>
 
-<!--
-
 <dt> Problem: </dt> <dd> <p> The "postmap <a href="LMDB_README.html">lmdb</a>:filename" command
 fails with an MDB_TXN_FULL error.  This problem does not exist with
 other Postfix databases. </p> </dd>
@@ -146,8 +138,6 @@ structures should share the same storage pool so that they can scale
 with the database size, and so that all "out of storage" errors are
 resolved by increasing the database size. </p> </dd>
 
--->
-
 <dt> Problem: </dt> <dd> <p> The "postmap <a href="LMDB_README.html">lmdb</a>:filename" command
 fails with an MDB_MAP_FULL error.  This problem does not exist with
 other Postfix databases. </p> </dd>
@@ -177,23 +167,25 @@ availability, because the old data still exists in the database.
 MDB_MAP_FULL error, it expands the database file size to the current
 LMDB map size limit before terminating.  </p>
 
-<p> When the <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a> command opens an LMDB file
-larger than <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a>/3, it logs a warning and uses a larger
-size limit instead: </p>
+<p> Next, when you re-run the <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a> command,
+it discovers that the LMDB file is larger than <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a>/3,
+logs a warning, and uses a larger LMDB map size limit instead: </p>
 
 <p> <tt> warning: <i>filename</i>.<a href="LMDB_README.html">lmdb</a>: file size 15024128 &ge;
-(lmdb map size limit 16777216)/3 -- using a larger map size limit</tt>
-</p>
+(lmdb map size limit 16777216)/3<br> warning: <i>filename</i>.<a href="LMDB_README.html">lmdb</a>:
+using map size limit 45072384</tt> </p>
 
-<p> The two steps above can be used to automate recovery and avoid
-the need for human intervention. Just repeat "postmap <a href="LMDB_README.html">lmdb</a>:filename"
-(up to some limit).  After each failure it will use a 3x larger
-size limit, and eventually the "database full" error will disappear.
-</p>
+<p> By repeating the two steps above you can automate recovery and
+avoid the need for human intervention. Just repeat "postmap
+<a href="LMDB_README.html">lmdb</a>:filename" (up to some limit).  After each failure it will use
+a 3x larger size limit, and eventually the "database full" error
+should disappear. This fails only when the disk is full or when
+the LMDB map size limit would exceed the memory address space size
+limit.  </p>
 
 <dt> Prevention: </dt> <dd> <p> Monitor your LMDB files and make
-sure that <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a> &gt; 3x the largest LMDB file size. </p>
-</dd> </dl>
+sure that in <a href="postconf.5.html">main.cf</a>, <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a> &gt; 3x the largest LMDB file
+size. </p> </dd> </dl>
 
 <p> <strong>Unexpected Postfix daemon "database full" errors.
 </strong></p>
@@ -214,8 +206,8 @@ file larger than <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a>/3, it
 larger size limit instead: </p>
 
 <p> <tt> warning: <i>filename</i>.<a href="LMDB_README.html">lmdb</a>: file size 15024128 &ge;
-(lmdb map size limit 16777216)/3 -- using a larger map size limit</tt>
-</p>
+(lmdb map size limit 16777216)/3 <br>warning: <i>filename</i>.<a href="LMDB_README.html">lmdb</a>:
+using map size limit 45072384</tt> </p>
 
 <p> This can be used to automate recovery and avoid the need for
 human intervention. Each time the daemon runs into a "database full"
@@ -226,14 +218,16 @@ full" error will disappear, at least for a while.  </p>
 sure that <a href="postconf.5.html#lmdb_map_size">lmdb_map_size</a> &gt; 3x the largest LMDB file size. </p>
 </dd> </dl>
 
+-->
+
 <p> <strong>Non-obvious recovery with <a href="postmap.1.html">postmap(1)</a>/<a href="postalias.1.html">postalias(1)</a>/<a href="tlsmgr.8.html">tlsmgr(8)</a>
 from a corrupted database.  </strong></p>
 
 <dl>
 
 <dt> Problem: </dt> <dd> <p> You cannot rebuild a corrupted LMDB
-database simply by running <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a>, or by waiting
-until the <a href="tlsmgr.8.html">tlsmgr(8)</a> daemon restarts automatically.  This problem
+database simply by re-running <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a>, or by
+waiting until the <a href="tlsmgr.8.html">tlsmgr(8)</a> daemon restarts.  This problem
 does not exist with other Postfix databases.  </p> </dd>
 
 <dt> Background: </dt> <dd> <p> The Postfix LMDB database client
@@ -245,9 +239,9 @@ That is obviously not possible with a corrupted database file. </p>
 <dt> Impact: </dt> <dd> <p> Postfix does not process mail until
 someone fixes the problem.  </p> </dd>
 
-<dt> Recovery: </dt> <dd> <p> First delete the ".lmdb" file by hand,
-then rebuild the file with the <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a> command,
-or wait until the <a href="tlsmgr.8.html">tlsmgr(8)</a> daemon restarts automatically.  </p>
+<dt> Recovery: </dt> <dd> <p> First delete the ".lmdb" file by hand.
+Then, rebuild the file with the <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a> command,
+or wait until the <a href="tlsmgr.8.html">tlsmgr(8)</a> daemon restarts.  </p>
 </dd>
 
 <dt> Prevention: </dt> <dd> 
index ec5cb84caa3e53582d1011037047bba49baab7bd..408ad2e4fd3801c9b9c0b8c523f63dff200373cd 100644 (file)
@@ -1450,7 +1450,8 @@ restriction above will reject the sender address in the MAIL FROM
 command if <code><a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a></code> does not specify
 the SMTP client's login name as an owner of that address. </p>
 
-<p> See also <code><a href="postconf.5.html#reject_authenticated_sender_login_mismatch">reject_authenticated_sender_login_mismatch</a></code> and
+<p> See also <code><a href="postconf.5.html#reject_authenticated_sender_login_mismatch">reject_authenticated_sender_login_mismatch</a></code>,
+<code><a href="postconf.5.html#reject_known_sender_login_mismatch">reject_known_sender_login_mismatch</a></code>, and
 <code><a href="postconf.5.html#reject_unauthenticated_sender_login_mismatch">reject_unauthenticated_sender_login_mismatch</a></code> for additional
 control over the SASL login name and the envelope sender. </p>
 
index bd4c1b8339d715d65def7c70e094c217d5a18ab9..8dbfa3f7d5370b1233a0db43eb07fb36f0c116d8 100644 (file)
@@ -33,6 +33,8 @@ and for earlier Postfix versions that don't.  </p>
 
 <li><a href="#overload"> Symptoms of Postfix SMTP server overload </a> 
 
+<li><a href="#adapt"> Automatic stress-adaptive behavior </a>
+
 <li><a href="#concurrency"> Service more SMTP clients at the same time </a> 
 
 <li><a href="#time"> Spend less time per SMTP client </a>
@@ -41,8 +43,6 @@ and for earlier Postfix versions that don't.  </p>
 
 <li><a href="#legacy"> Temporary measures for older Postfix releases </a>
 
-<li><a href="#adapt"> Automatic stress-adaptive behavior </a>
-
 <li><a href="#feature"> Detecting support for stress-adaptive behavior </a>
 
 <li><a href="#forcing"> Forcing stress-adaptive behavior on or off </a>
@@ -109,6 +109,9 @@ Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
 Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
  condition, increase the process count in <a href="master.5.html">master.cf</a> or reduce the
  service time per client
+Oct  3 20:39:27 spike postfix/master[28905]: warning: see
+  <a href="http://www.postfix.org/STRESS_README.html">http://www.postfix.org/STRESS_README.html</a> for examples of
+  stress-adapting configuration settings
 </pre>
 
 </ul>
@@ -118,8 +121,116 @@ Postfix SMTP server overload is not necessarily lost. It should
 still arrive once the situation returns to normal, as long as the
 overload condition is temporary.  </p>
 
+<h2><a name="adapt"> Automatic stress-adaptive behavior </a></h2>
+
+<p> Postfix version 2.5 introduces automatic stress-adaptive behavior.
+It works as follows. When a "public" network service such as the
+SMTP server runs into an "all server ports are busy" condition, the
+Postfix <a href="master.8.html">master(8)</a> daemon logs a warning, restarts the service
+(without interrupting existing network sessions), and runs the
+service with "-o stress=yes" on the server process command line:
+</p>
+
+<blockquote>
+<pre>
+80821  ??  S      0:00.24 smtpd -n smtp -t inet -u -c -o stress=yes
+</pre>
+</blockquote>
+
+<p> Normally, the Postfix <a href="master.8.html">master(8)</a> daemon runs such a service with
+"-o stress=" on the command line (i.e.  with an empty parameter
+value):  </p>
+
+<blockquote>
+<pre>
+83326  ??  S      0:00.28 smtpd -n smtp -t inet -u -c -o stress=
+</pre>
+</blockquote>
+
+<p> Services that have local access only never have "-o stress"
+parameters on the command line. This includes services internal to
+Postfix such as the queue manager, and services that listen on a
+loopback interface only, such as after-filter SMTP services.  </p>
+
+<p> The "stress" parameter value is the key to making <a href="postconf.5.html">main.cf</a>
+parameter settings stress adaptive. The following settings are the
+default with Postfix 2.6 and later. </p>
+
+<blockquote>
+<pre>
+1 <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> = ${stress?10}${stress:300}s
+2 <a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> = ${stress?1}${stress:20}
+3 <a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> = ${stress?1}${stress:100}
+4 # Parameters added after Postfix 2.6:
+5 <a href="postconf.5.html#smtpd_per_record_deadline">smtpd_per_record_deadline</a> = ${stress?yes}${stress:no}
+6 <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a> = ${stress?10}${stress:300}s
+7 <a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> = ${stress?1}${stress:3}
+</pre>
+</blockquote>
+
+<p> Translation: <p>
+
+<ul>
+
+<li> <p> Line 1: under conditions of stress, use an <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a>
+value of 10 seconds instead of the default 300 seconds. Experience
+on the postfix-users list from a variety of sysadmins shows that
+reducing the "normal" <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> to 60s is unlikely to affect
+legitimate clients. However, it is unlikely to become the Postfix
+default because it's not RFC compliant. Setting <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> to
+10s or even 5s under stress will still allow most
+legitimate clients to connect and send mail, but may delay mail
+from some clients. No mail should be lost, as long as this measure
+is used only temporarily. </p>
+
+<li> <p> Line 2: under conditions of stress, use an <a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a>
+of 1 instead of the default 20. This helps by disconnecting clients
+after a single error, giving other clients a chance to connect.
+However, this may cause significant delays with legitimate mail,
+such as a mailing list that contains a few no-longer-active user
+names that didn't bother to unsubscribe. No mail should be lost,
+as long as this measure is used only temporarily. </p>
+
+<li> <p> Line 3: under conditions of stress, use an
+<a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> of 1 instead of the default 100. This
+prevents clients from keeping connections open by repeatedly
+sending HELO, EHLO, NOOP, RSET, VRFY or ETRN commands. </p>
+
+<li> <p> Line 5: under conditions of stress, change the behavior
+of <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> and <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a>, from a time limit per
+read or write system call, to a time limit to send or receive a
+complete record (an SMTP command line, SMTP response line, SMTP
+message content line, or TLS protocol message). </p>
+
+<li> <p> Line 6: under conditions of stress, reduce the time limit
+for TLS protocol handshake messages to 10 seconds, from the default
+value of 300 seconds. See also the <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> discussion above.
+</p>
+
+<li> <p> Line 7: under conditions of stress, do not wait up to 6
+seconds for the completion of an address verification probe. If the
+result is not already in the address verification cache, reply
+immediately with $<a href="postconf.5.html#unverified_recipient_tempfail_action">unverified_recipient_tempfail_action</a> or
+$<a href="postconf.5.html#unverified_sender_tempfail_action">unverified_sender_tempfail_action</a>. No mail should be lost, as long
+as this measure is used only temporarily.  </p>
+
+</ul>
+
+<p> The syntax of ${name?value} and ${name:value} is explained at
+the beginning of the <a href="postconf.5.html">postconf(5)</a> manual page. </p>
+
+<p> NOTE: Please keep in mind that the stress-adaptive feature is
+a fairly desperate measure to keep <b>some</b> legitimate mail
+flowing under overload conditions.  If a site is reaching the SMTP
+server process limit when there isn't an attack or bot flood
+occurring, then either the process limit needs to be raised or more
+hardware needs to be added.  </p>
+
 <h2><a name="concurrency"> Service more SMTP clients at the same time </a> </h2>
 
+<p> This section and the ones that follow discuss permanent measures
+against mail server overload.  </p>
+
 <p> One measure to avoid the "all server processes busy" condition
 is to service more SMTP clients simultaneously. For this you need
 to increase the number of Postfix SMTP server processes. This will
@@ -349,95 +460,6 @@ repeatedly sending NOOP or RSET commands. </p>
 as these measures are used only temporarily. The next section of
 this document introduces a way to automate this process. </p>
 
-<h2><a name="adapt"> Automatic stress-adaptive behavior </a></h2>
-
-<p> Postfix version 2.5 introduces automatic stress-adaptive behavior.
-This is also available as a source code patch for Postfix versions
-2.4 and 2.3 from the mirrors listed at
-<a href="http://www.postfix.org/download.html">http://www.postfix.org/download.html</a>.  </p>
-
-<p> It works as follows. When a "public" network service such as
-the SMTP server runs into an "all server ports are busy" condition,
-the Postfix <a href="master.8.html">master(8)</a> daemon logs a warning, restarts the service
-(without interrupting existing network sessions), and runs the
-service with "-o stress=yes" on the server process command line:
-</p>
-
-<blockquote>
-<pre>
-80821  ??  S      0:00.24 smtpd -n smtp -t inet -u -c -o stress=yes
-</pre>
-</blockquote>
-
-<p> Normally, the Postfix <a href="master.8.html">master(8)</a> daemon runs such a service with
-"-o stress=" on the command line (i.e.  with an empty parameter
-value):  </p>
-
-<blockquote>
-<pre>
-83326  ??  S      0:00.28 smtpd -n smtp -t inet -u -c -o stress=
-</pre>
-</blockquote>
-
-<p> Services that have local access only never have "-o stress"
-parameters on the command line. This includes services internal to
-Postfix such as the queue manager, and services that listen on a
-loopback interface only, such as after-filter SMTP services.  </p>
-
-<p> The "stress" parameter value is the key to making <a href="postconf.5.html">main.cf</a>
-parameter settings stress adaptive. The following settings are the
-default with Postfix 2.6 and later. With earlier Postfix versions
-that have stress-adaptive support, append the lines below to the
-<a href="postconf.5.html">main.cf</a> file and issue a "postfix reload" command: </p>
-
-<blockquote>
-<pre>
-1 <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> = ${stress?10}${stress:300}s
-2 <a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> = ${stress?1}${stress:20}
-3 <a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> = ${stress?1}${stress:100}
-</pre>
-</blockquote>
-
-<p> Translation: <p>
-
-<ul>
-
-<li> <p> Line 1: under conditions of stress, use an <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a>
-value of 10 seconds instead of the default 300 seconds. Experience
-on the postfix-users list from a variety of sysadmins shows that
-reducing the "normal" <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> to 60s is unlikely to affect
-legitimate clients. However, it is unlikely to become the Postfix
-default because it's not RFC compliant. Setting <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> to
-10s (line 2 below) or even 5s under stress will still allow most
-legitimate clients to connect and send mail, but may delay mail
-from some clients. No mail should be lost, as long as this measure
-is used only temporarily. </p>
-
-<li> <p> Line 2: under conditions of stress, use an <a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a>
-of 1 instead of the default 20. This helps by disconnecting clients
-after a single error, giving other clients a chance to connect.
-However, this may cause significant delays with legitimate mail,
-such as a mailing list that contains a few no-longer-active user
-names that didn't bother to unsubscribe. No mail should be lost,
-as long as this measure is used only temporarily. </p>
-
-<li> <p> Line 3: under conditions of stress, use an
-<a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> of 1 instead of the default 100. This
-prevents clients from keeping idle connections open by repeatedly
-sending NOOP or RSET commands. </p>
-
-</ul>
-
-<p> The syntax of ${name?value} and ${name:value} is explained at
-the beginning of the <a href="postconf.5.html">postconf(5)</a> manual page. </p>
-
-<p> NOTE: Please keep in mind that the stress-adaptive feature is
-a fairly desperate measure to keep <b>some</b> legitimate mail
-flowing under overload conditions.  If a site is reaching the SMTP
-server process limit when there isn't an attack or bot flood
-occurring, then either the process limit needs to be raised or more
-hardware needs to be added.  </p>
-
 <h2><a name="feature"> Detecting support for stress-adaptive behavior </a></h2>
 
 <p> To find out if your Postfix installation supports stress-adaptive
index 8d8c43039722704bc99c29b8540edd6e6267821e..dcb3a9ee7d4fdeb6c621e8a03c8cf7b330793af9 100644 (file)
@@ -10,9 +10,9 @@ LDAP_TABLE(5)                                                    LDAP_TABLE(5)
        ldap_table - Postfix LDAP client configuration
 
 <b>SYNOPSIS</b>
-       <b>postmap -q "</b><i>string</i><b>" <a href="ldap_table.5.html">ldap</a>:/etc/postfix/filename</b>
+       <b>postmap -q "<i></b>string</i><b>" <a href="ldap_table.5.html">ldap</a>:/etc/postfix/filename</b>
 
-       <b>postmap -q - <a href="ldap_table.5.html">ldap</a>:/etc/postfix/</b><i>filename</i> &lt;<i>inputfile</i>
+       <b>postmap -q - <a href="ldap_table.5.html">ldap</a>:/etc/postfix/<i></b>filename</i> &lt;<i>inputfile</i>
 
 <b>DESCRIPTION</b>
        The  Postfix  mail system uses optional tables for address
@@ -716,7 +716,7 @@ LDAP_TABLE(5)                                                    LDAP_TABLE(5)
               the <b>demand</b> value of <b>TLS_REQCERT</b> in LDAP client con-
               figuration files.
 
-              The "try" and "never" values of <b>TLS_REQCERT</b> have no
+              The "try" and "allow" values of <b>TLS_REQCERT</b> have no
               equivalents  here.  They  are  not  available  with
               OpenLDAP  2.0,  and  in  any case have questionable
               security properties. Either you want  TLS  verified
index a173c855746c2b101fb679ae94fa9f02362d0974..a9ca178248641aa041e5ec6815828fd39279001d 100644 (file)
@@ -3782,11 +3782,11 @@ this length; upon delivery, long lines are reconstructed.  </p>
 </DD>
 
 <DT><b><a name="lmdb_map_size">lmdb_map_size</a>
-(default: 10485760)</b></DT><DD>
+(default: 16777216)</b></DT><DD>
 
 <p>
-The per-table size limit for programs that create OpenLDAP LMDB
-tables.  Specify a byte count.
+The initial OpenLDAP LMDB database size limit in bytes.  Each time
+a database becomes full, its size limit is doubled.
 </p>
 
 <p>
@@ -13683,7 +13683,8 @@ DNS lookup and increases the maximal inbound delivery rate. </p>
 <DT><b><a name="smtpd_per_record_deadline">smtpd_per_record_deadline</a>
 (default: normal: no, overload: yes)</b></DT><DD>
 
-<p> Change the behavior of the <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> time limit, from a
+<p> Change the behavior of the <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> and <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a>
+time limits, from a
 time limit per read or write system call, to a time limit to send
 or receive a complete record (an SMTP command line, SMTP response
 line, SMTP message content line, or TLS protocol message).  This
@@ -14706,6 +14707,12 @@ feature is available in Postfix 2.1 and later.  </dd>
 authenticated clients only. This feature is available in
 Postfix version 2.1 and later. </dd>
 
+<dt><b><a name="reject_known_sender_login_mismatch">reject_known_sender_login_mismatch</a></b></dt>
+
+<dd>Apply the <a href="postconf.5.html#reject_sender_login_mismatch">reject_sender_login_mismatch</a> restriction only to MAIL
+FROM addresses that are known in $<a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a>.  This
+feature is available in Postfix version 2.11 and later. </dd>
+
 <dt><b><a name="reject_non_fqdn_sender">reject_non_fqdn_sender</a></b></dt>
 
 <dd>Reject the request when the MAIL FROM address is not in
index f746a465098ff9482f35c116268f656a9708f886..898f9d707dc72e6f89e5f9c248a035bdb66d4c0c 100644 (file)
@@ -189,7 +189,7 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               where a  non-whitelisted  remote  SMTP  client  can
               obtain  <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s temporary whitelist status.
 
-<b>BEFORE-GREETING TESTS</b>
+<b>BEFORE 220 GREETING TESTS</b>
        These tests are executed before  the  remote  SMTP  client
        receives the "220 servername" greeting. If no tests remain
        after the successful completion of this phase, the  client
@@ -253,13 +253,13 @@ POSTSCREEN(8)                                                    POSTSCREEN(8)
               combined  DNSBL   score   as   defined   with   the
               <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
 
-<b>AFTER-GREETING TESTS</b>
+<b>AFTER 220 GREETING TESTS</b>
        These  tests  are  executed  after  the remote SMTP client
        receives the "220 servername" greeting. If a client passes
        all  tests  during  this  phase,  it  will  receive  a 4XX
-       response to RCPT TO commands until the  client  hangs  up.
-       After this, the client will be allowed to talk directly to
-       a Postfix SMTP server process.
+       response to all RCPT TO commands. After the client  recon-
+       nects,  it  will  be allowed to talk directly to a Postfix
+       SMTP server process.
 
        <b><a href="postconf.5.html#postscreen_bare_newline_action">postscreen_bare_newline_action</a> (ignore)</b>
               The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when  a  remote
index 0b650edebadfb867ffd5d7af38e21709446d293a..67fa8244ee4ebf01c2529f117747f1a314a05320 100644 (file)
@@ -658,7 +658,7 @@ version dependent behavior). The \fByes\fR setting corresponds to the
 \fBdemand\fR value of \fBTLS_REQCERT\fR in LDAP client configuration
 files.
 .sp
-The "try" and "never" values of \fBTLS_REQCERT\fR have no equivalents
+The "try" and "allow" values of \fBTLS_REQCERT\fR have no equivalents
 here. They are not available with OpenLDAP 2.0, and in any case have
 questionable security properties. Either you want TLS verified LDAP
 connections, or you don't.
index 02d7d8824404e57cef278a0d39e4f5696ab1b515..d9d7dfea97f9b9e9e17a8cabe97ecaeb4bfcc79e 100644 (file)
@@ -2242,9 +2242,9 @@ This feature is available in Postfix 2.1 and later.
 .SH line_length_limit (default: 2048)
 Upon input, long lines are chopped up into pieces of at most
 this length; upon delivery, long lines are reconstructed.
-.SH lmdb_map_size (default: 10485760)
-The per-table size limit for programs that create OpenLDAP LMDB
-tables.  Specify a byte count.
+.SH lmdb_map_size (default: 16777216)
+The initial OpenLDAP LMDB database size limit in bytes.  Each time
+a database becomes full, its size limit is doubled.
 .PP
 This feature is available in Postfix 2.11 and later.
 .SH lmtp_address_preference (default: ipv6)
@@ -9034,7 +9034,8 @@ DNS lookup and increases the maximal inbound delivery rate.
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH smtpd_per_record_deadline (default: normal: no, overload: yes)
-Change the behavior of the smtpd_timeout time limit, from a
+Change the behavior of the smtpd_timeout and smtpd_starttls_timeout
+time limits, from a
 time limit per read or write system call, to a time limit to send
 or receive a complete record (an SMTP command line, SMTP response
 line, SMTP message content line, or TLS protocol message).  This
@@ -9797,6 +9798,11 @@ Enforces the reject_sender_login_mismatch restriction for
 authenticated clients only. This feature is available in
 Postfix version 2.1 and later.
 .br
+.IP "\fBreject_known_sender_login_mismatch\fR"
+Apply the reject_sender_login_mismatch restriction only to MAIL
+FROM addresses that are known in $smtpd_sender_login_maps.  This
+feature is available in Postfix version 2.11 and later.
+.br
 .IP "\fBreject_non_fqdn_sender\fR"
 Reject the request when the MAIL FROM address is not in
 fully-qualified domain form, as required by the RFC.
index 2aa1aacb295e40a7d198386dbb32f02b3a4c149e..de8bb240129ff82eb31b5e5fbc5a16ba7952da70 100644 (file)
@@ -196,7 +196,7 @@ which would introduce a common point of failure.
 A list of local \fBpostscreen\fR(8) server IP addresses where a
 non-whitelisted remote SMTP client can obtain \fBpostscreen\fR(8)'s temporary
 whitelist status.
-.SH "BEFORE-GREETING TESTS"
+.SH "BEFORE 220 GREETING TESTS"
 .na
 .nf
 .ad
@@ -248,7 +248,7 @@ Available in Postfix version 2.11 and later:
 Allow a remote SMTP client to skip "before" and "after 220
 greeting" protocol tests, based on its combined DNSBL score as
 defined with the postscreen_dnsbl_sites parameter.
-.SH "AFTER-GREETING TESTS"
+.SH "AFTER 220 GREETING TESTS"
 .na
 .nf
 .ad
@@ -256,9 +256,9 @@ defined with the postscreen_dnsbl_sites parameter.
 These tests are executed after the remote SMTP client
 receives the "220 servername" greeting. If a client passes
 all tests during this phase, it will receive a 4XX response
-to RCPT TO commands until the client hangs up. After this,
-the client will be allowed to talk directly to a Postfix
-SMTP server process.
+to all RCPT TO commands. After the client reconnects, it
+will be allowed to talk directly to a Postfix SMTP server
+process.
 .IP "\fBpostscreen_bare_newline_action (ignore)\fR"
 The action that \fBpostscreen\fR(8) takes when a remote SMTP client sends
 a bare newline character, that is, a newline not preceded by carriage
index 6da58ae745f8f78dd2b7f523a1e210b2c7b41a63..f038fb62029cbfcd285626a258bddca2ffbb6e02 100755 (executable)
@@ -897,6 +897,7 @@ while (<>) {
     s;\bcheck_sender_mx_access\b;<a href="postconf.5.html#check_sender_mx_access">$&</a>;g;
     s;\bcheck_sender_ns_access\b;<a href="postconf.5.html#check_sender_ns_access">$&</a>;g;
     s;\b(reject_authenti)([-</bB>]*\n*[ <bB>]*)(cated_sender_login_mismatch)\b;<a href="postconf.5.html#reject_authenticated_sender_login_mismatch">$1<\/a>$2<a href="postconf.5.html#reject_authenticated_sender_login_mismatch">$3</a>;g;
+    s;\breject_known_sender_login_mismatch\b;<a href="postconf.5.html#reject_known_sender_login_mismatch">$&</a>;g;
     s;\breject_non_fqdn_sender\b;<a href="postconf.5.html#reject_non_fqdn_sender">$&</a>;g;
     s;\breject_rhsbl_sender\b;<a href="postconf.5.html#reject_rhsbl_sender">$&</a>;g;
     s;\breject_sender_login_mis[-</bB>]*\n*[ <bB>]*match\b;<a href="postconf.5.html#reject_sender_login_mismatch">$&</a>;g;
index a4bb6ac4644ec0ca40c7003c0fcbf04bb7beacaf..93200249cd388db63b6a1f685d625eb7d583c3d4 100644 (file)
@@ -310,6 +310,9 @@ default</th> </tr>
 <tr> <td>DEF_CONFIG_DIR</td> <td>config_directory</td>
 <td>/etc/postfix</td> </tr>
 
+<tr> <td>DEF_DB_TYPE</td> <td>default_database_type</td>
+<td>hash</td> </tr>
+
 <tr> <td>DEF_DAEMON_DIR</td> <td>daemon_directory</td>
 <td>/usr/libexec/postfix</td> </tr>
 
@@ -376,7 +379,9 @@ off Postfix features at compile time:</td> </tr>
 
 <tr> <td> </td> <td> -DNO_DB </td> <td> Do not build with Berkeley
 DB support. By default, Berkeley DB support is compiled in on
-platforms that are known to support this feature.  </td> </tr>
+platforms that are known to support this feature. If you override
+this, then you probably should also override DEF_DB_TYPE as described
+in section 4.4.  </td> </tr>
 
 <tr> <td> </td> <td> -DNO_DEVPOLL </td> <td> Do not build with
 Solaris <tt>/dev/poll</tt> support. By default, <tt>/dev/poll</tt>
index 72451281975def8f6ea25b557bf97e2ef8bb7e1b..5f810dcc560b71fc047a6360deaa143137386134 100644 (file)
 
 <h2>Introduction</h2>
 
-<blockquote> <p> <strong> Warning: LMDB databases have a show-stopper
-bug: they do not grow beyond a specified limit, and introduce a
-"database full" hard error condition that does not exist with any
-other Postfix database type.  This is a problem for programs whose
-database grows with system load. Examples are postscreen(8),
-greylisting, verify(8) and tlsmgr(8).  </strong> </p> <p> <strong>
-You have been warned.  </strong> </p> </blockquote>
-
 <p> Postfix uses databases of various kinds to store and look up
 information. Postfix databases are specified as "type:name".
 OpenLDAP LMDB implements the Postfix database type "lmdb".
@@ -52,9 +44,8 @@ don't exist with other Postfix databases. </p>
 
 <h2><a name="with_lmdb">Building Postfix with OpenLDAP LMDB support</a></h2>
 
-<p> Postfix normally does not enable OpenLDAP LMDB support.
-To build Postfix after you installed OpenLDAP LMDB from
-source code, use something like: </p>
+<p> Postfix normally does not enable OpenLDAP LMDB support.  To
+build Postfix with OpenLDAP LMDB support, use something like: </p>
 
 <blockquote>
 <pre>
@@ -64,7 +55,7 @@ source code, use something like: </p>
 </pre>
 </blockquote>
 
-<p> Solaris needs this: </p>
+<p> Solaris may need this: </p>
 
 <blockquote>
 <pre>
@@ -78,15 +69,14 @@ source code, use something like: </p>
 
 <h2><a name="configure">Configure LMDB settings</a></h2>
 
-<p> Postfix provides a configuration parameter that controls how
-large an OpenLDAP LMDB database may grow. </p>
+<p> Postfix provides one configuration parameter that controls 
+OpenLDAP LMDB database behavior. </p>
 
 <ul>
 
-<li> <p> lmdb_map_size (default: 16 MBytes per table).  This setting
-controls how large any OpenLDAP LMDB database may grow. It must be
-set large enough to accommodate the largest table that Postfix will
-use. </p>
+<li> <p> lmdb_map_size (default: 16777216).  This setting specifies
+the initial OpenLDAP LMDB database size limit in bytes.  Each time
+a database becomes full, its size limit is doubled.  </p>
 
 </ul>
 
@@ -119,15 +109,17 @@ http://highlandsun.com/hyc/mdb/. </p>
 databases.  </a> </h2>
 
 <p> As documented below, conversion to LMDB introduces a number of
-failure modes that don't exist with other Postfix databases. </p>
+failure modes that don't exist with other Postfix databases.  Some
+failure modes have been eliminated on the course of time.
+The writeup below reflects the status as of of LMDB 0.9.8. </p>
+
+<!--
 
 <p> <strong>Unexpected postmap(1)/postalias(1) "database full"
 errors.  </strong></p>
 
 <dl>
 
-<!--
-
 <dt> Problem: </dt> <dd> <p> The "postmap lmdb:filename" command
 fails with an MDB_TXN_FULL error.  This problem does not exist with
 other Postfix databases. </p> </dd>
@@ -146,8 +138,6 @@ structures should share the same storage pool so that they can scale
 with the database size, and so that all "out of storage" errors are
 resolved by increasing the database size. </p> </dd>
 
--->
-
 <dt> Problem: </dt> <dd> <p> The "postmap lmdb:filename" command
 fails with an MDB_MAP_FULL error.  This problem does not exist with
 other Postfix databases. </p> </dd>
@@ -177,23 +167,25 @@ availability, because the old data still exists in the database.
 MDB_MAP_FULL error, it expands the database file size to the current
 LMDB map size limit before terminating.  </p>
 
-<p> When the postmap(1) or postalias(1) command opens an LMDB file
-larger than lmdb_map_size/3, it logs a warning and uses a larger
-size limit instead: </p>
+<p> Next, when you re-run the postmap(1) or postalias(1) command,
+it discovers that the LMDB file is larger than lmdb_map_size/3,
+logs a warning, and uses a larger LMDB map size limit instead: </p>
 
 <p> <tt> warning: <i>filename</i>.lmdb: file size 15024128 &ge;
-(lmdb map size limit 16777216)/3 -- using a larger map size limit</tt>
-</p>
+(lmdb map size limit 16777216)/3<br> warning: <i>filename</i>.lmdb:
+using map size limit 45072384</tt> </p>
 
-<p> The two steps above can be used to automate recovery and avoid
-the need for human intervention. Just repeat "postmap lmdb:filename"
-(up to some limit).  After each failure it will use a 3x larger
-size limit, and eventually the "database full" error will disappear.
-</p>
+<p> By repeating the two steps above you can automate recovery and
+avoid the need for human intervention. Just repeat "postmap
+lmdb:filename" (up to some limit).  After each failure it will use
+a 3x larger size limit, and eventually the "database full" error
+should disappear. This fails only when the disk is full or when
+the LMDB map size limit would exceed the memory address space size
+limit.  </p>
 
 <dt> Prevention: </dt> <dd> <p> Monitor your LMDB files and make
-sure that lmdb_map_size &gt; 3x the largest LMDB file size. </p>
-</dd> </dl>
+sure that in main.cf, lmdb_map_size &gt; 3x the largest LMDB file
+size. </p> </dd> </dl>
 
 <p> <strong>Unexpected Postfix daemon "database full" errors.
 </strong></p>
@@ -214,8 +206,8 @@ file larger than lmdb_map_size/3, it logs a warning and uses a
 larger size limit instead: </p>
 
 <p> <tt> warning: <i>filename</i>.lmdb: file size 15024128 &ge;
-(lmdb map size limit 16777216)/3 -- using a larger map size limit</tt>
-</p>
+(lmdb map size limit 16777216)/3 <br>warning: <i>filename</i>.lmdb:
+using map size limit 45072384</tt> </p>
 
 <p> This can be used to automate recovery and avoid the need for
 human intervention. Each time the daemon runs into a "database full"
@@ -226,14 +218,16 @@ full" error will disappear, at least for a while.  </p>
 sure that lmdb_map_size &gt; 3x the largest LMDB file size. </p>
 </dd> </dl>
 
+-->
+
 <p> <strong>Non-obvious recovery with postmap(1)/postalias(1)/tlsmgr(8)
 from a corrupted database.  </strong></p>
 
 <dl>
 
 <dt> Problem: </dt> <dd> <p> You cannot rebuild a corrupted LMDB
-database simply by running postmap(1) or postalias(1), or by waiting
-until the tlsmgr(8) daemon restarts automatically.  This problem
+database simply by re-running postmap(1) or postalias(1), or by
+waiting until the tlsmgr(8) daemon restarts.  This problem
 does not exist with other Postfix databases.  </p> </dd>
 
 <dt> Background: </dt> <dd> <p> The Postfix LMDB database client
@@ -245,9 +239,9 @@ That is obviously not possible with a corrupted database file. </p>
 <dt> Impact: </dt> <dd> <p> Postfix does not process mail until
 someone fixes the problem.  </p> </dd>
 
-<dt> Recovery: </dt> <dd> <p> First delete the ".lmdb" file by hand,
-then rebuild the file with the postmap(1) or postalias(1) command,
-or wait until the tlsmgr(8) daemon restarts automatically.  </p>
+<dt> Recovery: </dt> <dd> <p> First delete the ".lmdb" file by hand.
+Then, rebuild the file with the postmap(1) or postalias(1) command,
+or wait until the tlsmgr(8) daemon restarts.  </p>
 </dd>
 
 <dt> Prevention: </dt> <dd> 
index 49e7fb7cf62e0fe5fa3c03d6c6d15380469c0899..b9104e2a9ad463ef9961918ef07c41925642f0a9 100644 (file)
@@ -1450,7 +1450,8 @@ restriction above will reject the sender address in the MAIL FROM
 command if <code>smtpd_sender_login_maps</code> does not specify
 the SMTP client's login name as an owner of that address. </p>
 
-<p> See also <code>reject_authenticated_sender_login_mismatch</code> and
+<p> See also <code>reject_authenticated_sender_login_mismatch</code>,
+<code>reject_known_sender_login_mismatch</code>, and
 <code>reject_unauthenticated_sender_login_mismatch</code> for additional
 control over the SASL login name and the envelope sender. </p>
 
index 00f84918763230b0cdc8cdcdac9ace1a73b8e45d..77caf4886565e879e3bca536be601de03097ac96 100644 (file)
@@ -33,6 +33,8 @@ and for earlier Postfix versions that don't.  </p>
 
 <li><a href="#overload"> Symptoms of Postfix SMTP server overload </a> 
 
+<li><a href="#adapt"> Automatic stress-adaptive behavior </a>
+
 <li><a href="#concurrency"> Service more SMTP clients at the same time </a> 
 
 <li><a href="#time"> Spend less time per SMTP client </a>
@@ -41,8 +43,6 @@ and for earlier Postfix versions that don't.  </p>
 
 <li><a href="#legacy"> Temporary measures for older Postfix releases </a>
 
-<li><a href="#adapt"> Automatic stress-adaptive behavior </a>
-
 <li><a href="#feature"> Detecting support for stress-adaptive behavior </a>
 
 <li><a href="#forcing"> Forcing stress-adaptive behavior on or off </a>
@@ -109,6 +109,9 @@ Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
 Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
  condition, increase the process count in master.cf or reduce the
  service time per client
+Oct  3 20:39:27 spike postfix/master[28905]: warning: see
+  <a href="http://www.postfix.org/STRESS_README.html">http://www.postfix.org/STRESS_README.html</a> for examples of
+  stress-adapting configuration settings
 </pre>
 
 </ul>
@@ -118,8 +121,116 @@ Postfix SMTP server overload is not necessarily lost. It should
 still arrive once the situation returns to normal, as long as the
 overload condition is temporary.  </p>
 
+<h2><a name="adapt"> Automatic stress-adaptive behavior </a></h2>
+
+<p> Postfix version 2.5 introduces automatic stress-adaptive behavior.
+It works as follows. When a "public" network service such as the
+SMTP server runs into an "all server ports are busy" condition, the
+Postfix master(8) daemon logs a warning, restarts the service
+(without interrupting existing network sessions), and runs the
+service with "-o stress=yes" on the server process command line:
+</p>
+
+<blockquote>
+<pre>
+80821  ??  S      0:00.24 smtpd -n smtp -t inet -u -c -o stress=yes
+</pre>
+</blockquote>
+
+<p> Normally, the Postfix master(8) daemon runs such a service with
+"-o stress=" on the command line (i.e.  with an empty parameter
+value):  </p>
+
+<blockquote>
+<pre>
+83326  ??  S      0:00.28 smtpd -n smtp -t inet -u -c -o stress=
+</pre>
+</blockquote>
+
+<p> Services that have local access only never have "-o stress"
+parameters on the command line. This includes services internal to
+Postfix such as the queue manager, and services that listen on a
+loopback interface only, such as after-filter SMTP services.  </p>
+
+<p> The "stress" parameter value is the key to making main.cf
+parameter settings stress adaptive. The following settings are the
+default with Postfix 2.6 and later. </p>
+
+<blockquote>
+<pre>
+1 smtpd_timeout = ${stress?10}${stress:300}s
+2 smtpd_hard_error_limit = ${stress?1}${stress:20}
+3 smtpd_junk_command_limit = ${stress?1}${stress:100}
+4 # Parameters added after Postfix 2.6:
+5 smtpd_per_record_deadline = ${stress?yes}${stress:no}
+6 smtpd_starttls_timeout = ${stress?10}${stress:300}s
+7 address_verify_poll_count = ${stress?1}${stress:3}
+</pre>
+</blockquote>
+
+<p> Translation: <p>
+
+<ul>
+
+<li> <p> Line 1: under conditions of stress, use an smtpd_timeout
+value of 10 seconds instead of the default 300 seconds. Experience
+on the postfix-users list from a variety of sysadmins shows that
+reducing the "normal" smtpd_timeout to 60s is unlikely to affect
+legitimate clients. However, it is unlikely to become the Postfix
+default because it's not RFC compliant. Setting smtpd_timeout to
+10s or even 5s under stress will still allow most
+legitimate clients to connect and send mail, but may delay mail
+from some clients. No mail should be lost, as long as this measure
+is used only temporarily. </p>
+
+<li> <p> Line 2: under conditions of stress, use an smtpd_hard_error_limit
+of 1 instead of the default 20. This helps by disconnecting clients
+after a single error, giving other clients a chance to connect.
+However, this may cause significant delays with legitimate mail,
+such as a mailing list that contains a few no-longer-active user
+names that didn't bother to unsubscribe. No mail should be lost,
+as long as this measure is used only temporarily. </p>
+
+<li> <p> Line 3: under conditions of stress, use an
+smtpd_junk_command_limit of 1 instead of the default 100. This
+prevents clients from keeping connections open by repeatedly
+sending HELO, EHLO, NOOP, RSET, VRFY or ETRN commands. </p>
+
+<li> <p> Line 5: under conditions of stress, change the behavior
+of smtpd_timeout and smtpd_starttls_timeout, from a time limit per
+read or write system call, to a time limit to send or receive a
+complete record (an SMTP command line, SMTP response line, SMTP
+message content line, or TLS protocol message). </p>
+
+<li> <p> Line 6: under conditions of stress, reduce the time limit
+for TLS protocol handshake messages to 10 seconds, from the default
+value of 300 seconds. See also the smtpd_timeout discussion above.
+</p>
+
+<li> <p> Line 7: under conditions of stress, do not wait up to 6
+seconds for the completion of an address verification probe. If the
+result is not already in the address verification cache, reply
+immediately with $unverified_recipient_tempfail_action or
+$unverified_sender_tempfail_action. No mail should be lost, as long
+as this measure is used only temporarily.  </p>
+
+</ul>
+
+<p> The syntax of ${name?value} and ${name:value} is explained at
+the beginning of the postconf(5) manual page. </p>
+
+<p> NOTE: Please keep in mind that the stress-adaptive feature is
+a fairly desperate measure to keep <b>some</b> legitimate mail
+flowing under overload conditions.  If a site is reaching the SMTP
+server process limit when there isn't an attack or bot flood
+occurring, then either the process limit needs to be raised or more
+hardware needs to be added.  </p>
+
 <h2><a name="concurrency"> Service more SMTP clients at the same time </a> </h2>
 
+<p> This section and the ones that follow discuss permanent measures
+against mail server overload.  </p>
+
 <p> One measure to avoid the "all server processes busy" condition
 is to service more SMTP clients simultaneously. For this you need
 to increase the number of Postfix SMTP server processes. This will
@@ -349,95 +460,6 @@ repeatedly sending NOOP or RSET commands. </p>
 as these measures are used only temporarily. The next section of
 this document introduces a way to automate this process. </p>
 
-<h2><a name="adapt"> Automatic stress-adaptive behavior </a></h2>
-
-<p> Postfix version 2.5 introduces automatic stress-adaptive behavior.
-This is also available as a source code patch for Postfix versions
-2.4 and 2.3 from the mirrors listed at
-http://www.postfix.org/download.html.  </p>
-
-<p> It works as follows. When a "public" network service such as
-the SMTP server runs into an "all server ports are busy" condition,
-the Postfix master(8) daemon logs a warning, restarts the service
-(without interrupting existing network sessions), and runs the
-service with "-o stress=yes" on the server process command line:
-</p>
-
-<blockquote>
-<pre>
-80821  ??  S      0:00.24 smtpd -n smtp -t inet -u -c -o stress=yes
-</pre>
-</blockquote>
-
-<p> Normally, the Postfix master(8) daemon runs such a service with
-"-o stress=" on the command line (i.e.  with an empty parameter
-value):  </p>
-
-<blockquote>
-<pre>
-83326  ??  S      0:00.28 smtpd -n smtp -t inet -u -c -o stress=
-</pre>
-</blockquote>
-
-<p> Services that have local access only never have "-o stress"
-parameters on the command line. This includes services internal to
-Postfix such as the queue manager, and services that listen on a
-loopback interface only, such as after-filter SMTP services.  </p>
-
-<p> The "stress" parameter value is the key to making main.cf
-parameter settings stress adaptive. The following settings are the
-default with Postfix 2.6 and later. With earlier Postfix versions
-that have stress-adaptive support, append the lines below to the
-main.cf file and issue a "postfix reload" command: </p>
-
-<blockquote>
-<pre>
-1 smtpd_timeout = ${stress?10}${stress:300}s
-2 smtpd_hard_error_limit = ${stress?1}${stress:20}
-3 smtpd_junk_command_limit = ${stress?1}${stress:100}
-</pre>
-</blockquote>
-
-<p> Translation: <p>
-
-<ul>
-
-<li> <p> Line 1: under conditions of stress, use an smtpd_timeout
-value of 10 seconds instead of the default 300 seconds. Experience
-on the postfix-users list from a variety of sysadmins shows that
-reducing the "normal" smtpd_timeout to 60s is unlikely to affect
-legitimate clients. However, it is unlikely to become the Postfix
-default because it's not RFC compliant. Setting smtpd_timeout to
-10s (line 2 below) or even 5s under stress will still allow most
-legitimate clients to connect and send mail, but may delay mail
-from some clients. No mail should be lost, as long as this measure
-is used only temporarily. </p>
-
-<li> <p> Line 2: under conditions of stress, use an smtpd_hard_error_limit
-of 1 instead of the default 20. This helps by disconnecting clients
-after a single error, giving other clients a chance to connect.
-However, this may cause significant delays with legitimate mail,
-such as a mailing list that contains a few no-longer-active user
-names that didn't bother to unsubscribe. No mail should be lost,
-as long as this measure is used only temporarily. </p>
-
-<li> <p> Line 3: under conditions of stress, use an
-smtpd_junk_command_limit of 1 instead of the default 100. This
-prevents clients from keeping idle connections open by repeatedly
-sending NOOP or RSET commands. </p>
-
-</ul>
-
-<p> The syntax of ${name?value} and ${name:value} is explained at
-the beginning of the postconf(5) manual page. </p>
-
-<p> NOTE: Please keep in mind that the stress-adaptive feature is
-a fairly desperate measure to keep <b>some</b> legitimate mail
-flowing under overload conditions.  If a site is reaching the SMTP
-server process limit when there isn't an attack or bot flood
-occurring, then either the process limit needs to be raised or more
-hardware needs to be added.  </p>
-
 <h2><a name="feature"> Detecting support for stress-adaptive behavior </a></h2>
 
 <p> To find out if your Postfix installation supports stress-adaptive
index 666aa28aba617a3657c85b7863f678c465a73e3f..7b0e564f17ad9143a9e0619d227da93f9d3e30f5 100644 (file)
 #      \fBdemand\fR value of \fBTLS_REQCERT\fR in LDAP client configuration
 #      files.
 # .sp
-#      The "try" and "never" values of \fBTLS_REQCERT\fR have no equivalents
+#      The "try" and "allow" values of \fBTLS_REQCERT\fR have no equivalents
 #      here. They are not available with OpenLDAP 2.0, and in any case have
 #      questionable security properties. Either you want TLS verified LDAP
 #      connections, or you don't.
index c4b6c53a187e6585a2f1fb90a9d8411b5f633bbd..ef2e709c65d26e8ac782ddfbf4181498577ccd53 100644 (file)
@@ -2837,11 +2837,11 @@ The default time unit is d (days).
 Specify 0 when mail delivery should be tried only once.
 </p>
 
-%PARAM lmdb_map_size 10485760
+%PARAM lmdb_map_size 16777216
 
 <p>
-The per-table size limit for programs that create OpenLDAP LMDB
-tables.  Specify a byte count.
+The initial OpenLDAP LMDB database size limit in bytes.  Each time
+a database becomes full, its size limit is doubled.
 </p>
 
 <p>
@@ -6292,6 +6292,12 @@ feature is available in Postfix 2.1 and later.  </dd>
 authenticated clients only. This feature is available in
 Postfix version 2.1 and later. </dd>
 
+<dt><b><a name="reject_known_sender_login_mismatch">reject_known_sender_login_mismatch</a></b></dt>
+
+<dd>Apply the reject_sender_login_mismatch restriction only to MAIL
+FROM addresses that are known in $smtpd_sender_login_maps.  This
+feature is available in Postfix version 2.11 and later. </dd>
+
 <dt><b><a name="reject_non_fqdn_sender">reject_non_fqdn_sender</a></b></dt>
 
 <dd>Reject the request when the MAIL FROM address is not in
@@ -14754,7 +14760,8 @@ service performs plaintext &lt;=&gt; TLS ciphertext conversion. <p>
 
 %PARAM smtpd_per_record_deadline normal: no, overload: yes
 
-<p> Change the behavior of the smtpd_timeout time limit, from a
+<p> Change the behavior of the smtpd_timeout and smtpd_starttls_timeout
+time limits, from a
 time limit per read or write system call, to a time limit to send
 or receive a complete record (an SMTP command line, SMTP response
 line, SMTP message content line, or TLS protocol message).  This
index 93d2c356940e4deaaf292cd85ce3f15c277d90c6..871fcc50db83abb67405d8f2ddc1329f6cd962d8 100644 (file)
@@ -1591,6 +1591,8 @@ extern char *var_smtpd_snd_auth_maps;
 #define REJECT_SENDER_LOGIN_MISMATCH   "reject_sender_login_mismatch"
 #define REJECT_AUTH_SENDER_LOGIN_MISMATCH \
                                "reject_authenticated_sender_login_mismatch"
+#define REJECT_KNOWN_SENDER_LOGIN_MISMATCH \
+                               "reject_known_sender_login_mismatch"
 #define REJECT_UNAUTH_SENDER_LOGIN_MISMATCH \
                                "reject_unauthenticated_sender_login_mismatch"
 
index 2dc2e54da233dd3410b4393b29e7de607953833c..1ee311c13094ae4751d21d1a9186a167ade2b0ff 100644 (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      "20130825"
+#define MAIL_RELEASE_DATE      "20130927"
 #define MAIL_VERSION_NUMBER    "2.11"
 
 #ifdef SNAPSHOT
index 750b263c8e8b1b47803c2b4c9a4dc037ff164d30..430c156417d989e1744cd5d1b14812d9fd57b8a7 100644 (file)
 static void postalias(char *map_type, char *path_name, int postalias_flags,
                              int open_flags, int dict_flags)
 {
-    VSTREAM *source_fp;
+    VSTREAM *NOCLOBBER source_fp;
     VSTRING *line_buffer;
     MKMAP  *mkmap;
     int     lineno;
@@ -286,10 +286,10 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
        /* Create database. */
        if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
            msg_fatal("can't create maps via the proxy service");
+       dict_flags |= DICT_FLAG_BULK_UPDATE;
        if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0)
            msg_fatal("open %s: %m", path_name);
     }
-    dict_flags |= DICT_FLAG_BULK_UPDATE;
     if (fstat(vstream_fileno(source_fp), &st) < 0)
        msg_fatal("fstat %s: %m", path_name);
 
@@ -322,72 +322,85 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
        umask(saved_mask);
 
     /*
-     * Add records to the database.
+     * Trap "exceptions" so that we can restart a bulk-mode update after a
+     * recoverable error.
      */
-    lineno = 0;
-    while (readlline(line_buffer, source_fp, &lineno)) {
+    for (;;) {
+       if (dict_isjmp(mkmap->dict) != 0
+           && dict_setjmp(mkmap->dict) != 0
+           && vstream_fseek(source_fp, SEEK_SET, 0) < 0)
+           msg_fatal("seek %s: %m", VSTREAM_PATH(source_fp));
 
        /*
-        * Tokenize the input, so that we do the right thing when a quoted
-        * localpart contains special characters such as "@", ":" and so on.
+        * Add records to the database.
         */
-       if ((tok_list = tok822_scan(STR(line_buffer), (TOK822 **) 0)) == 0)
-           continue;
+       lineno = 0;
+       while (readlline(line_buffer, source_fp, &lineno)) {
+
+           /*
+            * Tokenize the input, so that we do the right thing when a
+            * quoted localpart contains special characters such as "@", ":"
+            * and so on.
+            */
+           if ((tok_list = tok822_scan(STR(line_buffer), (TOK822 **) 0)) == 0)
+               continue;
+
+           /*
+            * Enforce the key:value format. Disallow missing keys,
+            * multi-address keys, or missing values. In order to specify an
+            * empty string or value, enclose it in double quotes.
+            */
+           if ((colon = tok822_find_type(tok_list, ':')) == 0
+               || colon->prev == 0 || colon->next == 0
+               || tok822_rfind_type(colon, ',')) {
+               msg_warn("%s, line %d: need name:value pair",
+                        VSTREAM_PATH(source_fp), lineno);
+               tok822_free_tree(tok_list);
+               continue;
+           }
 
-       /*
-        * Enforce the key:value format. Disallow missing keys, multi-address
-        * keys, or missing values. In order to specify an empty string or
-        * value, enclose it in double quotes.
-        */
-       if ((colon = tok822_find_type(tok_list, ':')) == 0
-           || colon->prev == 0 || colon->next == 0
-           || tok822_rfind_type(colon, ',')) {
-           msg_warn("%s, line %d: need name:value pair",
-                    VSTREAM_PATH(source_fp), lineno);
-           tok822_free_tree(tok_list);
-           continue;
-       }
+           /*
+            * Key must be local. XXX We should use the Postfix rewriting and
+            * resolving services to handle all address forms correctly.
+            * However, we can't count on the mail system being up when the
+            * alias database is being built, so we're guessing a bit.
+            */
+           if (tok822_rfind_type(colon, '@') || tok822_rfind_type(colon, '%')) {
+               msg_warn("%s, line %d: name must be local",
+                        VSTREAM_PATH(source_fp), lineno);
+               tok822_free_tree(tok_list);
+               continue;
+           }
 
-       /*
-        * Key must be local. XXX We should use the Postfix rewriting and
-        * resolving services to handle all address forms correctly. However,
-        * we can't count on the mail system being up when the alias database
-        * is being built, so we're guessing a bit.
-        */
-       if (tok822_rfind_type(colon, '@') || tok822_rfind_type(colon, '%')) {
-           msg_warn("%s, line %d: name must be local",
-                    VSTREAM_PATH(source_fp), lineno);
-           tok822_free_tree(tok_list);
-           continue;
+           /*
+            * Split the input into key and value parts, and convert from
+            * token representation back to string representation. Convert
+            * the key to internal (unquoted) form, because the resolver
+            * produces addresses in internal form. Convert the value to
+            * external (quoted) form, because it will have to be re-parsed
+            * upon lookup. Discard the token representation when done.
+            */
+           key_list = tok_list;
+           tok_list = 0;
+           value_list = tok822_cut_after(colon);
+           tok822_unlink(colon);
+           tok822_free(colon);
+
+           tok822_internalize(key_buffer, key_list, TOK822_STR_DEFL);
+           tok822_free_tree(key_list);
+
+           tok822_externalize(value_buffer, value_list, TOK822_STR_DEFL);
+           tok822_free_tree(value_list);
+
+           /*
+            * Store the value under a case-insensitive key.
+            */
+           mkmap_append(mkmap, STR(key_buffer), STR(value_buffer));
+           if (mkmap->dict->error)
+               msg_fatal("table %s:%s: write error: %m",
+                         mkmap->dict->type, mkmap->dict->name);
        }
-
-       /*
-        * Split the input into key and value parts, and convert from token
-        * representation back to string representation. Convert the key to
-        * internal (unquoted) form, because the resolver produces addresses
-        * in internal form. Convert the value to external (quoted) form,
-        * because it will have to be re-parsed upon lookup. Discard the
-        * token representation when done.
-        */
-       key_list = tok_list;
-       tok_list = 0;
-       value_list = tok822_cut_after(colon);
-       tok822_unlink(colon);
-       tok822_free(colon);
-
-       tok822_internalize(key_buffer, key_list, TOK822_STR_DEFL);
-       tok822_free_tree(key_list);
-
-       tok822_externalize(value_buffer, value_list, TOK822_STR_DEFL);
-       tok822_free_tree(value_list);
-
-       /*
-        * Store the value under a case-insensitive key.
-        */
-       mkmap_append(mkmap, STR(key_buffer), STR(value_buffer));
-       if (mkmap->dict->error)
-           msg_fatal("table %s:%s: write error: %m",
-                     mkmap->dict->type, mkmap->dict->name);
+       break;
     }
 
     /*
index 5d891aa6df1a5a495362da1108d0bfbd20298bc7..e10ac166976467a1993e02631cc1e18c8ee4d7d4 100644 (file)
@@ -328,7 +328,7 @@ typedef struct {
 static void postmap(char *map_type, char *path_name, int postmap_flags,
                            int open_flags, int dict_flags)
 {
-    VSTREAM *source_fp;
+    VSTREAM *NOCLOBBER source_fp;
     VSTRING *line_buffer;
     MKMAP  *mkmap;
     int     lineno;
@@ -349,10 +349,10 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
        /* Create database. */
        if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
            msg_fatal("can't create maps via the proxy service");
+       dict_flags |= DICT_FLAG_BULK_UPDATE;
        if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0)
            msg_fatal("open %s: %m", path_name);
     }
-    dict_flags |= DICT_FLAG_BULK_UPDATE;
     if (fstat(vstream_fileno(source_fp), &st) < 0)
        msg_fatal("fstat %s: %m", path_name);
 
@@ -385,44 +385,56 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
        umask(saved_mask);
 
     /*
-     * Add records to the database.
+     * Trap "exceptions" so that we can restart a bulk-mode update after a
+     * recoverable error.
      */
-    lineno = 0;
-    while (readlline(line_buffer, source_fp, &lineno)) {
+    for (;;) {
+       if (dict_isjmp(mkmap->dict) != 0
+           && dict_setjmp(mkmap->dict) != 0
+           && vstream_fseek(source_fp, SEEK_SET, 0) < 0)
+           msg_fatal("seek %s: %m", VSTREAM_PATH(source_fp));
 
        /*
-        * Split on the first whitespace character, then trim leading and
-        * trailing whitespace from key and value.
+        * Add records to the database.
         */
-       key = STR(line_buffer);
-       value = key + strcspn(key, " \t\r\n");
-       if (*value)
-           *value++ = 0;
-       while (ISSPACE(*value))
-           value++;
-       trimblanks(key, 0)[0] = 0;
-       trimblanks(value, 0)[0] = 0;
-
-       /*
-        * Enforce the "key whitespace value" format. Disallow missing keys
-        * or missing values.
-        */
-       if (*key == 0 || *value == 0) {
-           msg_warn("%s, line %d: expected format: key whitespace value",
-                    VSTREAM_PATH(source_fp), lineno);
-           continue;
+       lineno = 0;
+       while (readlline(line_buffer, source_fp, &lineno)) {
+
+           /*
+            * Split on the first whitespace character, then trim leading and
+            * trailing whitespace from key and value.
+            */
+           key = STR(line_buffer);
+           value = key + strcspn(key, " \t\r\n");
+           if (*value)
+               *value++ = 0;
+           while (ISSPACE(*value))
+               value++;
+           trimblanks(key, 0)[0] = 0;
+           trimblanks(value, 0)[0] = 0;
+
+           /*
+            * Enforce the "key whitespace value" format. Disallow missing
+            * keys or missing values.
+            */
+           if (*key == 0 || *value == 0) {
+               msg_warn("%s, line %d: expected format: key whitespace value",
+                        VSTREAM_PATH(source_fp), lineno);
+               continue;
+           }
+           if (key[strlen(key) - 1] == ':')
+               msg_warn("%s, line %d: record is in \"key: value\" format; is this an alias file?",
+                        VSTREAM_PATH(source_fp), lineno);
+
+           /*
+            * Store the value under a case-insensitive key.
+            */
+           mkmap_append(mkmap, key, value);
+           if (mkmap->dict->error)
+               msg_fatal("table %s:%s: write error: %m",
+                         mkmap->dict->type, mkmap->dict->name);
        }
-       if (key[strlen(key) - 1] == ':')
-           msg_warn("%s, line %d: record is in \"key: value\" format; is this an alias file?",
-                    VSTREAM_PATH(source_fp), lineno);
-
-       /*
-        * Store the value under a case-insensitive key.
-        */
-       mkmap_append(mkmap, key, value);
-       if (mkmap->dict->error)
-           msg_fatal("table %s:%s: write error: %m",
-                     mkmap->dict->type, mkmap->dict->name);
+       break;
     }
 
     /*
index 9c29a3d5544c94f5cb465c5f9f4bb668d148c7e5..ecbf3da13e1c3bcc6dfa77b664be802d5e571699 100644 (file)
@@ -16,8 +16,9 @@ CFLAGS        = $(DEBUG) $(OPT) $(DEFS)
 TESTPROG=
 PROG   = postscreen
 INC_DIR = ../../include
-LIBS   = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libglobal.a \
-       ../../lib/libutil.a
+# Fake libdns dependency, for early-binding shared-library builds.
+LIBS   = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libdns.a \
+       ../../lib/libglobal.a ../../lib/libutil.a
 
 .c.o:; $(CC) $(CFLAGS) -c $*.c
 
index deff9abfabd6160a36ab9e462448bf4fa6c329c9..58ecc40d4419a20da8abfd5c7ac5f096cc6b497c 100644 (file)
 /*     A list of local \fBpostscreen\fR(8) server IP addresses where a
 /*     non-whitelisted remote SMTP client can obtain \fBpostscreen\fR(8)'s temporary
 /*     whitelist status.
-/* BEFORE-GREETING TESTS
+/* BEFORE 220 GREETING TESTS
 /* .ad
 /* .fi
 /*     These tests are executed before the remote SMTP client
 /*     Allow a remote SMTP client to skip "before" and "after 220
 /*     greeting" protocol tests, based on its combined DNSBL score as
 /*     defined with the postscreen_dnsbl_sites parameter.
-/* AFTER-GREETING TESTS
+/* AFTER 220 GREETING TESTS
 /* .ad
 /* .fi
 /*     These tests are executed after the remote SMTP client
 /*     receives the "220 servername" greeting. If a client passes
 /*     all tests during this phase, it will receive a 4XX response
-/*     to RCPT TO commands until the client hangs up. After this,
-/*     the client will be allowed to talk directly to a Postfix
-/*     SMTP server process.
+/*     to all RCPT TO commands. After the client reconnects, it
+/*     will be allowed to talk directly to a Postfix SMTP server
+/*     process.
 /* .IP "\fBpostscreen_bare_newline_action (ignore)\fR"
 /*     The action that \fBpostscreen\fR(8) takes when a remote SMTP client sends
 /*     a bare newline character, that is, a newline not preceded by carriage
index 01b4a545f2352c7a0a6d2d92bfa92ace72421b2b..7376b7b3995c795b9aa068945229b435310c322e 100644 (file)
@@ -16,9 +16,10 @@ CFLAGS       = $(DEBUG) $(OPT) $(DEFS)
 TESTPROG= smtpd_token smtpd_check
 PROG   = smtpd
 INC_DIR        = ../../include
+# Fake libdns dependency, for early-binding shared-library builds.
 LIBS   = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libdns.a \
-       ../../lib/libxsasl.a ../../lib/libmilter.a ../../lib/libglobal.a \
-       ../../lib/libutil.a
+       ../../lib/libxsasl.a ../../lib/libmilter.a ../../lib/libdns.a \
+       ../../lib/libglobal.a ../../lib/libutil.a
 
 .c.o:; $(CC) $(CFLAGS) -c $*.c
 
index a27dc701225acd7cb0ed83bdbfa49839314b2064..3b9508328707c4a51c98263bd589e958cb1e4eff 100644 (file)
@@ -3461,7 +3461,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
 
 /* reject_auth_sender_login_mismatch - logged in client must own sender address */
 
-static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sender)
+static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sender, int allow_unknown_sender)
 {
     const RESOLVE_REPLY *reply;
     const char *owners;
@@ -3470,6 +3470,9 @@ static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sen
     char   *name;
     int     found = 0;
 
+#define ALLOW_UNKNOWN_SENDER   1
+#define FORBID_UNKNOWN_SENDER  0
+
     /*
      * Reject if the client is logged in and does not own the sender address.
      */
@@ -3487,7 +3490,8 @@ static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sen
                }
            }
            myfree(saved_owners);
-       }
+       } else if (allow_unknown_sender)
+           return (SMTPD_CHECK_DUNNO);
        if (!found)
            return (smtpd_check_reject(state, MAIL_ERROR_POLICY, 553, "5.7.1",
                      "<%s>: Sender address rejected: not owned by user %s",
@@ -4017,7 +4021,21 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
 #ifdef USE_SASL_AUTH
            if (var_smtpd_sasl_enable) {
                if (state->sender && *state->sender)
-                   status = reject_auth_sender_login_mismatch(state, state->sender);
+                   status = reject_auth_sender_login_mismatch(state,
+                                     state->sender, FORBID_UNKNOWN_SENDER);
+           } else
+#endif
+               msg_warn("restriction `%s' ignored: no SASL support", name);
+       } else if (strcasecmp(name, REJECT_KNOWN_SENDER_LOGIN_MISMATCH) == 0) {
+#ifdef USE_SASL_AUTH
+           if (var_smtpd_sasl_enable) {
+               if (state->sender && *state->sender) {
+                   if (state->sasl_username)
+                       status = reject_auth_sender_login_mismatch(state,
+                                      state->sender, ALLOW_UNKNOWN_SENDER);
+                   else
+                       status = reject_unauth_sender_login_mismatch(state, state->sender);
+               }
            } else
 #endif
                msg_warn("restriction `%s' ignored: no SASL support", name);
index c40c91fe7b3a6383be4bae52489e4d07dde251fe..ced0b5404a27732cdc1a4244eb10e2e8002321ee 100644 (file)
@@ -8,8 +8,9 @@ CFLAGS  = $(DEBUG) $(OPT) $(DEFS)
 TESTPROG= 
 PROG   = tlsmgr
 INC_DIR        = ../../include
-LIBS   = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libglobal.a \
-       ../../lib/libutil.a
+# Fake libdns dependency, for early-binding shared-library builds.
+LIBS   = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libdns.a \
+       ../../lib/libglobal.a ../../lib/libutil.a
 
 .c.o:; $(CC) $(CFLAGS) -c $*.c
 
index 74323ffa5af38c0e03799f2b0648b5d082850c3d..0dacf13b8cbe0a02fffa64cfadab40f706f4bfef 100644 (file)
@@ -1833,6 +1833,8 @@ stream_trigger.o: sys_defs.h
 stream_trigger.o: trigger.h
 sys_compat.o: sys_compat.c
 sys_compat.o: sys_defs.h
+timecmp.o: timecmp.c
+timecmp.o: timecmp.h
 timed_connect.o: iostuff.h
 timed_connect.o: msg.h
 timed_connect.o: sane_connect.h
index c47c20657132fe9bfb9361133c043f8524262257..d255aac3b0ade884fba414f75860197617d996d1 100644 (file)
   * System library.
   */
 #include <fcntl.h>
+#include <setjmp.h>
+
+#ifdef NO_SIGSETJMP
+#define DICT_JMP_BUF jmp_buf
+#else
+#define DICT_JMP_BUF sigjmp_buf
+#endif
 
  /*
   * Utility library.
@@ -56,6 +63,7 @@ typedef struct DICT {
     VSTRING *fold_buf;                 /* key folding buffer */
     DICT_OWNER owner;                  /* provenance */
     int     error;                     /* last operation only */
+    DICT_JMP_BUF *jbuf;                        /* exception handling */
 } DICT;
 
 extern DICT *dict_alloc(const char *, const char *, ssize_t);
@@ -206,6 +214,31 @@ extern DICT *dict_surrogate(const char *, const char *, int, int, const char *,.
   */
 #define DICT_TYPE_NOFILE       "non-existent"
 
+ /*
+  * Duplicated from vstream(3). This should probably be abstracted out.
+  * 
+  * Exception handling. We use pointer to jmp_buf to avoid a lot of unused
+  * baggage for streams that don't need this functionality.
+  * 
+  * XXX sigsetjmp()/siglongjmp() save and restore the signal mask which can
+  * avoid surprises in code that manipulates signals, but unfortunately some
+  * systems have bugs in their implementation.
+  */
+#ifdef NO_SIGSETJMP
+#define dict_setjmp(stream)            setjmp((stream)->jbuf[0])
+#define dict_longjmp(stream, val)      longjmp((stream)->jbuf[0], (val))
+#else
+#define dict_setjmp(stream)            sigsetjmp((stream)->jbuf[0], 1)
+#define dict_longjmp(stream, val)      siglongjmp((stream)->jbuf[0], (val))
+#endif
+#define dict_isjmp(stream)             ((stream)->jbuf != 0)
+
+ /*
+  * Temporary API. If exception handling proves to be useful,
+  * dict_jmp_alloc() should be integrated into dict_alloc().
+  */
+extern void dict_jmp_alloc(DICT *);
+
 /* LICENSE
 /* .ad
 /* .fi
index a5cbd204c449cdbddad5d687cc5463c2e56e4f25..fc35dc0a8e8d378662af478f83608b767cd2b16a 100644 (file)
@@ -13,6 +13,9 @@
 /*
 /*     void    dict_free(dict)
 /*     DICT    *ptr;
+/*
+/*     void    dict_jmp_alloc(dict)
+/*     DICT    *ptr;
 /* DESCRIPTION
 /*     dict_alloc() allocates memory for a dictionary structure of
 /*     \fIsize\fR bytes, initializes all generic dictionary
@@ -35,6 +38,9 @@
 /*     It is up to the caller to dispose of any memory that was allocated
 /*     by the caller.
 /*
+/*     dict_jmp_alloc() implements preliminary support for exception
+/*     handling. This will eventually be built into dict_alloc().
+/*
 /*     Arguments:
 /* .IP dict_type
 /*     The official name for this type of dictionary, as used by
@@ -114,7 +120,7 @@ static int dict_default_lock(DICT *dict, int operation)
        return (0);
     }
 }
+
 /* dict_default_close - trap unimplemented operation */
 
 static void dict_default_close(DICT *dict)
@@ -145,6 +151,7 @@ DICT   *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size)
     dict->owner.status = DICT_OWNER_UNKNOWN;
     dict->owner.uid = ~0;
     dict->error = DICT_ERR_NONE;
+    dict->jbuf = 0;
     return dict;
 }
 
@@ -154,5 +161,20 @@ void    dict_free(DICT *dict)
 {
     myfree(dict->type);
     myfree(dict->name);
+    if (dict->jbuf)
+       myfree((char *) dict->jbuf);
     myfree((char *) dict);
 }
+
+ /*
+  * TODO: add a dict_flags() argument to dict_alloc() and handle jump buffer
+  * allocation there.
+  */
+
+/* dict_jmp_alloc - enable exception handling */
+
+void    dict_jmp_alloc(DICT *dict)
+{
+    if (dict->jbuf == 0)
+       dict->jbuf = (DICT_JMP_BUF *) mymalloc(sizeof(DICT_JMP_BUF));
+}
index e9d07458c5839142da07944cacf99c54c3cf1930..c4c206e03fb4f464ffdcb77ac6619406048fcce8 100644 (file)
 /*     int     open_flags;
 /*     int     dict_flags;
 /* DESCRIPTION
-/*     dict_lmdb_open() opens the named LMDB database and makes it available
-/*     via the generic interface described in dict_open(3).
+/*     dict_lmdb_open() opens the named LMDB database and makes
+/*     it available via the generic interface described in
+/*     dict_open(3).
 /*
-/*     The dict_lmdb_map_size variable specifies a non-default
-/*     per-table memory map size.  The map size is also the maximum
-/*     size the table can grow to, so it must be set large enough
-/*     to accomodate the largest tables in use.
-/*
-/*     As a safety measure, when Postfix opens an LMDB database
-/*     it will set the memory map size to at least 3x the ".lmdb"
-/*     file size, so that there is room for the file to grow. This
-/*     ensures that a process can recover from a "table full" error
-/*     with a simple terminate-and-restart.
-/*
-/*     As a second safety measure, when an update or delete operation
-/*     runs into an MDB_MAP_FULL error, Postfix will extend the
-/*     database file to the current ".lmdb" file size, so that the
-/*     above workaround will be triggered the next time the database
-/*     is opened.
+/*     The dict_lmdb_map_size variable specifies the initial
+/*     database memory map size.  When a map becomes full its size
+/*     is doubled, and other programs pick up the size change.
 /* DIAGNOSTICS
-/*     Fatal errors: cannot open file, file write error, out of memory.
+/*     Fatal errors: cannot open file, file write error, out of
+/*     memory.
+/* BUGS
+/*     The on-the-fly map resize operations require no concurrent
+/*     activity in the same database by other threads in the same
+/*     process.
 /* SEE ALSO
 /*     dict(3) generic dictionary manager
 /* LICENSE
 /* AUTHOR(S)
 /*     Howard Chu
 /*     Symas Corporation
+/*
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
 /*--*/
 
-#include "sys_defs.h"
+#include <sys_defs.h>
 
 #ifdef HAS_LMDB
 
 #include PATH_LMDB_H
 #else
 #include <lmdb.h>
+#endif
+
+ /*
+  * As of LMDB 0.9.8 the database size limit can be updated on-the-fly. The
+  * only limit that remains is imposed by the hardware address space. Earlier
+  * LMDB versions are not suitable for use with Postfix.
+  */
+#if MDB_VERSION_FULL < MDB_VERINT(0, 9, 8)
+#error "Build with LMDB version 0.9.8 or later"
 #endif
 
 /* Utility library. */
 
-#include "msg.h"
-#include "mymalloc.h"
-#include "htable.h"
-#include "iostuff.h"
-#include "vstring.h"
-#include "myflock.h"
-#include "stringops.h"
-#include "dict.h"
-#include "dict_lmdb.h"
-#include "warn_stat.h"
+#include <msg.h>
+#include <mymalloc.h>
+#include <htable.h>
+#include <iostuff.h>
+#include <vstring.h>
+#include <myflock.h>
+#include <stringops.h>
+#include <dict.h>
+#include <dict_lmdb.h>
+#include <warn_stat.h>
 
 /* Application-specific. */
 
@@ -84,55 +91,423 @@ typedef struct {
     MDB_dbi dbi;                       /* database handle */
     MDB_txn *txn;                      /* bulk update transaction */
     MDB_cursor *cursor;                        /* for sequence ops */
+    size_t  map_size;                  /* per-database size limit */
     VSTRING *key_buf;                  /* key buffer */
-    VSTRING *val_buf;                  /* result buffer */
+    VSTRING *val_buf;                  /* value buffer */
+    /* The following facilitate LMDB quirk workarounds. */
+    int     dict_api_retries;          /* workarounds per dict(3) call */
+    int     bulk_mode_retries;         /* workarounds per bulk transaction */
+    int     open_flags;                        /* dict(3) open flags */
+    int     env_flags;                 /* LMDB open flags */
 } DICT_LMDB;
 
+ /*
+  * The LMDB database filename suffix happens to equal our DICT_TYPE_LMDB
+  * prefix, but that doesn't mean it is kosher to use DICT_TYPE_LMDB where a
+  * suffix is needed, so we define an explicit suffix here.
+  */
+#define DICT_LMDB_SUFFIX       "lmdb"
+
+ /*
+  * Make a safe string copy that is guaranteed to be null-terminated.
+  */
 #define SCOPY(buf, data, size) \
     vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size))
 
-size_t  dict_lmdb_map_size = (10 * 1024 * 1024);       /* 10MB default mmap
-                                                        * size */
+ /*
+  * Postfix writers recover from a "map full" error by increasing the memory
+  * map size with a factor DICT_LMDB_SIZE_INCR (up to some limit) and
+  * retrying the transaction.
+  * 
+  * Each dict(3) API call is retried no more than a few times. For bulk-mode
+  * transactions the number of retries is proportional to the size of the
+  * address space.
+  */
+#ifndef SSIZE_T_MAX                    /* The maximum map size */
+#define SSIZE_T_MAX __MAXINT__(ssize_t)        /* XXX Assumes two's complement */
+#endif
+
+#define DICT_LMDB_SIZE_INCR    2       /* Increase size by 1 bit on retry */
+#define DICT_LMDB_SIZE_MAX     SSIZE_T_MAX
+
+#define DICT_LMDB_API_RETRY_LIMIT 2    /* Retries per dict(3) API call */
+#define DICT_LMDB_BULK_RETRY_LIMIT \
+       (2 * sizeof(size_t) * CHAR_BIT) /* Retries per bulk-mode transaction */
+
+ /*
+  * XXX Should dict_lmdb_max_readers be configurable? Is this a per-database
+  * property? Per-process? Does it need to be the same for all processes?
+  */
+size_t  dict_lmdb_map_size = 8192;     /* Minimum size without SIGSEGV */
 unsigned int dict_lmdb_max_readers = 216;      /* 200 postfix processes,
                                                 * plus some extra */
 
+/* #define msg_verbose 1 */
+
  /*
-  * Out-of-space safety net. When an update or delete operation fails with
-  * MDB_MAP_FULL, extend the database file size so that the next
-  * dict_lmdb_open() call will force a 3x over-allocation.
+  * The purpose of the error-recovering functions below is to hide LMDB
+  * quirks (MAP_FULL, MAP_CHANGED), so that the dict(3) API routines can
+  * pretend that those quirks don't exist, and focus on their own job.
   * 
-  * XXX This strategy assumes that a bogus file size will not affect LMDB
-  * operation. In private communication on August 18, 2013, Howard Chu
-  * confirmed this as follows: "It will have no effect. LMDB internally
-  * accounts for the last used page#, the filesystem's notion of filesize
-  * isn't used for any purpose."
+  * - To recover from a single-transaction LMDB error, each wrapper function
+  * uses tail recursion instead of goto. Since LMDB errors are rare, code
+  * clarity is more important than speed.
   * 
-  * We make no assumptions about which LMDB operations may fail with
-  * MDB_MAP_FULL. Instead we wrap all LMDB operations inside a Postfix
-  * function that may change a database.
+  * - To recover from a bulk-mode transaction LMDB error, the error-recovery
+  * code jumps back into the caller to some pre-arranged point (the closest
+  * thing that C has to exception handling). With postmap, this means that
+  * bulk-mode LMDB error recovery is limited to input that is seekable.
   */
-#define DICT_LMDB_WRAPPER(dict, status, operation) \
-    ((status = operation) == MDB_MAP_FULL ? \
-       (dict_lmdb_grow(dict), status) : status)
 
-/* dict_lmdb_grow - grow the DB file if the last txn failed to grow it */
+/* dict_lmdb_prepare - LMDB-specific (re)initialization before actual access */
 
-static void dict_lmdb_grow(DICT *dict)
+static void dict_lmdb_prepare(DICT_LMDB *dict_lmdb)
 {
-    struct stat st;
-    char   *mdb_path = concatenate(dict->name, "." DICT_TYPE_LMDB, (char *) 0);
+    int     status;
 
     /*
-     * After MDB_MAP_FULL error, expand the file size to trigger the 3x size
-     * limit workaround on the next open() attempt.
+     * This is called before accessing the database, or after recovery from
+     * an LMDB error. dict_lmdb->txn is either the database open()
+     * transaction or a freshly-created bulk-mode transaction.
+     * 
+     * - With O_TRUNC we make a "drop" request before populating the database.
+     * 
+     * - With DICT_FLAG_BULK_UPDATE we commit a bulk-mode transaction when the
+     * database is closed.
      */
-    if (stat(mdb_path, &st) == 0 && st.st_size < dict_lmdb_map_size
-       && truncate(mdb_path, dict_lmdb_map_size) < 0)
-       msg_warn("dict_lmdb_grow: cannot grow database file %s:%s: %m",
-                dict->type, dict->name);
-    myfree(mdb_path);
+    if (dict_lmdb->open_flags & O_TRUNC) {
+       if ((status = mdb_drop(dict_lmdb->txn, dict_lmdb->dbi, 0)) != 0)
+           msg_fatal("truncate %s:%s: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
+       if ((dict_lmdb->dict.flags & DICT_FLAG_BULK_UPDATE) == 0) {
+           if ((status = mdb_txn_commit(dict_lmdb->txn)))
+               msg_fatal("truncate %s:%s: %s",
+                         dict_lmdb->dict.type, dict_lmdb->dict.name,
+                         mdb_strerror(status));
+           dict_lmdb->txn = NULL;
+       }
+    } else if ((dict_lmdb->env_flags & MDB_RDONLY) != 0
+              || (dict_lmdb->dict.flags & DICT_FLAG_BULK_UPDATE) == 0) {
+       mdb_txn_abort(dict_lmdb->txn);
+       dict_lmdb->txn = NULL;
+    }
+}
+
+/* dict_lmdb_recover - recover from LMDB errors */
+
+static int dict_lmdb_recover(DICT_LMDB *dict_lmdb, int status)
+{
+    const char *myname = "dict_lmdb_recover";
+    MDB_envinfo info;
+
+    /*
+     * Limit the number of recovery attempts per dict(3) API request.
+     */
+    if ((dict_lmdb->dict_api_retries += 1) > DICT_LMDB_API_RETRY_LIMIT) {
+       if (msg_verbose)
+           msg_info("%s: %s:%s too many recovery attempts %d",
+                    myname, dict_lmdb->dict.type, dict_lmdb->dict.name,
+                    dict_lmdb->dict_api_retries);
+       return (status);
+    }
+
+    /*
+     * If we can recover from the error, we clear the error condition and the
+     * caller should retry the failed operation immediately. Otherwise, the
+     * caller should terminate with a fatal run-time error and the program
+     * should be re-run later.
+     * 
+     * dict_lmdb->txn is either null (non-bulk transaction error), or an aborted
+     * bulk-mode transaction. If we want to make this wrapper layer suitable
+     * for general use, then the bulk/non-bulk distinction should be made
+     * less specific to Postfix.
+     */
+    switch (status) {
+
+       /*
+        * As of LMDB 0.9.8 when a non-bulk update runs into a "map full"
+        * error, we can resize the environment's memory map and clear the
+        * error condition. The caller should retry immediately.
+        */
+    case MDB_MAP_FULL:
+       /* Can we increase the memory map? Give up if we can't. */
+       if (dict_lmdb->map_size < DICT_LMDB_SIZE_MAX / DICT_LMDB_SIZE_INCR) {
+           dict_lmdb->map_size = dict_lmdb->map_size * DICT_LMDB_SIZE_INCR;
+       } else if (dict_lmdb->map_size < DICT_LMDB_SIZE_MAX) {
+           dict_lmdb->map_size = DICT_LMDB_SIZE_MAX;
+       } else {
+           /* Sorry, but we are already maxed out. */
+           break;
+       }
+       /* Resize the memory map.  */
+       if (msg_verbose)
+           msg_info("updating database %s:%s size limit to %lu",
+                    dict_lmdb->dict.type, dict_lmdb->dict.name,
+                    (unsigned long) dict_lmdb->map_size);
+       if ((status = mdb_env_set_mapsize(dict_lmdb->env,
+                                         dict_lmdb->map_size)) != 0)
+           msg_fatal("env_set_mapsize %s:%s to %lu: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     (unsigned long) dict_lmdb->map_size,
+                     mdb_strerror(status));
+       break;
+
+       /*
+        * When a writer resizes the database, read-only applications must
+        * increase their LMDB memory map size limit, too. Otherwise, they
+        * won't be able to read a table after it grows.
+        * 
+        * As of LMDB 0.9.8 we can import the new memory map size limit into the
+        * database environment by calling mdb_env_set_mapsize() with a zero
+        * size argument. Then we extract the map size limit for later use.
+        * The caller should retry immediately.
+        */
+    case MDB_MAP_RESIZED:
+       if ((status = mdb_env_set_mapsize(dict_lmdb->env, 0)) != 0)
+           msg_fatal("env_set_mapsize %s:%s to 0: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
+       /* Do not panic. Maps may shrink after bulk update. */
+       mdb_env_info(dict_lmdb->env, &info);
+       dict_lmdb->map_size = info.me_mapsize;
+       if (msg_verbose)
+           msg_info("importing database %s:%s new size limit %lu",
+                    dict_lmdb->dict.type, dict_lmdb->dict.name,
+                    (unsigned long) dict_lmdb->map_size);
+       break;
+
+       /*
+        * We can't solve this problem. The application should terminate with
+        * a fatal run-time error and the program should be re-run later.
+        */
+    default:
+       break;
+    }
+
+    /*
+     * If a bulk-mode transaction error is recoverable, build a new bulk-mode
+     * transaction from scratch, by making a long jump back into the caller
+     * at some pre-arranged point.
+     */
+    if (dict_lmdb->txn != 0 && status == 0
+     && (dict_lmdb->bulk_mode_retries += 1) <= DICT_LMDB_BULK_RETRY_LIMIT) {
+       status = mdb_txn_begin(dict_lmdb->env, NULL,
+                              dict_lmdb->env_flags & MDB_RDONLY,
+                              &dict_lmdb->txn);
+       if (status != 0)
+           msg_fatal("txn_begin %s:%s: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
+       dict_lmdb_prepare(dict_lmdb);
+       dict_longjmp(&dict_lmdb->dict, 1);
+    }
+    return (status);
+}
+
+/* dict_lmdb_txn_begin - mdb_txn_begin() wrapper with LMDB error recovery */
+
+static void dict_lmdb_txn_begin(DICT_LMDB *dict_lmdb, int rdonly, MDB_txn **txn)
+{
+    int     status;
+
+    if ((status = mdb_txn_begin(dict_lmdb->env, NULL, rdonly, txn)) != 0) {
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0) {
+           dict_lmdb_txn_begin(dict_lmdb, rdonly, txn);
+           return;
+       }
+       msg_fatal("%s:%s: error starting %s transaction: %s",
+                 dict_lmdb->dict.type, dict_lmdb->dict.name,
+                 rdonly ? "read" : "write", mdb_strerror(status));
+    }
+}
+
+/* dict_lmdb_get - mdb_get() wrapper with LMDB error recovery */
+
+static int dict_lmdb_get(DICT_LMDB *dict_lmdb, MDB_val *mdb_key,
+                                MDB_val *mdb_value)
+{
+    MDB_txn *txn;
+    int     status;
+
+    /*
+     * Start a read transaction if there's no bulk-mode txn.
+     */
+    if (dict_lmdb->txn)
+       txn = dict_lmdb->txn;
+    else
+       dict_lmdb_txn_begin(dict_lmdb, MDB_RDONLY, &txn);
+
+    /*
+     * Do the lookup.
+     */
+    if ((status = mdb_get(txn, dict_lmdb->dbi, mdb_key, mdb_value)) != 0
+       && status != MDB_NOTFOUND) {
+       mdb_txn_abort(txn);
+       if (dict_lmdb->txn == 0)
+           txn = 0;
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+           return (dict_lmdb_get(dict_lmdb, mdb_key, mdb_value));
+    }
+
+    /*
+     * Close the read txn if it's not the bulk-mode txn.
+     */
+    if (txn && dict_lmdb->txn == 0)
+       mdb_txn_abort(txn);
+
+    return (status);
+}
+
+/* dict_lmdb_put - mdb_put() wrapper with LMDB error recovery */
+
+static int dict_lmdb_put(DICT_LMDB *dict_lmdb, MDB_val *mdb_key,
+                                MDB_val *mdb_value, int flags)
+{
+    MDB_txn *txn;
+    int     status;
+
+    /*
+     * Start a write transaction if there's no bulk-mode txn.
+     */
+    if (dict_lmdb->txn)
+       txn = dict_lmdb->txn;
+    else
+       dict_lmdb_txn_begin(dict_lmdb, 0, &txn);
+
+    /*
+     * Do the update.
+     */
+    if ((status = mdb_put(txn, dict_lmdb->dbi, mdb_key, mdb_value, flags)) != 0
+       && status != MDB_KEYEXIST) {
+       mdb_txn_abort(txn);
+       if (dict_lmdb->txn == 0)
+           txn = 0;
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+           return (dict_lmdb_put(dict_lmdb, mdb_key, mdb_value, flags));
+    }
+
+    /*
+     * Commit the transaction if it's not the bulk-mode txn.
+     */
+    if (txn && dict_lmdb->txn == 0 && (status = mdb_txn_commit(txn)) != 0) {
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+           return (dict_lmdb_put(dict_lmdb, mdb_key, mdb_value, flags));
+       msg_fatal("error committing database %s:%s: %s",
+                 dict_lmdb->dict.type, dict_lmdb->dict.name,
+                 mdb_strerror(status));
+    }
+    return (status);
 }
 
+/* dict_lmdb_del - mdb_del() wrapper with LMDB error recovery */
+
+static int dict_lmdb_del(DICT_LMDB *dict_lmdb, MDB_val *mdb_key)
+{
+    MDB_txn *txn;
+    int     status;
+
+    /*
+     * Start a write transaction if there's no bulk-mode txn.
+     */
+    if (dict_lmdb->txn)
+       txn = dict_lmdb->txn;
+    else
+       dict_lmdb_txn_begin(dict_lmdb, 0, &txn);
+
+    /*
+     * Do the update.
+     */
+    if ((status = mdb_del(txn, dict_lmdb->dbi, mdb_key, NULL)) != 0
+       && status != MDB_NOTFOUND) {
+       mdb_txn_abort(txn);
+       if (dict_lmdb->txn == 0)
+           txn = 0;
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+           return (dict_lmdb_del(dict_lmdb, mdb_key));
+    }
+
+    /*
+     * Commit the transaction if it's not the bulk-mode txn.
+     */
+    if (txn && dict_lmdb->txn == 0 && (status = mdb_txn_commit(txn)) != 0) {
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+           return (dict_lmdb_del(dict_lmdb, mdb_key));
+       msg_fatal("error committing database %s:%s: %s",
+                 dict_lmdb->dict.type, dict_lmdb->dict.name,
+                 mdb_strerror(status));
+    }
+    return (status);
+}
+
+/* dict_lmdb_cursor_get - mdb_cursor_get() wrapper with LMDB error recovery */
+
+static int dict_lmdb_cursor_get(DICT_LMDB *dict_lmdb, MDB_val *mdb_key,
+                                       MDB_val *mdb_value, MDB_cursor_op op)
+{
+    MDB_txn *txn;
+    int     status;
+
+    /*
+     * Open a read transaction and cursor if needed.
+     */
+    if (dict_lmdb->cursor == 0) {
+       dict_lmdb_txn_begin(dict_lmdb, MDB_RDONLY, &txn);
+       if ((status = mdb_cursor_open(txn, dict_lmdb->dbi, &dict_lmdb->cursor))) {
+           if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+               return (dict_lmdb_cursor_get(dict_lmdb, mdb_key, mdb_value, op));
+           msg_fatal("%s:%s: cursor_open database: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
+       }
+    }
+
+    /*
+     * Database lookup.
+     */
+    status = mdb_cursor_get(dict_lmdb->cursor, mdb_key, mdb_value, op);
+    if (status != 0 && status != MDB_NOTFOUND)
+       if ((status = dict_lmdb_recover(dict_lmdb, status)) == 0)
+           return (dict_lmdb_cursor_get(dict_lmdb, mdb_key, mdb_value, op));
+    return (status);
+}
+
+/* dict_lmdb_finish - wrapper with LMDB error recovery */
+
+static void dict_lmdb_finish(DICT_LMDB *dict_lmdb)
+{
+    int     status;
+
+    /*
+     * Finish the bulk-mode transaction. If dict_lmdb_recover() returns after
+     * a bulk-mode transaction error, then it was unable to recover.
+     */
+    if (dict_lmdb->txn) {
+       if ((status = mdb_txn_commit(dict_lmdb->txn)) != 0) {
+           (void) dict_lmdb_recover(dict_lmdb, status);
+           msg_fatal("%s:%s: closing dictionary: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
+       }
+    }
+
+    /*
+     * Clean up after an unfinished sequence() operation.
+     */
+    if (dict_lmdb->cursor) {
+       MDB_txn *txn = mdb_cursor_txn(dict_lmdb->cursor);
+
+       mdb_cursor_close(dict_lmdb->cursor);
+       mdb_txn_abort(txn);
+    }
+}
+
+ /*
+  * With all recovery from LMDB quirks encapsulated in the routines above,
+  * the dict(3) API routines below can pretend that LMDB quirks don't exist
+  * and focus on their own job: accessing or updating the database.
+  */
+
 /* dict_lmdb_lookup - find database entry */
 
 static const char *dict_lmdb_lookup(DICT *dict, const char *name)
@@ -140,11 +515,11 @@ static const char *dict_lmdb_lookup(DICT *dict, const char *name)
     DICT_LMDB *dict_lmdb = (DICT_LMDB *) dict;
     MDB_val mdb_key;
     MDB_val mdb_value;
-    MDB_txn *txn;
     const char *result = 0;
     int     status, klen;
 
     dict->error = 0;
+    dict_lmdb->dict_api_retries = 0;
     klen = strlen(name);
 
     /*
@@ -163,14 +538,6 @@ static const char *dict_lmdb_lookup(DICT *dict, const char *name)
        name = lowercase(vstring_str(dict->fold_buf));
     }
 
-    /*
-     * Start a read transaction if there's no global txn.
-     */
-    if (dict_lmdb->txn)
-       txn = dict_lmdb->txn;
-    else if ((status = mdb_txn_begin(dict_lmdb->env, NULL, MDB_RDONLY, &txn)))
-       msg_fatal("%s: txn_begin(read) dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
-
     /*
      * See if this LMDB file was written with one null byte appended to key
      * and value.
@@ -178,10 +545,15 @@ static const char *dict_lmdb_lookup(DICT *dict, const char *name)
     if (dict->flags & DICT_FLAG_TRY1NULL) {
        mdb_key.mv_data = (void *) name;
        mdb_key.mv_size = klen + 1;
-       status = mdb_get(txn, dict_lmdb->dbi, &mdb_key, &mdb_value);
-       if (!status) {
+       status = dict_lmdb_get(dict_lmdb, &mdb_key, &mdb_value);
+       if (status == 0) {
            dict->flags &= ~DICT_FLAG_TRY0NULL;
-           result = SCOPY(dict_lmdb->val_buf, mdb_value.mv_data, mdb_value.mv_size);
+           result = SCOPY(dict_lmdb->val_buf, mdb_value.mv_data,
+                          mdb_value.mv_size);
+       } else if (status != MDB_NOTFOUND) {
+           msg_fatal("error reading %s:%s: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
        }
     }
 
@@ -192,19 +564,17 @@ static const char *dict_lmdb_lookup(DICT *dict, const char *name)
     if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
        mdb_key.mv_data = (void *) name;
        mdb_key.mv_size = klen;
-       status = mdb_get(txn, dict_lmdb->dbi, &mdb_key, &mdb_value);
-       if (!status) {
+       status = dict_lmdb_get(dict_lmdb, &mdb_key, &mdb_value);
+       if (status == 0) {
            dict->flags &= ~DICT_FLAG_TRY1NULL;
-           result = SCOPY(dict_lmdb->val_buf, mdb_value.mv_data, mdb_value.mv_size);
+           result = SCOPY(dict_lmdb->val_buf, mdb_value.mv_data,
+                          mdb_value.mv_size);
+       } else if (status != MDB_NOTFOUND) {
+           msg_fatal("error reading %s:%s: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
        }
     }
-
-    /*
-     * Close the read txn if it's not the global txn.
-     */
-    if (!dict_lmdb->txn)
-       mdb_txn_abort(txn);
-
     return (result);
 }
 
@@ -215,10 +585,10 @@ static int dict_lmdb_update(DICT *dict, const char *name, const char *value)
     DICT_LMDB *dict_lmdb = (DICT_LMDB *) dict;
     MDB_val mdb_key;
     MDB_val mdb_value;
-    MDB_txn *txn;
     int     status;
 
     dict->error = 0;
+    dict_lmdb->dict_api_retries = 0;
 
     /*
      * Sanity check.
@@ -236,6 +606,7 @@ static int dict_lmdb_update(DICT *dict, const char *name, const char *value)
        name = lowercase(vstring_str(dict->fold_buf));
     }
     mdb_key.mv_data = (void *) name;
+
     mdb_value.mv_data = (void *) value;
     mdb_key.mv_size = strlen(name);
     mdb_value.mv_size = strlen(value);
@@ -261,40 +632,27 @@ static int dict_lmdb_update(DICT *dict, const char *name, const char *value)
        mdb_value.mv_size++;
     }
 
-    /*
-     * Start a write transaction if there's no global txn.
-     */
-    if (dict_lmdb->txn)
-       txn = dict_lmdb->txn;
-    else if (DICT_LMDB_WRAPPER(dict, status,
-                              mdb_txn_begin(dict_lmdb->env, NULL, 0, &txn)))
-       msg_fatal("%s: txn_begin(write) dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
-
     /*
      * Do the update.
      */
-    (void) DICT_LMDB_WRAPPER(dict, status,
-                         mdb_put(txn, dict_lmdb->dbi, &mdb_key, &mdb_value,
-             (dict->flags & DICT_FLAG_DUP_REPLACE) ? 0 : MDB_NOOVERWRITE));
-    if (status) {
+    status = dict_lmdb_put(dict_lmdb, &mdb_key, &mdb_value,
+              (dict->flags & DICT_FLAG_DUP_REPLACE) ? 0 : MDB_NOOVERWRITE);
+    if (status != 0) {
        if (status == MDB_KEYEXIST) {
            if (dict->flags & DICT_FLAG_DUP_IGNORE)
                 /* void */ ;
            else if (dict->flags & DICT_FLAG_DUP_WARN)
-               msg_warn("%s: duplicate entry: \"%s\"", dict_lmdb->dict.name, name);
+               msg_warn("%s:%s: duplicate entry: \"%s\"",
+                        dict_lmdb->dict.type, dict_lmdb->dict.name, name);
            else
-               msg_fatal("%s: duplicate entry: \"%s\"", dict_lmdb->dict.name, name);
+               msg_fatal("%s:%s: duplicate entry: \"%s\"",
+                         dict_lmdb->dict.type, dict_lmdb->dict.name, name);
        } else {
-           msg_fatal("error writing LMDB database %s: %s", dict_lmdb->dict.name, mdb_strerror(status));
+           msg_fatal("error updating %s:%s: %s",
+                     dict_lmdb->dict.type, dict_lmdb->dict.name,
+                     mdb_strerror(status));
        }
     }
-
-    /*
-     * Commit the transaction if it's not the global txn.
-     */
-    if (!dict_lmdb->txn && DICT_LMDB_WRAPPER(dict, status, mdb_txn_commit(txn)))
-       msg_fatal("error committing LMDB database %s: %s", dict_lmdb->dict.name, mdb_strerror(status));
-
     return (status);
 }
 
@@ -304,10 +662,10 @@ static int dict_lmdb_delete(DICT *dict, const char *name)
 {
     DICT_LMDB *dict_lmdb = (DICT_LMDB *) dict;
     MDB_val mdb_key;
-    MDB_txn *txn;
-    int     status = 1, klen, rc;
+    int     status = 1, klen;
 
     dict->error = 0;
+    dict_lmdb->dict_api_retries = 0;
     klen = strlen(name);
 
     /*
@@ -326,15 +684,6 @@ static int dict_lmdb_delete(DICT *dict, const char *name)
        name = lowercase(vstring_str(dict->fold_buf));
     }
 
-    /*
-     * Start a write transaction if there's no global txn.
-     */
-    if (dict_lmdb->txn)
-       txn = dict_lmdb->txn;
-    else if (DICT_LMDB_WRAPPER(dict, status,
-                              mdb_txn_begin(dict_lmdb->env, NULL, 0, &txn)))
-       msg_fatal("%s: txn_begin(write) dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
-
     /*
      * See if this LMDB file was written with one null byte appended to key
      * and value.
@@ -342,13 +691,14 @@ static int dict_lmdb_delete(DICT *dict, const char *name)
     if (dict->flags & DICT_FLAG_TRY1NULL) {
        mdb_key.mv_data = (void *) name;
        mdb_key.mv_size = klen + 1;
-       (void) DICT_LMDB_WRAPPER(dict, status,
-                             mdb_del(txn, dict_lmdb->dbi, &mdb_key, NULL));
-       if (status) {
+       status = dict_lmdb_del(dict_lmdb, &mdb_key);
+       if (status != 0) {
            if (status == MDB_NOTFOUND)
                status = 1;
            else
-               msg_fatal("error deleting from %s: %s", dict_lmdb->dict.name, mdb_strerror(status));
+               msg_fatal("error deleting from %s:%s: %s",
+                         dict_lmdb->dict.type, dict_lmdb->dict.name,
+                         mdb_strerror(status));
        } else {
            dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */
        }
@@ -361,28 +711,22 @@ static int dict_lmdb_delete(DICT *dict, const char *name)
     if (status > 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
        mdb_key.mv_data = (void *) name;
        mdb_key.mv_size = klen;
-       (void) DICT_LMDB_WRAPPER(dict, status,
-                             mdb_del(txn, dict_lmdb->dbi, &mdb_key, NULL));
-       if (status) {
+       status = dict_lmdb_del(dict_lmdb, &mdb_key);
+       if (status != 0) {
            if (status == MDB_NOTFOUND)
                status = 1;
            else
-               msg_fatal("error deleting from %s: %s", dict_lmdb->dict.name, mdb_strerror(status));
+               msg_fatal("error deleting from %s:%s: %s",
+                         dict_lmdb->dict.type, dict_lmdb->dict.name,
+                         mdb_strerror(status));
        } else {
            dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */
        }
     }
-
-    /*
-     * Commit the transaction if it's not the global txn.
-     */
-    if (!dict_lmdb->txn && DICT_LMDB_WRAPPER(dict, rc, mdb_txn_commit(txn)))
-       msg_fatal("error committing LMDB database %s: %s", dict_lmdb->dict.name, mdb_strerror(rc));
-
     return (status);
 }
 
-/* traverse the dictionary */
+/* dict_lmdb_sequence - traverse the dictionary */
 
 static int dict_lmdb_sequence(DICT *dict, int function,
                                      const char **key, const char **value)
@@ -396,6 +740,7 @@ static int dict_lmdb_sequence(DICT *dict, int function,
     int     status;
 
     dict->error = 0;
+    dict_lmdb->dict_api_retries = 0;
 
     /*
      * Determine the seek function.
@@ -411,50 +756,42 @@ static int dict_lmdb_sequence(DICT *dict, int function,
        msg_panic("%s: invalid function: %d", myname, function);
     }
 
-    /*
-     * Open a read transaction and cursor if needed.
-     */
-    if (dict_lmdb->cursor == 0) {
-       if ((status = mdb_txn_begin(dict_lmdb->env, NULL, MDB_RDONLY, &txn)))
-           msg_fatal("%s: txn_begin(read) dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
-       if ((status = mdb_cursor_open(txn, dict_lmdb->dbi, &dict_lmdb->cursor)))
-           msg_fatal("%s: cursor_open dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
-    }
-
     /*
      * Database lookup.
      */
-    status = mdb_cursor_get(dict_lmdb->cursor, &mdb_key, &mdb_value, op);
-    if (status && status != MDB_NOTFOUND)
-       msg_fatal("%s: seeking dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
+    status = dict_lmdb_cursor_get(dict_lmdb, &mdb_key, &mdb_value, op);
+
+    switch (status) {
 
-    if (status == MDB_NOTFOUND) {
+       /*
+        * Copy the key and value so they are guaranteed null terminated.
+        */
+    case 0:
+       *key = SCOPY(dict_lmdb->key_buf, mdb_key.mv_data, mdb_key.mv_size);
+       if (mdb_value.mv_data != 0 && mdb_value.mv_size > 0)
+           *value = SCOPY(dict_lmdb->val_buf, mdb_value.mv_data,
+                          mdb_value.mv_size);
+       break;
 
        /*
-        * Caller must read to end, to ensure cursor gets closed.
+        * Destroy cursor and read transaction.
         */
+    case MDB_NOTFOUND:
        status = 1;
        txn = mdb_cursor_txn(dict_lmdb->cursor);
        mdb_cursor_close(dict_lmdb->cursor);
        mdb_txn_abort(txn);
        dict_lmdb->cursor = 0;
-    } else {
+       break;
 
        /*
-        * Copy the key so that it is guaranteed null terminated.
+        * Bust.
         */
-       *key = SCOPY(dict_lmdb->key_buf, mdb_key.mv_data, mdb_key.mv_size);
-
-       if (mdb_value.mv_data != 0 && mdb_value.mv_size > 0) {
-
-           /*
-            * Copy the value so that it is guaranteed null terminated.
-            */
-           *value = SCOPY(dict_lmdb->val_buf, mdb_value.mv_data, mdb_value.mv_size);
-           status = 0;
-       }
+    default:
+       msg_fatal("error seeking %s:%s: %s",
+                 dict_lmdb->dict.type, dict_lmdb->dict.name,
+                 mdb_strerror(status));
     }
-
     return (status);
 }
 
@@ -472,20 +809,8 @@ static void dict_lmdb_close(DICT *dict)
 {
     DICT_LMDB *dict_lmdb = (DICT_LMDB *) dict;
 
-    if (dict_lmdb->txn) {
-       int     status;
-
-       (void) DICT_LMDB_WRAPPER(dict, status, mdb_txn_commit(dict_lmdb->txn));
-       if (status)
-           msg_fatal("%s: closing dictionary: %s", dict_lmdb->dict.name, mdb_strerror(status));
-       dict_lmdb->cursor = NULL;
-    }
-    if (dict_lmdb->cursor) {
-       MDB_txn *txn = mdb_cursor_txn(dict_lmdb->cursor);
-
-       mdb_cursor_close(dict_lmdb->cursor);
-       mdb_txn_abort(txn);
-    }
+    dict_lmdb->dict_api_retries = 0;
+    dict_lmdb_finish(dict_lmdb);
     if (dict_lmdb->dict.stat_fd >= 0)
        close(dict_lmdb->dict.stat_fd);
     mdb_env_close(dict_lmdb->env);
@@ -509,6 +834,7 @@ DICT   *dict_lmdb_open(const char *path, int open_flags, int dict_flags)
     MDB_dbi dbi;
     char   *mdb_path;
     int     env_flags, status;
+    size_t  map_size = dict_lmdb_map_size;
 
     mdb_path = concatenate(path, "." DICT_TYPE_LMDB, (char *) 0);
 
@@ -519,73 +845,33 @@ DICT   *dict_lmdb_open(const char *path, int open_flags, int dict_flags)
     if ((status = mdb_env_create(&env)))
        msg_fatal("env_create %s: %s", mdb_path, mdb_strerror(status));
 
-    /*
-     * Try to ensure that the LMDB size limit is at least 3x the current LMDB
-     * file size. This ensures that Postfix daemon processes can recover from
-     * a "table full" error with a simple terminate-and-restart.
-     * 
-     * Note: read-only applications must increase their LMDB size limit, too,
-     * otherwise they won't be able to read a table after it grows.
-     */
-#ifndef SIZE_T_MAX
-#define SIZE_T_MAX __MAXINT__(size_t)
-#endif
-#define LMDB_SIZE_FUDGE_FACTOR 3
-
-    if (stat(mdb_path, &st) == 0
-       && st.st_size >= dict_lmdb_map_size / LMDB_SIZE_FUDGE_FACTOR) {
-       msg_warn("%s: file size %lu >= (%s map size limit %ld)/%d -- "
-                "using a larger map size limit",
-                mdb_path, (unsigned long) st.st_size,
-                DICT_TYPE_LMDB, (long) dict_lmdb_map_size,
-                LMDB_SIZE_FUDGE_FACTOR);
-       /* Defense against naive optimizers. */
-       if (st.st_size < SIZE_T_MAX / LMDB_SIZE_FUDGE_FACTOR)
-           dict_lmdb_map_size = st.st_size * LMDB_SIZE_FUDGE_FACTOR;
-       else
-           dict_lmdb_map_size = SIZE_T_MAX;
-    }
-    if ((status = mdb_env_set_mapsize(env, dict_lmdb_map_size)))
+    if (stat(mdb_path, &st) == 0 && st.st_size > map_size)
+       map_size = st.st_size;
+    if ((status = mdb_env_set_mapsize(env, map_size)))
        msg_fatal("env_set_mapsize %s: %s", mdb_path, mdb_strerror(status));
 
     if ((status = mdb_env_set_maxreaders(env, dict_lmdb_max_readers)))
        msg_fatal("env_set_maxreaders %s: %s", mdb_path, mdb_strerror(status));
 
-    if ((status = mdb_env_open(env, mdb_path, env_flags, 0644)))
-       msg_fatal("env_open %s: %s", mdb_path, mdb_strerror(status));
-
+    /*
+     * Gracefully handle the most common mistake.
+     */
+    if ((status = mdb_env_open(env, mdb_path, env_flags, 0644))) {
+       mdb_env_close(env);
+       return (dict_surrogate(DICT_TYPE_LMDB, path, open_flags, dict_flags,
+                              "open database %s: %m", mdb_path));
+    }
     if ((status = mdb_txn_begin(env, NULL, env_flags & MDB_RDONLY, &txn)))
        msg_fatal("txn_begin %s: %s", mdb_path, mdb_strerror(status));
 
     /*
-     * mdb_open requires a txn, but since the default DB always exists in an
-     * LMDB environment, we usually don't need to do anything else with the
-     * txn.
+     * mdb_open() requires a txn, but since the default DB always exists in
+     * an LMDB environment, we usually don't need to do anything else with
+     * the txn. It is currently used for bulk transactions.
      */
     if ((status = mdb_open(txn, NULL, 0, &dbi)))
        msg_fatal("mdb_open %s: %s", mdb_path, mdb_strerror(status));
 
-    /*
-     * Cases where we use the mdb_open transaction:
-     * 
-     * - With O_TRUNC we make the "drop" request before populating the database.
-     * 
-     * - With DICT_FLAG_BULK_UPDATE we commit the transaction when the database
-     * is closed.
-     */
-    if (open_flags & O_TRUNC) {
-       if ((status = mdb_drop(txn, dbi, 0)))
-           msg_fatal("truncate %s: %s", mdb_path, mdb_strerror(status));
-       if ((dict_flags & DICT_FLAG_BULK_UPDATE) == 0) {
-           if ((status = mdb_txn_commit(txn)))
-               msg_fatal("truncate %s: %s", mdb_path, mdb_strerror(status));
-           txn = NULL;
-       }
-    } else if ((env_flags & MDB_RDONLY) != 0
-              || (dict_flags & DICT_FLAG_BULK_UPDATE) == 0) {
-       mdb_txn_abort(txn);
-       txn = NULL;
-    }
     dict_lmdb = (DICT_LMDB *) dict_alloc(DICT_TYPE_LMDB, path, sizeof(*dict_lmdb));
     dict_lmdb->dict.lookup = dict_lmdb_lookup;
     dict_lmdb->dict.update = dict_lmdb_update;
@@ -619,14 +905,22 @@ DICT   *dict_lmdb_open(const char *path, int open_flags, int dict_flags)
        dict_lmdb->dict.fold_buf = vstring_alloc(10);
     dict_lmdb->env = env;
     dict_lmdb->dbi = dbi;
-
-    /* Save the write txn if we opened with O_TRUNC */
-    dict_lmdb->txn = txn;
+    dict_lmdb->map_size = map_size;
 
     dict_lmdb->cursor = 0;
     dict_lmdb->key_buf = 0;
     dict_lmdb->val_buf = 0;
 
+    /* The following facilitate transparent error recovery. */
+    dict_lmdb->dict_api_retries = 0;
+    dict_lmdb->bulk_mode_retries = 0;
+    dict_lmdb->open_flags = open_flags;
+    dict_lmdb->env_flags = env_flags;
+    dict_lmdb->txn = txn;
+    dict_lmdb_prepare(dict_lmdb);
+    if (dict_flags & DICT_FLAG_BULK_UPDATE)
+       dict_jmp_alloc(&dict_lmdb->dict);       /* build into dict_alloc() */
+
     myfree(mdb_path);
 
     return (DICT_DEBUG (&dict_lmdb->dict));
index 580d2b3a98d8dcf57534f88874975f3149dafbd4..aee1f8ddd9de04aaa9fd71dc6ee7272b3d2e922a 100644 (file)
 /*     DICT    *(*open) (const char *, int, int);
 /*
 /*     ARGV    *dict_mapnames()
+/*
+/*     int     dict_isjmp(dict)
+/*     DICT    *dict;
+/*
+/*     int     dict_setjmp(dict)
+/*     DICT    *dict;
+/*
+/*     int     dict_longjmp(dict, val)
+/*     DICT    *dict;
+/*     int     val;
 /* DESCRIPTION
 /*     This module implements a low-level interface to multiple
 /*     physical dictionary types.
 /* .IP DICT_FLAG_PARANOID
 /*     A combination of all the paranoia flags: DICT_FLAG_NO_REGSUB,
 /*     DICT_FLAG_NO_PROXY and DICT_FLAG_NO_UNAUTH.
+/* .IP DICT_FLAG_BULK_UPDATE
+/*     Enable preliminary code for bulk-mode database updates.
+/*     The caller must create an exception handler with dict_jmp_alloc()
+/*     and must trap exceptions from the database client with dict_setjmp().
 /* .IP DICT_FLAG_DEBUG
 /*     Enable additional logging.
 /* .PP
 /*
 /*     dict_mapnames() returns a sorted list with the names of all available
 /*     dictionary types.
+/*
+/*     dict_setjmp() saves processing context and makes that context
+/*     available for use with dict_longjmp().  Normally, dict_setjmp()
+/*     returns zero.  A non-zero result means that dict_setjmp()
+/*     returned through a dict_longjmp() call; the result is the
+/*     \fIval\fR argment given to dict_longjmp(). dict_isjmp()
+/*     returns non-zero when dict_setjmp() and dict_longjmp()
+/*     are enabled for a given dictionary.
+/*
+/*     NB: non-local jumps such as dict_longjmp() are not safe for
+/*     jumping out of any routine that manipulates DICT data.
+/*     longjmp() like calls are best avoided in signal handlers.
 /* DIAGNOSTICS
 /*     Fatal error: open error, unsupported dictionary type, attempt to
 /*     update non-writable dictionary.
index b7a3df586dbb03bb646037c6c234790e08249a63..409b634b9188e2f168e9eb987bf278a6e59406bf 100644 (file)
@@ -45,6 +45,8 @@ void    dict_test(int argc, char **argv)
     int     n;
     int     rc;
 
+#define USAGE  "verbose|del key|get key|put key=value|first|next|masks|flags"
+
     signal(SIGPIPE, SIG_IGN);
 
     msg_vstream_init(argv[0], VSTREAM_ERR);
@@ -88,7 +90,7 @@ void    dict_test(int argc, char **argv)
        if (*bufp == '#')
            continue;
        if ((cmd = mystrtok(&bufp, " ")) == 0) {
-           vstream_printf("usage: verbose|del key|get key|put key=value|first|next|masks|flags\n");
+           vstream_printf("usage: %s\n", USAGE);
            vstream_fflush(VSTREAM_OUT);
            continue;
        }
@@ -143,7 +145,7 @@ void    dict_test(int argc, char **argv)
            vstream_printf("DICT_FLAG_INST_MASK %s\n",
                           dict_flags_str(DICT_FLAG_INST_MASK));
        } else {
-           vstream_printf("usage: del key|get key|put key=value|first|next|masks|flags\n");
+           vstream_printf("usage: %s\n", USAGE);
        }
        vstream_fflush(VSTREAM_OUT);
     }
index 2bb01d79250347a85f524be417573112d3bc49de..04814a53753f90413a2cb448b2a9a6ef54282c0a 100644 (file)
 #define HAS_FSYNC
 #define HAS_DB
 #define HAS_SA_LEN
-#define DEF_DB_TYPE    "hash"
+#define NATIVE_DB_TYPE "hash"
 #if (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 104250000)
-#define ALIAS_DB_MAP   "hash:/etc/mail/aliases"        /* sendmail 8.10 */
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"        /* sendmail 8.10 */
 #endif
 #if (defined(OpenBSD) && OpenBSD >= 200006)
-#define ALIAS_DB_MAP   "hash:/etc/mail/aliases"        /* OpenBSD 2.7 */
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"        /* OpenBSD 2.7 */
 #endif
 #ifndef ALIAS_DB_MAP
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #endif
 #define GETTIMEOFDAY(t)        gettimeofday(t,(struct timezone *) 0)
 #define ROOT_PATH      "/bin:/usr/bin:/sbin:/usr/sbin"
 #define HAS_FSYNC
 #define HAS_DB
 #define HAS_SA_LEN
-#define DEF_DB_TYPE    "hash"
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define NATIVE_DB_TYPE "hash"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #define GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *) 0)
 #define ROOT_PATH      "/bin:/usr/bin:/sbin:/usr/sbin"
 #define USE_STATFS
 #define HAS_FSYNC
 /* might be set by makedef */
 #ifdef HAS_DB
-#define DEF_DB_TYPE    "hash"
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define NATIVE_DB_TYPE "hash"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #else
 #define HAS_DBM
-#define        DEF_DB_TYPE     "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/aliases"
+#define        NATIVE_DB_TYPE  "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #endif
 extern int optind;
 extern char *optarg;
@@ -336,8 +336,8 @@ extern int h_errno;
 #define HAS_FSYNC
 #define HAVE_BASENAME
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/var/adm/sendmail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/var/adm/sendmail/aliases"
 extern int optind;                     /* XXX use <getopt.h> */
 extern char *optarg;                   /* XXX use <getopt.h> */
 extern int opterr;                     /* XXX use <getopt.h> */
@@ -383,8 +383,8 @@ extern int opterr;                  /* XXX use <getopt.h> */
 #define DEF_MAILBOX_LOCK "flock, dotlock"
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 extern int optind;
 extern char *optarg;
 extern int opterr;
@@ -429,8 +429,8 @@ extern int opterr;
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #define HAS_NISPLUS
@@ -506,8 +506,8 @@ extern int opterr;
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -537,8 +537,8 @@ extern int opterr;
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE     "dbm"
-#define ALIAS_DB_MAP    "dbm:/etc/mail/aliases"
+#define NATIVE_DB_TYPE     "dbm"
+#define ALIAS_DB_MAP    DEF_DB_TYPE ":/etc/mail/aliases"
 #ifndef NO_NIS
 #define HAS_NIS */
 #endif
@@ -580,8 +580,8 @@ extern int opterr;
 #define USE_SYS_SELECT_H
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -634,8 +634,8 @@ extern int opterr;
 #define USE_SYS_SELECT_H
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -680,8 +680,8 @@ extern int initgroups(const char *, int);
 #define USE_SYS_SELECT_H
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -722,8 +722,8 @@ extern int initgroups(const char *, int);
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -766,8 +766,8 @@ extern int initgroups(const char *, int);
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"      /* RedHat >= 4.x */
 #define HAS_FSYNC
 #define HAS_DB
-#define DEF_DB_TYPE    "hash"
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define NATIVE_DB_TYPE "hash"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -843,8 +843,8 @@ extern int initgroups(const char *, int);
 #define DEF_MAILBOX_LOCK "dotlock"     /* verified RedHat 3.03 */
 #define HAS_FSYNC
 #define HAS_DB
-#define DEF_DB_TYPE    "hash"
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define NATIVE_DB_TYPE "hash"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -877,8 +877,8 @@ extern int initgroups(const char *, int);
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"      /* RedHat >= 4.x */
 #define HAS_FSYNC
 #define HAS_DB
-#define DEF_DB_TYPE    "hash"
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define NATIVE_DB_TYPE "hash"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 #ifndef NO_NIS
 #define HAS_NIS
 #endif
@@ -943,8 +943,8 @@ extern int initgroups(const char *, int);
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FCNTL
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"
 #define ROOT_PATH      "/usr/bin:/sbin:/usr/sbin"
 #define MISSING_SETENV
 #ifndef NO_NIS
@@ -982,8 +982,8 @@ extern int h_errno;                 /* <netdb.h> imports too much stuff */
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FCNTL
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"
 #define ROOT_PATH      "/usr/bin:/sbin:/usr/sbin"
 #define MISSING_SETENV
 #ifndef NO_NIS
@@ -1027,8 +1027,8 @@ extern int h_errno;                       /* <netdb.h> imports too much stuff */
 #define MISSING_SETENV
 #define MISSING_RLIMIT_FSIZE
 #define GETTIMEOFDAY(t)        gettimeofday(t,(struct timezone *) 0)
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/usr/lib/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/usr/lib/aliases"
 #define ROOT_PATH      "/bin:/usr/bin:/etc"
 #define _PATH_BSHELL   "/bin/sh"
 #define _PATH_MAILDIR  "/usr/mail"
@@ -1087,7 +1087,7 @@ extern int h_errno;
 #define _PATH_DEFPATH  "/bin:/usr/bin:/usr/ucb"
 #define _PATH_STDPATH  "/bin:/usr/bin:/usr/ucb"
 #define ROOT_PATH      "/bin:/usr/bin:/usr/etc:/usr/ucb"
-#define DEF_DB_TYPE    "dbm"
+#define NATIVE_DB_TYPE "dbm"
 #define ALIAS_DB_MAP   "netinfo:/aliases"
 #include <libc.h>
 #define MISSING_POSIX_S_IS
@@ -1142,7 +1142,7 @@ typedef unsigned short mode_t;
 #define _PATH_DEFPATH  "/bin:/usr/bin:/usr/ucb"
 #define _PATH_STDPATH  "/bin:/usr/bin:/usr/ucb"
 #define ROOT_PATH      "/bin:/usr/bin:/usr/etc:/usr/ucb"
-#define DEF_DB_TYPE    "dbm"
+#define NATIVE_DB_TYPE "dbm"
 #define ALIAS_DB_MAP   "netinfo:/aliases"
 #include <libc.h>
 #define MISSING_POSIX_S_IS
@@ -1179,8 +1179,8 @@ typedef unsigned short mode_t;
 #define FIONREAD_IN_SYS_FILIO_H
 #define USE_SYS_SOCKIO_H
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/var/adm/sendmail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/var/adm/sendmail/aliases"
 extern int optind;                     /* XXX use <getopt.h> */
 extern char *optarg;                   /* XXX use <getopt.h> */
 extern int opterr;                     /* XXX use <getopt.h> */
@@ -1209,8 +1209,8 @@ extern int opterr;                        /* XXX use <getopt.h> */
 #define INTERNAL_LOCK  MYFLOCK_STYLE_FCNTL
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
-#define DEF_DB_TYPE    "hash"
-#define ALIAS_DB_MAP   "hash:/etc/aliases"
+#define NATIVE_DB_TYPE "hash"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/aliases"
 /* Uncomment the following line if you have NIS package installed */
 /* #define HAS_NIS */
 #define USE_SYS_SOCKIO_H
@@ -1242,8 +1242,8 @@ extern int h_errno;
 #define DEF_MAILBOX_LOCK "fcntl, dotlock"
 #define HAS_FSYNC
 #define HAS_DBM
-#define DEF_DB_TYPE    "dbm"
-#define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
+#define NATIVE_DB_TYPE "dbm"
+#define ALIAS_DB_MAP   DEF_DB_TYPE ":/etc/mail/aliases"
 #define DBM_NO_TRAILING_NULL
 #ifndef NO_NIS
 #define HAS_NIS
@@ -1303,6 +1303,10 @@ extern int h_errno;
 #endif
 #endif
 
+#ifndef DEF_DB_TYPE
+#define DEF_DB_TYPE    NATIVE_DB_TYPE
+#endif
+
 #define CAST_CHAR_PTR_TO_INT(cptr)     ((int) (long) (cptr))
 #define CAST_INT_TO_CHAR_PTR(ival)     ((char *) (long) (ival))