From: Wietse Venema Date: Wed, 15 Dec 2004 05:00:00 +0000 (-0500) Subject: postfix-2.2-20041215 X-Git-Tag: v2.2.0-RC1~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9ef211dc61e3e78296d1a48ac9271da3fef4dc92;p=thirdparty%2Fpostfix.git postfix-2.2-20041215 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index ac72609b5..67a0f671c 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -9926,6 +9926,39 @@ Apologies for any names omitted. Hexadecimal encode/decode routines, from the TLS-enabled version. Files: util/hext_code.[hc]. +20041212 + + Solaris 10/ix86 chroot setup script update by J.D. Bronson. + +20041213 + + Updated the SDBM dictionary interface. It had fallen behind + with the Postfix dictionary interfaces that were already + bundled with Postfix. Files: util/dict_sdbm.[hc]. + + Cleanup: "postconf -m" (show all available map types) now + produces sorted output. File: util/dict_open.c. + +20041215 + + No bugfix: tests with the new "postmap -s" feature show + that SDBM first/next operations never worked with Postfix/TLS + patch 20040829 (verified with the 20040829 dict_sdbm.c + module on Linux and FreeBSD). The code stops after finding + one database element. Other SDBM versions found on the + Internet will find all database entries, but report an I/O + error after the last database element is found. All this + would be easy enough to fix, but the SDBM library is not + part of Postfix, and never will be. + + Bugfix: the sequence operator in the DBM and SDBM clients + released the shared lock after reading the next key but + before reading the corresponding value. This was never a + problem, because the sequence operator was used only in + the Postfix/TLS patch. This used the SDBM sequence operator + which didn't work as discussed above. Files: util/dict_dbm.c, + util/dict_sdbm.c. + Open problems: Med: implement ${name[?:]value} in main.cf or update the @@ -10024,9 +10057,6 @@ Open problems: servers seem to need this in particular. Need a way to expire cached results that are too old. - Medium: make address rewriting on/off configurable for - envelopes and/or headers. - Low: generic showq protocol, to allow for more intelligent processing than just mailq. Maybe marry this with postsuper. diff --git a/postfix/examples/chroot-setup/Solaris10 b/postfix/examples/chroot-setup/Solaris10 new file mode 100644 index 000000000..a815218f9 --- /dev/null +++ b/postfix/examples/chroot-setup/Solaris10 @@ -0,0 +1,110 @@ +#!/bin/sh +# From original Solaris 8 version by Matthew X. Economou +# Solaris 10 version updated by JD Bronson. Caution: this copies +# too many files. There is no need to copy libc.so and other files +# that are already linked in before a Postfix daemon chroots itself. + +COMMAND_DIRECTORY="/usr/sbin" +DAEMON_DIRECTORY="/usr/libexec/postfix" +QUEUE_DIRECTORY="/var/spool/postfix" + +## Copy any shared libraries, device entries, or configuration files +## needed by Postfix into the jail. +binlist=" +$DAEMON_DIRECTORY/virtual +$DAEMON_DIRECTORY/trivial-rewrite +$DAEMON_DIRECTORY/spawn +$DAEMON_DIRECTORY/smtpd +$DAEMON_DIRECTORY/smtp +$DAEMON_DIRECTORY/showq +$DAEMON_DIRECTORY/qmqpd +$DAEMON_DIRECTORY/qmgr +$DAEMON_DIRECTORY/proxymap +$DAEMON_DIRECTORY/pipe +$DAEMON_DIRECTORY/pickup +$DAEMON_DIRECTORY/nqmgr +$DAEMON_DIRECTORY/master +$DAEMON_DIRECTORY/local +$DAEMON_DIRECTORY/lmtp +$DAEMON_DIRECTORY/flush +$DAEMON_DIRECTORY/error +$DAEMON_DIRECTORY/cleanup +$DAEMON_DIRECTORY/bounce +/usr/lib/sendmail +$COMMAND_DIRECTORY/postsuper +$COMMAND_DIRECTORY/postqueue +$COMMAND_DIRECTORY/postmap +$COMMAND_DIRECTORY/postlog +$COMMAND_DIRECTORY/postlock +$COMMAND_DIRECTORY/postkick +$COMMAND_DIRECTORY/postfix +$COMMAND_DIRECTORY/postdrop +$COMMAND_DIRECTORY/postconf +$COMMAND_DIRECTORY/postcat +$COMMAND_DIRECTORY/postalias +" +ldd $binlist | awk '/[=]>/ { print $3 }' | sort -u | while read i +do + mkdir -p $QUEUE_DIRECTORY`dirname $i` + ## Sun's version of tar sucks. We'll have to remove the leading + ## slashes from file names ourself, otherwise the copy doesn't + ## work. + (cd / && tar cphf - `echo $i | sed -e 's/^\///'`) | (cd $QUEUE_DIRECTORY && tar xpf -) +done + +## More stuff for the jail, mostly discovered by inspection +## (e.g. strings, lsof). +more=" +/dev/zero +/dev/null +/dev/udp6 +/dev/tcp6 +/dev/udp +/dev/tcp +/dev/rawip +/dev/ticlts +/dev/ticotsord +/dev/ticots +/devices/pseudo/mm@0:zero +/devices/pseudo/mm@0:null +/devices/pseudo/udp6@0:udp6 +/devices/pseudo/tcp6@0:tcp6 +/devices/pseudo/udp@0:udp +/devices/pseudo/tcp@0:tcp +/devices/pseudo/icmp@0:icmp +/devices/pseudo/tl@0:ticlts +/devices/pseudo/tl@0:ticotsord +/devices/pseudo/tl@0:ticots +/etc/hosts +/etc/nsswitch.conf +/etc/netconfig +/etc/passwd +/etc/resolv.conf +/etc/default/init +/etc/default/nss +/etc/inet/services +/etc/inet/hosts +/etc/services +/lib/ld.so +/lib/ld.so.1 +/usr/lib/nss_dns.so.1 +/usr/lib/sparcv9/straddr.so +/usr/lib/straddr.so +/usr/lib/straddr.so.2 +/lib/libintl.so +/lib/libintl.so.1 +/lib/libw.so +/lib/libw.so.1 +/lib/nss_nis.so.1 +/lib/nss_nisplus.so.1 +/lib/nss_dns.so.1 +/lib/nss_files.so.1 +/usr/share/lib/zoneinfo +/var/ld/ld.config +" +for i in $more; do + mkdir -p $QUEUE_DIRECTORY`dirname $i` + (cd / && tar cpf - `echo $i | sed -e 's/^\///'`) | (cd $QUEUE_DIRECTORY && tar xpf -) +done + +exit 0 diff --git a/postfix/html/postconf.1.html b/postfix/html/postconf.1.html index 0398b2c0b..0150a6bb4 100644 --- a/postfix/html/postconf.1.html +++ b/postfix/html/postconf.1.html @@ -112,6 +112,10 @@ POSTCONF(1) POSTCONF(1) The file format is described in reg- exp_table(5). + sdbm An indexed file type based on hashing. This + is available only on systems with support + for SDBM databases. + static (read-only) A table that always returns its name as lookup result. For example, static:foobar diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 3b5f2f4b2..f36e3b6c8 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -5948,11 +5948,12 @@ Example: (default: empty)

