From: Wietse Venema Date: Fri, 9 Apr 1999 05:00:00 +0000 (-0500) Subject: snapshot-19990409 X-Git-Tag: v20010228~118 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=752a3e3c6bca7bc50a5f1ec747ec5826e48323b4;p=thirdparty%2Fpostfix.git snapshot-19990409 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/HISTORY b/postfix/HISTORY index 86c376ed9..4531b2e4e 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -2568,12 +2568,34 @@ Apologies for any names omitted. Portability: on LINUX systems, if exists, don't look for . - Workaround: on Solaris 2.x, don't put an flock()/fcntl() lock - on mailboxes, to avoid clashes with the mailtool application. + Workaround: specify "sun_mailtool_compatibility = yes" to + avoid clashes with the mailtool application. This disables + kernel locks on mailbox files. Use only where needed. Portability: renamed readline to readlline, to avoid clashes with mysql. +19990409 + + Bugfix: ignore temp queue files that aren't old enough. + Problem reported by Vivek Khera, Khera Communications, Inc. + + Bugfix: fixed typo in dict_db.c that caused processes to + not release DB shared locks. + + Feature: auto-detection of changes to DB or DBM lookup + tables. This avoids the need to run "postfix reload" after + change to the smtp access table and other tables. + + Feature: regular expression checks for message headers. + This requires support for POSIX or for PCRE regular + expressions. Specify "header_checks = regexp:/file/name" + or "header_checks = pcre:/file/name", and specify + "/^header-name: badstuff/ REJECT" in the pattern file + (patterns are case-insensitive by default). Code by Lamont + Jones, Hewlett-Packard. It is to be expected that full + content filtering will be delegated to an external command. + Future: Planned: must be able to list the same hash table in diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 19725e192..49cdc0412 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,4 +1,4 @@ -Incompatible changes with snapshot-19990408: +Incompatible changes with snapshot-19990409: =========================================== - If an address extension (+foo) matches a user's .forward+foo file @@ -6,22 +6,35 @@ name, the +foo extension is no longer appended to recipient addresses listed in the .forward+foo file. This is more consistent with the way Postfix expands aliases. -Major changes with snapshot-19990408: +Major changes with snapshot-19990409: ===================================== In addition to several little bugfixes, none related to security, lots of internal code cleanup, lots of new functionality, and lots of Solaris workarounds. +- POSIX regular expression support, enabled by default on 4.4BSD, +LINUX, and HP-UX. See conf/sample-regexp.cf. Initial code by Lamont +Jones, Hewlett-Packard, borrowing heavily from the PCRE implementation +by Andrew McNamara, connect.com.au Pty. Ltd., Australia. + +- Regular expression checks for message headers. This requires +support for POSIX or for PCRE regular expressions. Specify +"header_checks = regexp:/file/name" or "header_checks = pcre:/file/name", +and specify "/^header-name: badstuff/ REJECT" in the pattern file +(patterns are case-insensitive by default). Code by Lamont Jones, +Hewlett-Packard. It is to be expected that full content filtering +will be delegated to an external command. + - Regular expression support for all lookup tables, including access control (full mail addresses only), address rewriting (canonical/virtual, full mail addresses only) and transport tables (full domain names only). However, regular expressions are not allowed for aliases. -- POSIX regular expression support, enabled by default on 4.4BSD, -LINUX, and HP-UX. See conf/sample-regexp.cf. Initial code by Lamont -Jones, Hewlett-Packard, borrowing heavily from the PCRE implementation -by Andrew McNamara, connect.com.au Pty. Ltd., Australia. +- Automatic detection of changes to DB or DBM lookup tables. This +eliminates the need to run "postfix reload" after each change to +the SMTP access table, or to the canonical, virtual, transport or +aliases tables. - forward_path configuration parameter for .forward files (default: $home/.forward$recipient_delimiter$extension,$home/.forward). @@ -34,8 +47,8 @@ Solaris UNIX-domain sockets, because they are still broken, even with Solaris 7. - Workaround for the Solaris mailtool, which keeps an exclusive -fcntl/flock lock on the mailbox while its window is not iconified -(specify "deliver_lock_disable = yes" in main.cf). +kernel lock on the mailbox while its window is not iconified (specify +"sun_mailtool_compatibility = yes" in main.cf). - Questionable workaround for Solaris, which reportedly loses long-lived exclusive locks that are held by the master daemon. diff --git a/postfix/bounce/.indent.pro b/postfix/bounce/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/bounce/.indent.pro +++ b/postfix/bounce/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/cleanup/.indent.pro b/postfix/cleanup/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/cleanup/.indent.pro +++ b/postfix/cleanup/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/cleanup/cleanup.c b/postfix/cleanup/cleanup.c index 7666077f9..367693634 100644 --- a/postfix/cleanup/cleanup.c +++ b/postfix/cleanup/cleanup.c @@ -129,6 +129,7 @@ #include #include #include +#include /* Global library. */ @@ -167,6 +168,7 @@ char *var_rcpt_canon_maps; /* recipient canonical maps */ char *var_virtual_maps; /* virtual maps */ char *var_masq_domains; /* masquerade domains */ char *var_masq_exceptions; /* users not masqueraded */ +char *var_header_checks; /* any header checks */ int var_dup_filter_limit; /* recipient dup filter */ char *var_empty_addr; /* destination of bounced bounces */ int var_delay_warn_time; /* delay that triggers warning */ @@ -177,6 +179,7 @@ int var_delay_warn_time; /* delay that triggers warning */ MAPS *cleanup_comm_canon_maps; MAPS *cleanup_send_canon_maps; MAPS *cleanup_rcpt_canon_maps; +MAPS *cleanup_header_checks; MAPS *cleanup_virtual_maps; ARGV *cleanup_masq_domains; @@ -389,6 +392,19 @@ static void pre_jail_init(void) DICT_FLAG_LOCK); if (*var_masq_domains) cleanup_masq_domains = argv_split(var_masq_domains, " ,\t\r\n"); + if (*var_header_checks) + cleanup_header_checks = + maps_create(VAR_HEADER_CHECKS, var_header_checks, DICT_FLAG_LOCK); +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } } /* post_jail_init - initialize after entering the chroot jail */ @@ -426,6 +442,7 @@ int main(int argc, char **argv) VAR_MASQ_DOMAINS, DEF_MASQ_DOMAINS, &var_masq_domains, 0, 0, VAR_EMPTY_ADDR, DEF_EMPTY_ADDR, &var_empty_addr, 1, 0, VAR_MASQ_EXCEPTIONS, DEF_MASQ_EXCEPTIONS, &var_masq_exceptions, 0, 0, + VAR_HEADER_CHECKS, DEF_HEADER_CHECKS, &var_header_checks, 0, 0, 0, }; @@ -444,5 +461,6 @@ int main(int argc, char **argv) MAIL_SERVER_STR_TABLE, str_table, MAIL_SERVER_PRE_INIT, pre_jail_init, MAIL_SERVER_POST_INIT, post_jail_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/cleanup/cleanup.h b/postfix/cleanup/cleanup.h index 56e42c28f..7523262c6 100644 --- a/postfix/cleanup/cleanup.h +++ b/postfix/cleanup/cleanup.h @@ -61,6 +61,7 @@ extern BH_TABLE *cleanup_dups; /* recipient dup filter */ extern MAPS *cleanup_comm_canon_maps; extern MAPS *cleanup_send_canon_maps; extern MAPS *cleanup_rcpt_canon_maps; +extern MAPS *cleanup_header_checks; extern MAPS *cleanup_virtual_maps; extern ARGV *cleanup_masq_domains; diff --git a/postfix/cleanup/cleanup_message.c b/postfix/cleanup/cleanup_message.c index 3e5d1dce1..67a679197 100644 --- a/postfix/cleanup/cleanup_message.c +++ b/postfix/cleanup/cleanup_message.c @@ -223,8 +223,23 @@ static void cleanup_rewrite_recip(HEADER_OPTS *hdr_opts) static void cleanup_header(void) { + char *myname = "cleanup_header"; HEADER_OPTS *hdr_opts; + if (msg_verbose) + msg_info("%s: '%s'", myname, vstring_str(cleanup_header_buf)); + + if (cleanup_header_checks) { + char *header = vstring_str(cleanup_header_buf); + const char *value; + + if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) { + if (strcasecmp(value, "REJECT") == 0) { + msg_warn("%s: reject: header %.100s", cleanup_queue_id, header); + cleanup_errs |= CLEANUP_STAT_CONT; + } + } + } /* * If this is an "unknown" header, just copy it to the output without diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index d47113a76..992cc849f 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -259,6 +259,14 @@ program_directory = /some/where/postfix/bin # The controls listed here are only a very small subset. See the file # sample-smtpd.cf for an elaborate list of anti-UCE controls. +# The header_checks parameter restricts what may appear in message +# headers. This requires that POSIX or PCRE regular expression support +# is built-in. Specify "/^header-name: stuff you don not want/ REJECT" +# in the pattern file. Patterns are case-insensitive by default. +# +#header_checks = regexp:/etc/postfix/filename +#header_checks = pcre:/etc/postfix/filename + # The relay_domains parameter restricts what domains (and subdomains # thereof) this mail system will relay mail from or to. See the # smtpd_recipient_restrictions restriction in the file sample-smtpd.cf. diff --git a/postfix/conf/main.cf.default b/postfix/conf/main.cf.default index 6f6e351eb..20a1312bb 100644 --- a/postfix/conf/main.cf.default +++ b/postfix/conf/main.cf.default @@ -30,7 +30,6 @@ delay_notice_recipient = postmaster delay_warning_time = 0 deliver_lock_attempts = 5 deliver_lock_delay = 1 -deliver_lock_disable = no disable_dns_lookups = no dont_remove = 0 double_bounce_sender = double-bounce @@ -44,6 +43,7 @@ fork_delay = 1 forward_path = $home/.forward${recipient_delimiter}${extension},$home/.forward hash_queue_depth = 2 hash_queue_names = defer +header_checks = header_size_limit = 102400 home_mailbox = hopcount_limit = 50 @@ -61,7 +61,7 @@ luser_relay = mail_name = Postfix mail_owner = postfix mail_spool_directory = /var/mail -mail_version = Snapshot-19990408 +mail_version = Snapshot-19990409 mailbox_command = mailbox_transport = maps_rbl_domains = rbl.maps.vix.com @@ -122,6 +122,7 @@ smtpd_soft_error_limit = 10 smtpd_timeout = 300 soft_bounce = no stale_lock_time = 500 +sun_mailtool_compatibility = no swap_bangpath = yes transport_maps = transport_retry_time = 60 diff --git a/postfix/conf/sample-misc.cf b/postfix/conf/sample-misc.cf index f6a1a92c8..ca9df2166 100644 --- a/postfix/conf/sample-misc.cf +++ b/postfix/conf/sample-misc.cf @@ -28,15 +28,6 @@ daemon_timeout = 18000 # default_transport = uucp default_transport = smtp -# The deliver_lock_disable parameter disables fcntl/flock file locking -# on mailboxes. This is needed on SUN workstations because the mailtool -# program keeps an exclusive fcntl/flock lock while its window is open. -# SUN software uses user.lock files only. Unless you remove all SUN -# mail software, fcntl/flock just gives a false sense of security. -# -#deliver_lock_disable = yes -deliver_lock_disable = no - # The double_bounce_sender parameter specifies the sender address # for mail that must be discarded when it cannot be delivered. This # must be a unique name. All mail to this name is silently discarded, @@ -266,6 +257,15 @@ relayhost = # relocated_maps = hash:/etc/postfix/relocated relocated_maps = +# The sun_mailtool_compatibility parameter disables kernel file locks +# on mailboxes. This is needed on SUN workstations because the mailtool +# program keeps an exclusive kernel lock while its window is open. +# SUN software uses user.lock files only. Unless you remove all SUN +# mail software, kernel locks just give a false sense of security. +# +#sun_mailtool_compatibility = yes +sun_mailtool_compatibility = no + # The trigger_timeout parameter limits the time to send a trigger to # a Postfix daemon. This prevents programs from getting stuck when the # mail system is under heavy load. diff --git a/postfix/dns/.indent.pro b/postfix/dns/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/dns/.indent.pro +++ b/postfix/dns/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/fsstone/.indent.pro b/postfix/fsstone/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/fsstone/.indent.pro +++ b/postfix/fsstone/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/global/.indent.pro b/postfix/global/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/global/.indent.pro +++ b/postfix/global/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/global/deliver_flock.c b/postfix/global/deliver_flock.c index 7d97dba04..5df58ada3 100644 --- a/postfix/global/deliver_flock.c +++ b/postfix/global/deliver_flock.c @@ -10,7 +10,7 @@ /* int fd; /* VSTRING *why; /* DESCRIPTION -/* deliver_flock() sets one exclusive lock on an open file +/* deliver_flock() sets one exclusive kernel lock on an open file /* for the purpose of mail delivery. It attempts to acquire /* the exclusive lock several times before giving up. /* @@ -26,7 +26,7 @@ /* CONFIGURATION PARAMETERS /* deliver_lock_attempts, number of locking attempts /* deliver_lock_delay, time in seconds between attempts -/* deliver_lock_disable, disable exclusive locking +/* sun_mailtool_compatibility, disable kernel locking /* LICENSE /* .ad /* .fi @@ -59,7 +59,7 @@ int deliver_flock(int fd, VSTRING *why) { int i; - if (var_flock_disable) + if (var_mailtool_compat) return (0); for (i = 0; /* void */ ; i++) { diff --git a/postfix/global/mail_params.c b/postfix/global/mail_params.c index 55862517b..856156a92 100644 --- a/postfix/global/mail_params.c +++ b/postfix/global/mail_params.c @@ -51,7 +51,7 @@ /* int var_flock_tries; /* int var_flock_delay; /* int var_flock_stale; -/* int var_flock_disable; +/* int var_mailtool_compat; /* int var_disable_dns; /* int var_soft_bounce; /* time_t var_starttime; @@ -154,7 +154,7 @@ int var_fork_delay; int var_flock_tries; int var_flock_delay; int var_flock_stale; -int var_flock_disable; +int var_mailtool_compat; int var_disable_dns; int var_soft_bounce; time_t var_starttime; @@ -280,7 +280,7 @@ void mail_params_init() VAR_DISABLE_DNS, DEF_DISABLE_DNS, &var_disable_dns, VAR_SOFT_BOUNCE, DEF_SOFT_BOUNCE, &var_soft_bounce, VAR_OWNREQ_SPECIAL, DEF_OWNREQ_SPECIAL, &var_ownreq_special, - VAR_FLOCK_DISABLE, DEF_FLOCK_DISABLE, &var_flock_disable, + VAR_MAILTOOL_COMPAT, DEF_MAILTOOL_COMPAT, &var_mailtool_compat, 0, }; diff --git a/postfix/global/mail_params.h b/postfix/global/mail_params.h index a91c0feca..2c4a5280c 100644 --- a/postfix/global/mail_params.h +++ b/postfix/global/mail_params.h @@ -590,6 +590,10 @@ extern int var_message_limit; #define DEF_QUEUE_MINFREE 0 extern int var_queue_minfree; +#define VAR_HEADER_CHECKS "header_checks" +#define DEF_HEADER_CHECKS "" +extern char *var_header_checks; + /* * Bounce service: truncate bounce message that exceed $bounce_size_limit. */ @@ -631,9 +635,9 @@ extern int var_flock_delay; #define DEF_FLOCK_STALE 500 extern int var_flock_stale; -#define VAR_FLOCK_DISABLE "deliver_lock_disable" -#define DEF_FLOCK_DISABLE 0 -extern int var_flock_disable; +#define VAR_MAILTOOL_COMPAT "sun_mailtool_compatibility" +#define DEF_MAILTOOL_COMPAT 0 +extern int var_mailtool_compat; /* * How long a daemon command may take to receive or deliver a message etc. diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index f4fb16867..2e4b49c4c 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-19990408" +#define DEF_MAIL_VERSION "Snapshot-19990409" extern char *var_mail_version; /* LICENSE diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 8a93bbf86..4fd756000 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -44,6 +44,10 @@ command. + + +