-If non-empty, filters the SMTP server's list of offered SASL mechanisms. -Different client and server implementations may support different -mechanism lists. By default, the client will use the intersection of the -two. smtp_sasl_mechanism_filter further restricts what server mechanisms -the client will take into consideration.

+If non-empty, a Postfix SMTP client filter for the remote SMTP +server's list of offered SASL mechanisms. Different client and +server implementations may support different mechanism lists. By +default, the Postfix SMTP client will use the intersection of the +two. smtp_sasl_mechanism_filter further restricts what server +mechanisms the client will take into consideration.

Specify mechanism names, "/file/name" patterns or "type:table" lookup tables. The right-hand side result from "type:table" lookups diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 28fc4b42b..46f3659cb 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -173,29 +173,30 @@ SMTP(8) SMTP(8) Available in Postfix version 2.2 and later: smtp_sasl_mechanism_filter (empty) - If non-empty, filters the SMTP server's list of - offered SASL mechanisms. + If non-empty, a Postfix SMTP client filter for the + remote SMTP server's list of offered SASL mecha- + nisms. RESOURCE AND RATE CONTROLS smtp_destination_concurrency_limit ($default_destina- tion_concurrency_limit) - The maximal number of parallel deliveries to the - same destination via the smtp message delivery + The maximal number of parallel deliveries to the + same destination via the smtp message delivery transport. smtp_destination_recipient_limit ($default_destina- tion_recipient_limit) - The maximal number of recipients per delivery via + The maximal number of recipients per delivery via the smtp message delivery transport. smtp_connect_timeout (30s) - The SMTP client time limit for completing a TCP + The SMTP client time limit for completing a TCP connection, or zero (use the operating system built-in time limit). smtp_helo_timeout (300s) - The SMTP client time limit for sending the HELO or - EHLO command, and for receiving the initial server + The SMTP client time limit for sending the HELO or + EHLO command, and for receiving the initial server response. smtp_xforward_timeout (300s) @@ -203,30 +204,30 @@ SMTP(8) SMTP(8) command, and for receiving the server response. smtp_mail_timeout (300s) - The SMTP client time limit for sending the MAIL - FROM command, and for receiving the server + The SMTP client time limit for sending the MAIL + FROM command, and for receiving the server response. smtp_rcpt_timeout (300s) - The SMTP client time limit for sending the SMTP - RCPT TO command, and for receiving the server + The SMTP client time limit for sending the SMTP + RCPT TO command, and for receiving the server response. smtp_data_init_timeout (120s) - The SMTP client time limit for sending the SMTP - DATA command, and for receiving the server + The SMTP client time limit for sending the SMTP + DATA command, and for receiving the server response. smtp_data_xfer_timeout (180s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP ".", and for receiving the server response. smtp_quit_timeout (300s) - The SMTP client time limit for sending the QUIT + The SMTP client time limit for sending the QUIT command, and for receiving the server response. Available in Postfix version 2.1 and later: @@ -237,77 +238,77 @@ SMTP(8) SMTP(8) lookups, or zero (no limit). smtp_mx_session_limit (2) - The maximal number of SMTP sessions per delivery - request before giving up or delivering to a fall- + The maximal number of SMTP sessions per delivery + request before giving up or delivering to a fall- back relay host, or zero (no limit). smtp_rset_timeout (20s) - The SMTP client time limit for sending the RSET + The SMTP client time limit for sending the RSET command, and for receiving the server response. Available in Postfix version 2.2 and later: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - Temporarily enable SMTP connection caching while a + Temporarily enable SMTP connection caching while a destination has a high volume of mail in the active queue. smtp_connection_cache_reuse_limit (10) When SMTP connection caching is enabled, the number - of times that an SMTP session is reused before it + of times that an SMTP session is reused before it is closed. smtp_connection_cache_time_limit (2s) When SMTP connection caching is enabled, the amount - of time that an unused SMTP client socket is kept + of time that an unused SMTP client socket is kept open before it is closed. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - The increment in verbose logging level when a - remote client or server matches a pattern in the + The increment in verbose logging level when a + remote client or server matches a pattern in the debug_peer_list parameter. debug_peer_list (empty) - Optional list of remote client or server hostname - or network address patterns that cause the verbose - logging level to increase by the amount specified + Optional list of remote client or server hostname + or network address patterns that cause the verbose + logging level to increase by the amount specified in $debug_peer_level. error_notice_recipient (postmaster) - The recipient of postmaster notifications about - mail delivery problems that are caused by policy, + The recipient of postmaster notifications about + mail delivery problems that are caused by policy, resource, software or protocol errors. notify_classes (resource, software) - The list of error classes that are reported to the + The list of error classes that are reported to the postmaster. MISCELLANEOUS CONTROLS best_mx_transport (empty) - Where the Postfix SMTP client should deliver mail + Where the Postfix SMTP client should deliver mail when it detects a "mail loops back to myself" error condition. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. daemon_timeout (18000s) - How much time a Postfix daemon process may take to - handle a request before it is terminated by a + How much time a Postfix daemon process may take to + handle a request before it is terminated by a built-in watchdog timer. disable_dns_lookups (no) - Disable DNS lookups in the Postfix SMTP and LMTP + Disable DNS lookups in the Postfix SMTP and LMTP clients. fallback_relay (empty) - Optional list of relay hosts for SMTP destinations + Optional list of relay hosts for SMTP destinations that can't be found or that are unreachable. inet_interfaces (all) @@ -319,25 +320,25 @@ SMTP(8) SMTP(8) over an internal communication channel. max_idle (100s) - The maximum amount of time that an idle Postfix - daemon process waits for the next service request + The maximum amount of time that an idle Postfix + daemon process waits for the next service request before exiting. max_use (100) - The maximal number of connection requests before a + The maximal number of connection requests before a Postfix daemon process terminates. process_id (read-only) - The process ID of a Postfix command or daemon pro- + The process ID of a Postfix command or daemon pro- cess. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. proxy_interfaces (empty) The network interface addresses that this mail sys- - tem receives mail on by way of a proxy or network + tem receives mail on by way of a proxy or network address translation unit. smtp_bind_address (empty) @@ -345,22 +346,22 @@ SMTP(8) SMTP(8) client should bind to when making a connection. smtp_helo_name ($myhostname) - The hostname to send in the SMTP EHLO or HELO com- + The hostname to send in the SMTP EHLO or HELO com- mand. smtp_host_lookup (dns) - What mechanisms when the SMTP client uses to look + What mechanisms when the SMTP client uses to look up a host's IP address. smtp_randomize_addresses (yes) - Randomize the order of equal-preference MX host + Randomize the order of equal-preference MX host addresses. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - The mail system name that is prepended to the pro- + The mail system name that is prepended to the pro- cess name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". @@ -377,7 +378,7 @@ SMTP(8) SMTP(8) SASL_README, Postfix SASL howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/man/man1/postconf.1 b/postfix/man/man1/postconf.1 index b2a24623d..24d2114b5 100644 --- a/postfix/man/man1/postconf.1 +++ b/postfix/man/man1/postconf.1 @@ -95,6 +95,9 @@ A lookup table that is implemented via the Postfix .IP "\fBregexp\fR (read-only)" A lookup table based on regular expressions. The file format is described in \fBregexp_table\fR(5). +.IP \fBsdbm\fR +An indexed file type based on hashing. +This is available only on systems with support for SDBM databases. .IP "\fBstatic\fR (read-only)" A table that always returns its name as lookup result. For example, \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index accb79de3..5bf87ce68 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -3174,11 +3174,12 @@ smtp_sasl_auth_enable = yes .ad .ft R .SH smtp_sasl_mechanism_filter (default: empty) -If non-empty, filters the SMTP server's list of offered SASL mechanisms. -Different client and server implementations may support different -mechanism lists. By default, the client will use the intersection of the -two. smtp_sasl_mechanism_filter further restricts what server mechanisms -the client will take into consideration. +If non-empty, a Postfix SMTP client filter for the remote SMTP +server's list of offered SASL mechanisms. Different client and +server implementations may support different mechanism lists. By +default, the Postfix SMTP client will use the intersection of the +two. smtp_sasl_mechanism_filter further restricts what server +mechanisms the client will take into consideration. .PP Specify mechanism names, "/file/name" patterns or "type:table" lookup tables. The right-hand side result from "type:table" lookups diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 83bb849e1..d14b61a70 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -165,7 +165,8 @@ to use. .PP Available in Postfix version 2.2 and later: .IP "\fBsmtp_sasl_mechanism_filter (empty)\fR" -If non-empty, filters the SMTP server's list of offered SASL mechanisms. +If non-empty, a Postfix SMTP client filter for the remote SMTP +server's list of offered SASL mechanisms. .SH "RESOURCE AND RATE CONTROLS" .na .nf diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 1ced6c059..433b64bcc 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -3730,11 +3730,12 @@ smtp_sasl_security_options = noplaintext %PARAM smtp_sasl_mechanism_filter

-If non-empty, filters the SMTP server's list of offered SASL mechanisms. -Different client and server implementations may support different -mechanism lists. By default, the client will use the intersection of the -two. smtp_sasl_mechanism_filter further restricts what server mechanisms -the client will take into consideration.

+If non-empty, a Postfix SMTP client filter for the remote SMTP +server's list of offered SASL mechanisms. Different client and +server implementations may support different mechanism lists. By +default, the Postfix SMTP client will use the intersection of the +two. smtp_sasl_mechanism_filter further restricts what server +mechanisms the client will take into consideration.

Specify mechanism names, "/file/name" patterns or "type:table" lookup tables. The right-hand side result from "type:table" lookups diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 4adf152e8..0f23fb940 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -1070,6 +1070,7 @@ mkmap_open.o: ../../include/argv.h mkmap_open.o: ../../include/dict_db.h mkmap_open.o: ../../include/dict_cdb.h mkmap_open.o: ../../include/dict_dbm.h +mkmap_open.o: ../../include/dict_sdbm.h mkmap_open.o: ../../include/sigdelay.h mkmap_open.o: ../../include/mymalloc.h mkmap_open.o: mkmap.h diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 2361aaba1..bf355f8ed 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change the patchlevel and the release date. Snapshots change the * release date only. */ -#define MAIL_RELEASE_DATE "20041211" +#define MAIL_RELEASE_DATE "20041215" #define MAIL_VERSION_NUMBER "2.2" #define VAR_MAIL_VERSION "mail_version" diff --git a/postfix/src/global/mkmap.h b/postfix/src/global/mkmap.h index 848dbc003..45e32c69c 100644 --- a/postfix/src/global/mkmap.h +++ b/postfix/src/global/mkmap.h @@ -39,6 +39,7 @@ extern MKMAP *mkmap_dbm_open(const char *); extern MKMAP *mkmap_cdb_open(const char *); extern MKMAP *mkmap_hash_open(const char *); extern MKMAP *mkmap_btree_open(const char *); +extern MKMAP *mkmap_sdbm_open(const char *); /* LICENSE /* .ad diff --git a/postfix/src/global/mkmap_open.c b/postfix/src/global/mkmap_open.c index 92ed0f96c..a3caf952f 100644 --- a/postfix/src/global/mkmap_open.c +++ b/postfix/src/global/mkmap_open.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index 07567361d..8da57e1e2 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -89,6 +89,9 @@ /* .IP "\fBregexp\fR (read-only)" /* A lookup table based on regular expressions. The file format is /* described in \fBregexp_table\fR(5). +/* .IP \fBsdbm\fR +/* An indexed file type based on hashing. +/* This is available only on systems with support for SDBM databases. /* .IP "\fBstatic\fR (read-only)" /* A table that always returns its name as lookup result. For example, /* \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 0ecc7140e..9ffad1b5c 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -141,7 +141,8 @@ /* .PP /* Available in Postfix version 2.2 and later: /* .IP "\fBsmtp_sasl_mechanism_filter (empty)\fR" -/* If non-empty, filters the SMTP server's list of offered SASL mechanisms. +/* If non-empty, a Postfix SMTP client filter for the remote SMTP +/* server's list of offered SASL mechanisms. /* RESOURCE AND RATE CONTROLS /* .ad /* .fi diff --git a/postfix/src/util/dict_dbm.c b/postfix/src/util/dict_dbm.c index fa58ad004..87e527694 100644 --- a/postfix/src/util/dict_dbm.c +++ b/postfix/src/util/dict_dbm.c @@ -213,7 +213,6 @@ static int dict_dbm_delete(DICT *dict, const char *name) DICT_DBM *dict_dbm = (DICT_DBM *) dict; datum dbm_key; int status = 1; - int flags = 0; /* * Sanity check. @@ -281,7 +280,6 @@ static int dict_dbm_sequence(DICT *dict, int function, DICT_DBM *dict_dbm = (DICT_DBM *) dict; datum dbm_key; datum dbm_value; - int status = 0; /* * Acquire a shared lock. @@ -304,13 +302,6 @@ static int dict_dbm_sequence(DICT *dict, int function, msg_panic("%s: invalid function: %d", myname, function); } - /* - * Release the shared lock. - */ - if ((dict->flags & DICT_FLAG_LOCK) - && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) - msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name); - if (dbm_key.dptr != 0 && dbm_key.dsize > 0) { /* @@ -349,6 +340,14 @@ static int dict_dbm_sequence(DICT *dict, int function, msg_fatal("error seeking %s: %m", dict_dbm->dict.name); return (1); /* no error: eof/not found */ } + + /* + * Release the shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) + msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name); + return (0); } diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index 008d3becb..0a1ff93ab 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -42,6 +42,8 @@ /* dict_open_register(type, open) /* char *type; /* DICT *(*open) (const char *, int, int); +/* +/* ARGV *dict_mapnames() /* DESCRIPTION /* This module implements a low-level interface to multiple /* physical dictionary types. @@ -135,6 +137,9 @@ /* associated data structures. /* /* dict_open_register() adds support for a new dictionary type. +/* +/* dict_mapnames() returns a sorted list with the names of all available +/* dictionary types. /* DIAGNOSTICS /* Fatal error: open error, unsupported dictionary type, attempt to /* update non-writable dictionary. @@ -153,6 +158,7 @@ #include #include +#include #ifdef STRCASECMP_IN_STRINGS_H #include @@ -302,6 +308,13 @@ void dict_open_register(const char *type, htable_enter(dict_open_hash, dp->type, (char *) dp); } +/* dict_sort_alpha_cpp - qsort() callback */ + +static int dict_sort_alpha_cpp(const void *a, const void *b) +{ + return (strcmp(((char **) a)[0], ((char **) b)[0])); +} + /* dict_mapnames - return an ARGV of available map_names */ ARGV *dict_mapnames() @@ -318,6 +331,8 @@ ARGV *dict_mapnames() dp = (DICT_OPEN_INFO *) ht[0]->value; argv_add(mapnames, dp->type, ARGV_END); } + qsort((void *) mapnames->argv, mapnames->argc, sizeof(mapnames->argv[0]), + dict_sort_alpha_cpp); myfree((char *) ht_info); argv_terminate(mapnames); return mapnames; diff --git a/postfix/src/util/dict_sdbm.c b/postfix/src/util/dict_sdbm.c index d123fcf8d..35ee7782e 100644 --- a/postfix/src/util/dict_sdbm.c +++ b/postfix/src/util/dict_sdbm.c @@ -60,9 +60,13 @@ typedef struct { DICT dict; /* generic members */ SDBM *dbm; /* open database */ - char *path; /* pathname */ + VSTRING *key_buf; /* key buffer */ + VSTRING *val_buf; /* result buffer */ } DICT_SDBM; +#define SCOPY(buf, data, size) \ + vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size)) + /* dict_sdbm_lookup - find database entry */ static const char *dict_sdbm_lookup(DICT *dict, const char *name) @@ -70,9 +74,14 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; datum dbm_key; datum dbm_value; - static VSTRING *buf; const char *result = 0; + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + msg_panic("dict_sdbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); + dict_errno = 0; /* @@ -80,7 +89,7 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0) - msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name); /* * See if this DBM file was written with one null byte appended to key @@ -92,7 +101,7 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key); if (dbm_value.dptr != 0) { dict->flags &= ~DICT_FLAG_TRY0NULL; - result = dbm_value.dptr; + result = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize); } } @@ -105,11 +114,8 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) dbm_key.dsize = strlen(name); dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key); if (dbm_value.dptr != 0) { - if (buf == 0) - buf = vstring_alloc(10); - vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize); dict->flags &= ~DICT_FLAG_TRY1NULL; - result = vstring_str(buf); + result = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize); } } @@ -118,7 +124,7 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) - msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name); return (result); } @@ -132,6 +138,12 @@ static void dict_sdbm_update(DICT *dict, const char *name, const char *value) datum dbm_value; int status; + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + msg_panic("dict_sdbm_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); + dbm_key.dptr = (void *) name; dbm_value.dptr = (void *) value; dbm_key.dsize = strlen(name); @@ -163,21 +175,21 @@ static void dict_sdbm_update(DICT *dict, const char *name, const char *value) */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) - msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name); /* * Do the update. */ if ((status = sdbm_store(dict_sdbm->dbm, dbm_key, dbm_value, (dict->flags & DICT_FLAG_DUP_REPLACE) ? DBM_REPLACE : DBM_INSERT)) < 0) - msg_fatal("error writing SDBM database %s: %m", dict_sdbm->path); + msg_fatal("error writing SDBM database %s: %m", dict_sdbm->dict.name); if (status) { if (dict->flags & DICT_FLAG_DUP_IGNORE) /* void */ ; else if (dict->flags & DICT_FLAG_DUP_WARN) - msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->path, name); + msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->dict.name, name); else - msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->path, name); + msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->dict.name, name); } /* @@ -185,10 +197,9 @@ static void dict_sdbm_update(DICT *dict, const char *name, const char *value) */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) - msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name); } - /* dict_sdbm_delete - delete one entry from the dictionary */ static int dict_sdbm_delete(DICT *dict, const char *name) @@ -196,14 +207,19 @@ static int dict_sdbm_delete(DICT *dict, const char *name) DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; datum dbm_key; int status = 1; - int flags = 0; + + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + msg_panic("dict_sdbm_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); /* * Acquire an exclusive lock. */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) - msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name); /* * See if this DBM file was written with one null byte appended to key @@ -214,8 +230,8 @@ static int dict_sdbm_delete(DICT *dict, const char *name) dbm_key.dsize = strlen(name) + 1; sdbm_clearerr(dict_sdbm->dbm); if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) { - if (sdbm_error(dict_sdbm->dbm) != 0) /* fatal error */ - msg_fatal("error deleting from %s: %m", dict_sdbm->path); + if (sdbm_error(dict_sdbm->dbm) != 0)/* fatal error */ + msg_fatal("error deleting from %s: %m", dict_sdbm->dict.name); status = 1; /* not found */ } else { dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */ @@ -231,8 +247,8 @@ static int dict_sdbm_delete(DICT *dict, const char *name) dbm_key.dsize = strlen(name); sdbm_clearerr(dict_sdbm->dbm); if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) { - if (sdbm_error(dict_sdbm->dbm) != 0) /* fatal error */ - msg_fatal("error deleting from %s: %m", dict_sdbm->path); + if (sdbm_error(dict_sdbm->dbm) != 0)/* fatal error */ + msg_fatal("error deleting from %s: %m", dict_sdbm->dict.name); status = 1; /* not found */ } else { dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */ @@ -244,7 +260,7 @@ static int dict_sdbm_delete(DICT *dict, const char *name) */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) - msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name); return (status); } @@ -252,26 +268,24 @@ static int dict_sdbm_delete(DICT *dict, const char *name) /* traverse the dictionary */ static int dict_sdbm_sequence(DICT *dict, const int function, - const char **key, const char **value) + const char **key, const char **value) { char *myname = "dict_sdbm_sequence"; DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; datum dbm_key; datum dbm_value; - int status = 0; - static VSTRING *key_buf; - static VSTRING *value_buf; /* * Acquire a shared lock. */ if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0) - msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); + msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name); /* * Determine and execute the seek function. It returns the key. */ + sdbm_clearerr(dict_sdbm->dbm); switch (function) { case DICT_SEQ_FUN_FIRST: dbm_key = sdbm_firstkey(dict_sdbm->dbm); @@ -283,27 +297,12 @@ static int dict_sdbm_sequence(DICT *dict, const int function, msg_panic("%s: invalid function: %d", myname, function); } - /* - * Release the shared lock. - */ - if ((dict->flags & DICT_FLAG_LOCK) - && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) - msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); - if (dbm_key.dptr != 0 && dbm_key.dsize > 0) { /* - * See if this DB file was written with one null byte appended to key - * and value or not. If necessary, copy the key. + * Copy the key so that it is guaranteed null terminated. */ - if (((char *) dbm_key.dptr)[dbm_key.dsize - 1] == 0) { - *key = dbm_key.dptr; - } else { - if (key_buf == 0) - key_buf = vstring_alloc(10); - vstring_strncpy(key_buf, dbm_key.dptr, dbm_key.dsize); - *key = vstring_str(key_buf); - } + *key = SCOPY(dict_sdbm->key_buf, dbm_key.dptr, dbm_key.dsize); /* * Fetch the corresponding value. @@ -313,17 +312,9 @@ static int dict_sdbm_sequence(DICT *dict, const int function, if (dbm_value.dptr != 0 && dbm_value.dsize > 0) { /* - * See if this DB file was written with one null byte appended to - * key and value or not. If necessary, copy the key. + * Copy the value so that it is guaranteed null terminated. */ - if (((char *) dbm_value.dptr)[dbm_value.dsize - 1] == 0) { - *value = dbm_value.dptr; - } else { - if (value_buf == 0) - value_buf = vstring_alloc(10); - vstring_strncpy(value_buf, dbm_value.dptr, dbm_value.dsize); - *value = vstring_str(value_buf); - } + *value = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize); } else { /* @@ -331,7 +322,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function, * condition. */ if (sdbm_error(dict_sdbm->dbm)) - msg_fatal("error seeking %s: %m", dict_sdbm->path); + msg_fatal("error seeking %s: %m", dict_sdbm->dict.name); return (1); /* no error: eof/not found * (should not happen!) */ } @@ -341,9 +332,17 @@ static int dict_sdbm_sequence(DICT *dict, const int function, * Determine if we have hit the last record or an error condition. */ if (sdbm_error(dict_sdbm->dbm)) - msg_fatal("error seeking %s: %m", dict_sdbm->path); + msg_fatal("error seeking %s: %m", dict_sdbm->dict.name); return (1); /* no error: eof/not found */ } + + /* + * Release the shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) + msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name); + return (0); } @@ -354,8 +353,11 @@ static void dict_sdbm_close(DICT *dict) DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; sdbm_close(dict_sdbm->dbm); - myfree(dict_sdbm->path); - myfree((char *) dict_sdbm); + if (dict_sdbm->key_buf) + vstring_free(dict_sdbm->key_buf); + if (dict_sdbm->val_buf) + vstring_free(dict_sdbm->val_buf); + dict_free(dict); } /* dict_sdbm_open - open SDBM data base */ @@ -368,8 +370,15 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) char *dbm_path; int lock_fd; + /* + * Note: DICT_FLAG_LOCK is used only by programs that do fine-grained (in + * the time domain) locking while accessing individual database records. + * + * Programs such as postmap/postalias use their own large-grained (in the + * time domain) locks while rewriting the entire file. + */ if (dict_flags & DICT_FLAG_LOCK) { - dbm_path = concatenate(path, ".pag", (char *) 0); + dbm_path = concatenate(path, ".dir", (char *) 0); if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0) msg_fatal("open database %s: %m", dbm_path); if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0) @@ -387,9 +396,8 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) msg_fatal("unlock database %s for open: %m", dbm_path); if (close(lock_fd) < 0) msg_fatal("close database %s: %m", dbm_path); - myfree(dbm_path); } - dict_sdbm = (DICT_SDBM *) mymalloc(sizeof(*dict_sdbm)); + dict_sdbm = (DICT_SDBM *) dict_alloc(DICT_TYPE_SDBM, path, sizeof(*dict_sdbm)); dict_sdbm->dict.lookup = dict_sdbm_lookup; dict_sdbm->dict.update = dict_sdbm_update; dict_sdbm->dict.delete = dict_sdbm_delete; @@ -400,15 +408,30 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) if (fstat(dict_sdbm->dict.stat_fd, &st) < 0) msg_fatal("dict_sdbm_open: fstat: %m"); dict_sdbm->dict.mtime = st.st_mtime; + + /* + * Warn if the source file is newer than the indexed file, except when + * the source file changed only seconds ago. + */ + if ((dict_flags & DICT_FLAG_LOCK) != 0 + && stat(path, &st) == 0 + && st.st_mtime > dict_sdbm->dict.mtime + && st.st_mtime < time((time_t *) 0) - 100) + msg_warn("database %s is older than source file %s", dbm_path, path); + close_on_exec(sdbm_pagfno(dbm), CLOSE_ON_EXEC); close_on_exec(sdbm_dirfno(dbm), CLOSE_ON_EXEC); dict_sdbm->dict.flags = dict_flags | DICT_FLAG_FIXED; if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0) dict_sdbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL); dict_sdbm->dbm = dbm; - dict_sdbm->path = mystrdup(path); + dict_sdbm->key_buf = 0; + dict_sdbm->val_buf = 0; + + if ((dict_flags & DICT_FLAG_LOCK)) + myfree(dbm_path); - return (&dict_sdbm->dict); + return (DICT_DEBUG (&dict_sdbm->dict)); } #endif