Header filtering

+ +The header_checks parameter restricts what +is allowed in message headers. + +

+ +

+ +
Default: + +
Allow anything in message headers. + +

+ +

Syntax: + +
Specify a list of zero or more lookup tables. Whenever a +header matches a table, a REJECT result means reject the +message; an OK result means pass. + +
+ +

+ +

Examples: + +
header_checks = regexp:/etc/postfix/header_checks + +
header_checks = pcre:/etc/postfix/header_checks + +

+

Client name/address restrictions

diff --git a/postfix/local/.indent.pro b/postfix/local/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/local/.indent.pro +++ b/postfix/local/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/local/local.c b/postfix/local/local.c index ad1951a31..09d21b1d3 100644 --- a/postfix/local/local.c +++ b/postfix/local/local.c @@ -337,6 +337,7 @@ #include #include #include +#include /* Global library. */ @@ -501,6 +502,16 @@ static void local_mask_init(void) local_cmd_deliver_mask = name_mask(command_mask, var_allow_commands); } +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + /* post_init - post-jail initialization */ static void post_init(void) @@ -553,5 +564,6 @@ int main(int argc, char **argv) MAIL_SERVER_RAW_TABLE, raw_table, MAIL_SERVER_BOOL_TABLE, bool_table, MAIL_SERVER_POST_INIT, post_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/master/.indent.pro b/postfix/master/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/master/.indent.pro +++ b/postfix/master/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/master/mail_server.h b/postfix/master/mail_server.h index c5f9b83ab..9bf37117c 100644 --- a/postfix/master/mail_server.h +++ b/postfix/master/mail_server.h @@ -25,10 +25,12 @@ #define MAIL_SERVER_POST_INIT 11 #define MAIL_SERVER_LOOP 12 #define MAIL_SERVER_EXIT 13 +#define MAIL_SERVER_PRE_ACCEPT 14 typedef void (*MAIL_SERVER_INIT_FN) (void); typedef int (*MAIL_SERVER_LOOP_FN) (void); typedef void (*MAIL_SERVER_EXIT_FN) (void); +typedef void (*MAIL_SERVER_ACCEPT_FN) (void); /* * single_server.c diff --git a/postfix/master/multi_server.c b/postfix/master/multi_server.c index 0e8eb368b..2f2cb4909 100644 --- a/postfix/master/multi_server.c +++ b/postfix/master/multi_server.c @@ -80,6 +80,8 @@ /* .IP "MAIL_SERVER_EXIT (void *(void))" /* A pointer to function that is executed immediately before normal /* process termination. +/* .IP "MAIL_SERVER_PRE_ACCEPT (void *(void))" +/* Function to be executed prior to accepting a new connection. /* .PP /* multi_server_disconnect() should be called by the application /* when a client disconnects. @@ -171,6 +173,7 @@ static char *multi_server_name; static char **multi_server_argv; static void (*multi_server_accept) (int, char *); static void (*multi_server_onexit) (void); +static void (*multi_server_pre_accept) (void); static VSTREAM *multi_server_lock; /* multi_server_exit - normal termination */ @@ -287,6 +290,8 @@ static void multi_server_accept_local(int unused_event, char *context) if (client_count == 0 && var_idle_limit > 0) time_left = event_cancel_timer(multi_server_timeout, (char *) 0); + if (multi_server_pre_accept) + multi_server_pre_accept(); fd = LOCAL_ACCEPT(listen_fd); if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0) @@ -422,6 +427,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) case MAIL_SERVER_EXIT: multi_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN); break; + case MAIL_SERVER_PRE_ACCEPT: + multi_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); + break; default: msg_panic("%s: unknown argument type: %d", myname, key); } diff --git a/postfix/master/single_server.c b/postfix/master/single_server.c index 8f37acd4d..b3084ab1a 100644 --- a/postfix/master/single_server.c +++ b/postfix/master/single_server.c @@ -75,6 +75,8 @@ /* .IP "MAIL_SERVER_EXIT (void *(void))" /* A pointer to function that is executed immediately before normal /* process termination. +/* .IP "MAIL_SERVER_PRE_ACCEPT (void *(void))" +/* Function to be executed prior to accepting a new connection. /* .PP /* The var_use_limit variable limits the number of clients that /* a server can service before it commits suicide. @@ -161,6 +163,7 @@ static char *single_server_name; static char **single_server_argv; static void (*single_server_accept) (int, char *); static void (*single_server_onexit) (void); +static void (*single_server_pre_accept) (void); static VSTREAM *single_server_lock; /* single_server_exit - normal termination */ @@ -257,6 +260,8 @@ static void single_server_accept_local(int unused_event, char *context) if (var_idle_limit > 0) time_left = event_cancel_timer(single_server_timeout, (char *) 0); + if (single_server_pre_accept) + single_server_pre_accept(); fd = LOCAL_ACCEPT(listen_fd); if (single_server_lock != 0 && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0) @@ -391,6 +396,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) case MAIL_SERVER_EXIT: single_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN); break; + case MAIL_SERVER_PRE_ACCEPT: + single_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); + break; default: msg_panic("%s: unknown argument type: %d", myname, key); } diff --git a/postfix/master/trigger_server.c b/postfix/master/trigger_server.c index 2b5761b3b..1434617e7 100644 --- a/postfix/master/trigger_server.c +++ b/postfix/master/trigger_server.c @@ -82,6 +82,8 @@ /* .IP "MAIL_SERVER_EXIT (void *(void))" /* A pointer to function that is executed immediately before normal /* process termination. +/* .IP "MAIL_SERVER_PRE_ACCEPT (void *(void))" +/* Function to be executed prior to accepting a new request. /* .PP /* The var_use_limit variable limits the number of clients that /* a server can service before it commits suicide. @@ -168,6 +170,7 @@ static char *trigger_server_name; static char **trigger_server_argv; static void (*trigger_server_accept) (int, char *); static void (*trigger_server_onexit) (void); +static void (*trigger_server_pre_accept) (void); static VSTREAM *trigger_server_lock; /* trigger_server_exit - normal termination */ @@ -256,6 +259,8 @@ static void trigger_server_accept_fifo(int unused_event, char *context) * Read whatever the other side wrote into the FIFO. The FIFO read end is * non-blocking so we won't get stuck when multiple processes wake up. */ + if (trigger_server_pre_accept) + trigger_server_pre_accept(); trigger_server_wakeup(listen_fd); } @@ -288,6 +293,8 @@ static void trigger_server_accept_local(int unused_event, char *context) if (var_idle_limit > 0) time_left = event_cancel_timer(trigger_server_timeout, (char *) 0); + if (trigger_server_pre_accept) + trigger_server_pre_accept(); fd = LOCAL_ACCEPT(listen_fd); if (trigger_server_lock != 0 && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0) @@ -392,6 +399,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. case MAIL_SERVER_EXIT: trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN); break; + case MAIL_SERVER_PRE_ACCEPT: + trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); + break; default: msg_panic("%s: unknown argument type: %d", myname, key); } diff --git a/postfix/pickup/.indent.pro b/postfix/pickup/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/pickup/.indent.pro +++ b/postfix/pickup/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/pipe/.indent.pro b/postfix/pipe/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/pipe/.indent.pro +++ b/postfix/pipe/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/pipe/pipe.c b/postfix/pipe/pipe.c index 60c5e96a5..cc2750112 100644 --- a/postfix/pipe/pipe.c +++ b/postfix/pipe/pipe.c @@ -675,6 +675,16 @@ static void pipe_service(VSTREAM *client_stream, char *service, char **argv) } } +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + /* drop_privileges - drop privileges most of the time */ static void drop_privileges(void) @@ -694,5 +704,6 @@ int main(int argc, char **argv) single_server_main(argc, argv, pipe_service, MAIL_SERVER_INT_TABLE, int_table, MAIL_SERVER_POST_INIT, drop_privileges, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/postalias/.indent.pro b/postfix/postalias/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postalias/.indent.pro +++ b/postfix/postalias/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postcat/.indent.pro b/postfix/postcat/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postcat/.indent.pro +++ b/postfix/postcat/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postconf/.indent.pro b/postfix/postconf/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postconf/.indent.pro +++ b/postfix/postconf/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postdrop/.indent.pro b/postfix/postdrop/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postdrop/.indent.pro +++ b/postfix/postdrop/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postfix/.indent.pro b/postfix/postfix/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postfix/.indent.pro +++ b/postfix/postfix/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postkick/.indent.pro b/postfix/postkick/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postkick/.indent.pro +++ b/postfix/postkick/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postlock/.indent.pro b/postfix/postlock/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postlock/.indent.pro +++ b/postfix/postlock/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postlog/.indent.pro b/postfix/postlog/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postlog/.indent.pro +++ b/postfix/postlog/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postmap/.indent.pro b/postfix/postmap/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postmap/.indent.pro +++ b/postfix/postmap/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postsuper/.indent.pro b/postfix/postsuper/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/postsuper/.indent.pro +++ b/postfix/postsuper/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/postsuper/postsuper.c b/postfix/postsuper/postsuper.c index 9ebd498cd..b225f84f2 100644 --- a/postfix/postsuper/postsuper.c +++ b/postfix/postsuper/postsuper.c @@ -233,6 +233,12 @@ static void super(char **queues, int action) continue; } + /* + * Skip temporary files that aren't old enough. + */ + if (mail_queue_id_ok(path) == 0) + continue; + /* * See if this file sits in the right place in the file system * hierarchy. Its place may be wrong after a change to the diff --git a/postfix/qmgr/.indent.pro b/postfix/qmgr/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/qmgr/.indent.pro +++ b/postfix/qmgr/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/qmgr/qmgr.c b/postfix/qmgr/qmgr.c index b90ef97e7..22a690f96 100644 --- a/postfix/qmgr/qmgr.c +++ b/postfix/qmgr/qmgr.c @@ -231,6 +231,7 @@ #include #include #include +#include /* Global library. */ @@ -387,6 +388,16 @@ static int qmgr_loop(void) return (WAIT_FOR_EVENT); } +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + /* qmgr_pre_init - pre-jail initialization */ static void qmgr_pre_init(void) @@ -461,5 +472,6 @@ int main(int argc, char **argv) MAIL_SERVER_PRE_INIT, qmgr_pre_init, MAIL_SERVER_POST_INIT, qmgr_post_init, MAIL_SERVER_LOOP, qmgr_loop, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/sendmail/.indent.pro b/postfix/sendmail/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/sendmail/.indent.pro +++ b/postfix/sendmail/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/showq/.indent.pro b/postfix/showq/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/showq/.indent.pro +++ b/postfix/showq/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/smtp/.indent.pro b/postfix/smtp/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/smtp/.indent.pro +++ b/postfix/smtp/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/smtp/smtp.c b/postfix/smtp/smtp.c index 60c840b35..8287e6731 100644 --- a/postfix/smtp/smtp.c +++ b/postfix/smtp/smtp.c @@ -154,6 +154,7 @@ #include #include #include +#include /* Utility library. */ @@ -320,6 +321,16 @@ static void smtp_service(VSTREAM *client_stream, char *unused_service, char **ar } } +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + /* main - pass control to the single-threaded skeleton */ int main(int argc, char **argv) @@ -356,5 +367,6 @@ int main(int argc, char **argv) MAIL_SERVER_STR_TABLE, str_table, MAIL_SERVER_BOOL_TABLE, bool_table, MAIL_SERVER_PRE_INIT, debug_peer_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/smtpd/.indent.pro b/postfix/smtpd/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/smtpd/.indent.pro +++ b/postfix/smtpd/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/smtpd/smtpd.c b/postfix/smtpd/smtpd.c index 80f4b7e54..f7482e4f7 100644 --- a/postfix/smtpd/smtpd.c +++ b/postfix/smtpd/smtpd.c @@ -210,6 +210,7 @@ #include #include #include +#include /* Global library. */ @@ -459,6 +460,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) return (-1); } } + state->time = time((time_t *) 0); if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_mail(state, argv[3].strval)) != 0) { smtpd_chat_reply(state, "%s", err); @@ -712,6 +714,9 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) } else if ((state->err & CLEANUP_STAT_HOPS) != 0) { state->error_mask |= MAIL_ERROR_BOUNCE; smtpd_chat_reply(state, "554 Error: too many hops"); + } else if ((state->err & CLEANUP_STAT_CONT) != 0) { + state->error_mask |= MAIL_ERROR_BOUNCE; + smtpd_chat_reply(state, "552 Error: content rejected"); } else if ((state->err & CLEANUP_STAT_WRITE) != 0) { state->error_mask |= MAIL_ERROR_RESOURCE; smtpd_chat_reply(state, "451 Error: queue file write error"); @@ -1089,6 +1094,16 @@ static void smtpd_sig(int sig) exit(sig); } +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("lookup table has changed -- exiting"); + exit(0); + } +} + /* post_jail_init - post-jail initialization */ static void post_jail_init(void) @@ -1169,5 +1184,6 @@ int main(int argc, char **argv) MAIL_SERVER_BOOL_TABLE, bool_table, MAIL_SERVER_PRE_INIT, pre_jail_init, MAIL_SERVER_POST_INIT, post_jail_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/smtpd/smtpd_state.c b/postfix/smtpd/smtpd_state.c index 27a08437d..ef795d78c 100644 --- a/postfix/smtpd/smtpd_state.c +++ b/postfix/smtpd/smtpd_state.c @@ -78,7 +78,6 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream, state->err = CLEANUP_STAT_OK; state->client = stream; state->buffer = vstring_alloc(100); - state->time = event_time(); state->name = mystrdup(name); state->addr = mystrdup(addr); state->error_count = 0; diff --git a/postfix/smtpstone/.indent.pro b/postfix/smtpstone/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/smtpstone/.indent.pro +++ b/postfix/smtpstone/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/trivial-rewrite/.indent.pro b/postfix/trivial-rewrite/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/trivial-rewrite/.indent.pro +++ b/postfix/trivial-rewrite/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/trivial-rewrite/trivial-rewrite.c b/postfix/trivial-rewrite/trivial-rewrite.c index e9f59b389..161231733 100644 --- a/postfix/trivial-rewrite/trivial-rewrite.c +++ b/postfix/trivial-rewrite/trivial-rewrite.c @@ -120,6 +120,7 @@ #include #include #include +#include /* Global library. */ @@ -182,6 +183,16 @@ static void rewrite_service(VSTREAM *stream, char *unused_service, char **argv) multi_server_disconnect(stream); } +/* pre_accept - see if tables have changed */ + +static void pre_accept(void) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + /* pre_jail_init - initialize before entering chroot jail */ static void pre_jail_init(void) @@ -213,5 +224,6 @@ int main(int argc, char **argv) MAIL_SERVER_STR_TABLE, str_table, MAIL_SERVER_BOOL_TABLE, bool_table, MAIL_SERVER_PRE_INIT, pre_jail_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, 0); } diff --git a/postfix/util/.indent.pro b/postfix/util/.indent.pro index a39288416..7dd2776b0 100644 --- a/postfix/util/.indent.pro +++ b/postfix/util/.indent.pro @@ -99,3 +99,4 @@ -TVSTREAM -TVSTRING -TWAIT_STATUS_T +-TWATCH_FD diff --git a/postfix/util/Makefile.in b/postfix/util/Makefile.in index e50d1e623..74de770ad 100644 --- a/postfix/util/Makefile.in +++ b/postfix/util/Makefile.in @@ -19,7 +19,7 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \ unsafe.c username.c valid_hostname.c vbuf.c vbuf_print.c \ vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \ write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \ - stream_connect.c stream_trigger.c dict_regexp.c + stream_connect.c stream_trigger.c dict_regexp.c watch_fd.c OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \ dict_env.o dict_ht.o dict_ldap.o dict_ni.o dict_nis.o \ @@ -40,7 +40,7 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ unsafe.o username.o valid_hostname.o vbuf.o vbuf_print.o \ vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \ write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \ - stream_connect.o stream_trigger.o dict_regexp.o + stream_connect.o stream_trigger.o dict_regexp.o watch_fd.o HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_ni.h dict_nis.h \ dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \ @@ -54,7 +54,7 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \ timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \ vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \ - dict_unix.h dict_pcre.h dict_regexp.h + dict_unix.h dict_pcre.h dict_regexp.h watch_fd.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -367,6 +367,7 @@ dict_open.o: dict_pcre.h dict_open.o: dict_regexp.h dict_open.o: stringops.h dict_open.o: split_at.h +dict_open.o: htable.h dict_pcre.o: dict_pcre.c dict_pcre.o: sys_defs.h dict_regexp.o: dict_regexp.c @@ -819,6 +820,12 @@ vstring_vstream.o: vstring.h vstring_vstream.o: vbuf.h vstring_vstream.o: vstream.h vstring_vstream.o: vstring_vstream.h +watch_fd.o: watch_fd.c +watch_fd.o: sys_defs.h +watch_fd.o: msg.h +watch_fd.o: binhash.h +watch_fd.o: mymalloc.h +watch_fd.o: watch_fd.h writable.o: writable.c writable.o: sys_defs.h writable.o: msg.h diff --git a/postfix/util/dict.c b/postfix/util/dict.c index f6a1c5f53..f4931aec9 100644 --- a/postfix/util/dict.c +++ b/postfix/util/dict.c @@ -10,35 +10,41 @@ /* extern int dict_errno; /* /* void dict_register(dict_name, dict_info) -/* const const char *dict_name; +/* const char *dict_name; /* DICT *dict_info; /* /* DICT *dict_handle(dict_name) -/* const const char *dict_name; +/* const char *dict_name; /* /* void dict_unregister(dict_name) -/* const const char *dict_name; +/* const char *dict_name; /* /* void dict_update(dict_name, member, value) -/* const const char *dict_name; -/* const const char *member; +/* const char *dict_name; +/* const char *member; /* const char *value; /* /* const char *dict_lookup(dict_name, member) -/* const const char *dict_name; -/* const const char *member; +/* const char *dict_name; +/* const char *member; /* /* const char *dict_eval(dict_name, string, int recursive) -/* const const char *dict_name; +/* const char *dict_name; /* const char *string; /* int recursive; +/* +/* int dict_walk(action, context) +/* void (*action)(dict_name, dict_handle, context) +/* char *context; +/* +/* int dict_changed() /* AUXILIARY FUNCTIONS /* void dict_load_file(dict_name, path) -/* const const char *dict_name; -/* const const char *path; +/* const char *dict_name; +/* const char *path; /* /* void dict_load_fp(dict_name, fp) -/* const const char *dict_name; +/* const char *dict_name; /* FILE *fp; /* DESCRIPTION /* This module maintains a collection of name-value dictionaries. @@ -93,6 +99,19 @@ /* \fIrecursive\fR argument is non-zero, macros references are /* expanded recursively. /* +/* dict_walk() iterates over all registered dictionaries in some +/* arbitrary order, and invokes the specified action routine with +/* as arguments: +/* .IP "const char *dict_name" +/* Dictionary name. +/* .IP "DICT *dict_handle" +/* Generic dictionary handle. +/* .IP "char *context" +/* Application context from the caller. +/* .PP +/* dict_changed() returns non-zero when any dictionary needs to +/* be re-opened because it has changed. +/* /* dict_load_file() reads name-value entries from the named file. /* Lines that begin with whitespace are concatenated to the preceding /* line (the newline is deleted). @@ -128,6 +147,7 @@ /* System libraries. */ #include "sys_defs.h" +#include #include #include #include @@ -415,3 +435,44 @@ const char *dict_eval(const char *dict_name, const char *value, int recursive) return (STR(buf)); } + +/* dict_walk - iterate over all dictionaries in arbitrary order */ + +void dict_walk(DICT_WALK_ACTION action, char *ptr) +{ + HTABLE_INFO **ht_info_list; + HTABLE_INFO **ht; + HTABLE_INFO *h; + + ht_info_list = htable_list(dict_table); + for (ht = ht_info_list; (h = *ht) != 0; ht++) + action(h->key, (DICT *) h->value, ptr); + myfree((char *) ht_info_list); +} + +/* dict_changed - see if any dictionary has changed */ + +int dict_changed(void) +{ + char *myname = "dict_changed"; + struct stat st; + HTABLE_INFO **ht_info_list; + HTABLE_INFO **ht; + HTABLE_INFO *h; + int status; + DICT *dict; + + ht_info_list = htable_list(dict_table); + for (status = 0, ht = ht_info_list; status == 0 && (h = *ht) != 0; ht++) { + dict = ((DICT_NODE *) h->value)->dict; + if (dict->fd < 0) /* not file-based */ + continue; + if (dict->mtime == 0) /* not bloody likely */ + msg_warn("%s: table %s: null time stamp", myname, h->key); + if (fstat(dict->fd, &st) < 0) + msg_fatal("%s: fstat: %m", myname); + status = (st.st_mtime != dict->mtime); + } + myfree((char *) ht_info_list); + return (status); +} diff --git a/postfix/util/dict.h b/postfix/util/dict.h index dc279298d..2dd4d5dc0 100644 --- a/postfix/util/dict.h +++ b/postfix/util/dict.h @@ -31,6 +31,7 @@ typedef struct DICT { void (*update) (struct DICT *, const char *, const char *); void (*close) (struct DICT *); int fd; /* for dict_update() lock */ + time_t mtime; /* mod time at open */ } DICT; #define DICT_FLAG_DUP_WARN (1<<0) /* if file, warn about dups */ @@ -65,10 +66,13 @@ extern const char *dict_eval(const char *, const char *, int); */ extern DICT *dict_open(const char *, int, int); extern DICT *dict_open3(const char *, const char *, int, int); -extern void dict_open_register(const char *, DICT *(*)(const char *, int, int)); +extern void dict_open_register(const char *, DICT *(*) (const char *, int, int)); #define dict_get(dp, key) (dp)->lookup((dp), (key)) #define dict_put(dp, key, val) (dp)->update((dp), (key), (val)) #define dict_close(dp) (dp)->close(dp) +typedef void (*DICT_WALK_ACTION) (const char *, DICT *, char *); +extern void dict_walk(DICT_WALK_ACTION, char *); +extern int dict_changed(void); /* LICENSE /* .ad diff --git a/postfix/util/dict_db.c b/postfix/util/dict_db.c index 693397589..36e3bb969 100644 --- a/postfix/util/dict_db.c +++ b/postfix/util/dict_db.c @@ -48,6 +48,7 @@ /* System library. */ +#include #include #ifdef PATH_DB_H #include PATH_DB_H @@ -134,7 +135,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name) /* * Release the shared lock. */ - if ((dict->fd & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_NONE) < 0) + if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_NONE) < 0) msg_fatal("%s: unlock dictionary: %m", dict_db->path); return (result); @@ -223,6 +224,7 @@ static DICT *dict_db_open(const char *path, int flags, int type, void *tweak, int dict_flags) { DICT_DB *dict_db; + struct stat st; DB *db; char *db_path; @@ -235,6 +237,9 @@ static DICT *dict_db_open(const char *path, int flags, int type, dict_db->dict.update = dict_db_update; dict_db->dict.close = dict_db_close; dict_db->dict.fd = db->fd(db); + if (fstat(dict_db->dict.fd, &st) < 0) + msg_fatal("dict_db_open: fstat: %m"); + dict_db->dict.mtime = st.st_mtime; close_on_exec(dict_db->dict.fd, CLOSE_ON_EXEC); dict_db->dict.flags = dict_flags | DICT_FLAG_FIXED; if ((flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) diff --git a/postfix/util/dict_dbm.c b/postfix/util/dict_dbm.c index 1798202ff..78a73c0c2 100644 --- a/postfix/util/dict_dbm.c +++ b/postfix/util/dict_dbm.c @@ -36,6 +36,7 @@ /* System library. */ +#include #include #include @@ -196,6 +197,7 @@ static void dict_dbm_close(DICT *dict) DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags) { DICT_DBM *dict_dbm; + struct stat st; DBM *dbm; /* @@ -209,6 +211,9 @@ DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags) dict_dbm->dict.update = dict_dbm_update; dict_dbm->dict.close = dict_dbm_close; dict_dbm->dict.fd = dbm_dirfno(dbm); + if (fstat(dict_dbm->dict.fd, &st) < 0) + msg_fatal("dict_dbm_open: fstat: %m"); + dict_dbm->dict.mtime = st.st_mtime; close_on_exec(dict_dbm->dict.fd, CLOSE_ON_EXEC); dict_dbm->dict.flags = dict_flags | DICT_FLAG_FIXED; if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0) diff --git a/postfix/util/dict_open.c b/postfix/util/dict_open.c index 8d47e8dd9..e5912b6ca 100644 --- a/postfix/util/dict_open.c +++ b/postfix/util/dict_open.c @@ -314,8 +314,13 @@ main(int argc, char **argv) else msg_fatal("unknown access mode: %s", argv[2]); dict_name = argv[optind]; - dict = dict_open(dict_name, open_flags, 0); + dict = dict_open(dict_name, open_flags, DICT_FLAG_LOCK); + dict_register(dict_name, dict); while (vstring_fgets_nonl(keybuf, VSTREAM_IN)) { + if (dict_changed()) { + msg_warn("dictionary has changed -- exiting"); + exit(0); + } if ((key = strtok(vstring_str(keybuf), " =")) == 0) continue; if ((value = strtok((char *) 0, " =")) == 0) { diff --git a/postfix/util/watch_fd.c b/postfix/util/watch_fd.c new file mode 100644 index 000000000..76dda7225 --- /dev/null +++ b/postfix/util/watch_fd.c @@ -0,0 +1,114 @@ +/*++ +/* NAME +/* watch_fd 3 +/* SUMMARY +/* monitor file descriptors for change +/* SYNOPSIS +/* #include +/* +/* void watch_fd_register(fd) +/* int fd; +/* +/* void watch_fd_remove(fd) +/* int fd; +/* +/* int watch_fd_changed() +/* DESCRIPTION +/* This module monitors file modification times of arbitrary file +/* descriptors. +/* +/* watch_fd_register() records information about the specified +/* file descriptor. +/* +/* watch_fd_remove() releases storage allocated by watch_fd_register(). +/* +/* watch_fd_changed() returns non-zero if any of the registered +/* SEE ALSO +/* msg(3) diagnostics interface +/* DIAGNOSTICS +/* Problems are reported via the msg(3) diagnostics routines: +/* the requested amount of memory is not available; improper use +/* is detected; other fatal errors. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include + +/* Application-specific. */ + +typedef struct { + int fd; /* file descriptor */ + time_t mtime; /* initial modification time */ +} WATCH_FD; + +static BINHASH *watch_fd_table; + +/* watch_fd_register - register file descriptor */ + +void watch_fd_register(int fd) +{ + char *myname = "watch_fd_enter"; + WATCH_FD *info; + struct stat st; + + if (fstat(fd, &st) < 0) + msg_fatal("%s: fstat: %m", myname); + + info = (WATCH_FD *) mymalloc(sizeof(*info)); + info->fd = fd; + info->mtime = st.st_mtime; + + if (watch_fd_table == 0) + watch_fd_table = binhash_create(0); + if (binhash_find(watch_fd_table, (char *) &fd, sizeof(fd))) + msg_panic("%s: entry %d exists", myname, fd); + binhash_enter(watch_fd_table, (char *) &fd, sizeof(fd), (char *) info); +} + +/* watch_fd_remove - remove file descriptor */ + +void watch_fd_remove(int fd) +{ + binhash_delete(watch_fd_table, (char *) &fd, sizeof(fd), myfree); +} + +/* watch_fd_changed - see if any file has changed */ + +int watch_fd_changed(void) +{ + char *myname = "watch_fd_changed"; + struct stat st; + BINHASH_INFO **ht_info_list; + BINHASH_INFO **ht; + BINHASH_INFO *h; + WATCH_FD *info; + int status; + + ht_info_list = binhash_list(watch_fd_table); + for (status = 0, ht = ht_info_list; status == 0 && (h = *ht) != 0; ht++) { + info = (WATCH_FD *) h->value; + if (fstat(info->fd, &st) < 0) + msg_fatal("%s: fstat: %m", myname); + status = (st.st_mtime != info->mtime); + } + myfree((char *) ht_info_list); + return (status); +} diff --git a/postfix/util/watch_fd.h b/postfix/util/watch_fd.h new file mode 100644 index 000000000..ef02ccd02 --- /dev/null +++ b/postfix/util/watch_fd.h @@ -0,0 +1,32 @@ +#ifndef _WATCH_FD_H_INCLUDED_ +#define _WATCH_FD_H_INCLUDED_ + +/*++ +/* NAME +/* watch_fd 3h +/* SUMMARY +/* monitor file descriptors for change +/* SYNOPSIS +/* #include "watch_fd.h" + DESCRIPTION + .nf + + /* + * External interface. + */ +extern void watch_fd_register(int); +extern void watch_fd_remove(int); +extern int watch_fd_changed(void); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#endif