From 04bda7598b64c53f3ddc15c085a2fc06e883d298 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Tue, 3 Oct 2000 00:00:00 -0500 Subject: [PATCH] snapshot-20001003 --- postfix/.indent.pro | 2 + postfix/ETRN_README | 107 ++++++--- postfix/HISTORY | 27 ++- postfix/RELEASE_NOTES | 68 +++--- postfix/conf/main.cf | 28 ++- postfix/conf/master.cf | 2 +- postfix/html/flush.8.html | 156 +++++++++---- postfix/html/smtpd.8.html | 88 +++---- postfix/man/man8/flush.8 | 89 ++++++-- postfix/man/man8/smtpd.8 | 15 +- postfix/src/flush/Makefile.in | 4 + postfix/src/flush/flush.c | 329 ++++++++++++++++++--------- postfix/src/global/Makefile.in | 44 +++- postfix/src/global/defer.c | 12 +- postfix/src/global/deliver_request.c | 14 +- postfix/src/global/flush_clnt.c | 188 +++++++++++++++ postfix/src/global/flush_clnt.h | 47 ++++ postfix/src/global/mail_conf.h | 22 ++ postfix/src/global/mail_conf_time.c | 260 +++++++++++++++++++++ postfix/src/global/mail_flush.c | 205 +---------------- postfix/src/global/mail_flush.h | 27 +-- postfix/src/global/mail_params.c | 8 +- postfix/src/global/mail_params.h | 20 +- postfix/src/global/mail_version.h | 2 +- postfix/src/master/mail_server.h | 3 +- postfix/src/master/multi_server.c | 8 + postfix/src/master/single_server.c | 8 + postfix/src/master/trigger_server.c | 8 + postfix/src/nqmgr/Makefile.in | 2 +- postfix/src/nqmgr/qmgr_active.c | 8 - postfix/src/nqmgr/qmgr_message.c | 2 +- postfix/src/nqmgr/qmgr_scan.c | 9 + postfix/src/postconf/Makefile.in | 4 +- postfix/src/postconf/extract.awk | 6 + postfix/src/postconf/postconf.c | 34 +++ postfix/src/qmgr/Makefile.in | 2 +- postfix/src/qmgr/qmgr_active.c | 8 - postfix/src/qmgr/qmgr_message.c | 2 +- postfix/src/qmgr/qmgr_scan.c | 9 + postfix/src/sendmail/Makefile.in | 4 +- postfix/src/smtpd/Makefile.in | 2 +- postfix/src/smtpd/smtpd.c | 59 ++--- postfix/src/smtpd/smtpd_check.c | 52 +---- postfix/src/smtpd/smtpd_check.h | 1 - 44 files changed, 1293 insertions(+), 702 deletions(-) create mode 100644 postfix/src/global/flush_clnt.c create mode 100644 postfix/src/global/flush_clnt.h create mode 100644 postfix/src/global/mail_conf_time.c diff --git a/postfix/.indent.pro b/postfix/.indent.pro index ca739a89c..8c52cbf79 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -17,6 +17,8 @@ -TCONFIG_INT_TABLE -TCONFIG_STR_FN_TABLE -TCONFIG_STR_TABLE +-TCONFIG_TIME_FN_TABLE +-TCONFIG_TIME_TABLE -TDELIVER_ATTR -TDELIVER_REQUEST -TDICT diff --git a/postfix/ETRN_README b/postfix/ETRN_README index b247145ee..7c72c3c77 100644 --- a/postfix/ETRN_README +++ b/postfix/ETRN_README @@ -1,67 +1,104 @@ +Purpose of this document +======================== + +This document describes the purpose of the Postfix fast ETRN service, +how the service works, and how it can be tested. + The Postfix fast ETRN service ============================= The SMTP ETRN command was designed for sites that have intermittent Internet connectivity. With ETRN, a site can tell the mail server -of its network provider "Please deliver all my mail now". +of its provider to "Please deliver all my mail now". -Postfix versions before 20001001 implemented the ETRN command in +Postfix versions before 20001003 implemented the ETRN command in a lame manner: they would attempt to deliver all queued mail. This is slow on mail servers that queue mail for many customers. -The Postfix "fast ETRN" service speeds up deliveries by looking +As of version 20001003, Postfix has a faster ETRN implementation. +At the same time, the command "sendmail -qR" is now implemented by +sending an ETRN command to the local SMTP server. + +Postfix "fast ETRN/sendmail -qR" speeds up deliveries by looking only at mail that is queued for a given destination site. Postfix "slow ETRN" is still used as a fall-back method. -The "fast ETRN" service uses the new "fast flush" service which -maintains per-destination logfiles of queued mail. The "fast flush" -service is enabled by default: +How Postfix fast ETRN works +=========================== - fast_flush_domains = $relay_domains +The "fast ETRN" service uses the new "flush" daemon which maintains +per-destination logfiles of queued mail. These logfiles are kept +below /var/spool/postfix/flush. Each logfile is named after its +destination domain name. Only destinations with syntactically valid +domain names can have per-destination logfiles. -By default, Postfix "fast ETRN" service is available only for -destinations that the local MTA is willing to relay mail to. +The behavior of the new "flush" daemon is controlled by parameters +in the main.cf configuration file. -To disable the "fast ETRN" service, specify an empty string: +By default, Postfix "fast ETRN/sendmail -qR" service is available +only for destinations that Postfix is willing to relay mail to: - fast_flush_domains = + fast_flush_policy = relay -The syntax of the fast_flush_domains parameter is exactly the -same as for the relay_domains parameter: a list of domain names, -files with domain names, or maptype:mapname lookup tables where -the right-hand side is ignored. - -For destinations that cannot have "fast ETRN" service, Postfix -falls back to the old "slow ETRN" service that attempts to deliver +The relay_domains parameter specifies what destinations Postfix +will relay to. For destinations without "fast ETRN/sendmail -qR" +service, Postfix falls back to the old "slow ETRN" which delivers all queued mail. -By default, every site can issue ETRN commands to your SMTP -server: +To enable "fast ETRN/sendmail -qR" for all destinations, specify: - smtpd_etrn_restrictions = + fast_flush_policy = all + +To disable "fast ETRN/sendmail -qR", so that Postfix always uses +the old "slow ETRN" which delivers all queued mail, specify: + + fast_flush_policy = none + +Testing the fast ETRN service +============================= + +If you run Postfix with "fast ETRN" service for the very first +time, you need to run "sendmail -q" to populate the per-site deferred +mail logfiles. If you omit this step, the logfiles will eventually +become populated as Postfix routinely attempts to deliver delayed +mail, but that will take a couple hours. To test the "fast ETRN" service, telnet to the Postfix SMTP server -from a client that is allowed to execute ETRN commands, and type: +from a client that is allowed to execute ETRN commands (by default, +that's every client), and type: helo my.client.name etrn some.customer.domain where "some.customer.domain" is the name of a domain that your mail -server is willing to relay mail to. +server is willing to relay mail to, and that your server has some +mail queued for. -In the maillog file, you should see something logged like: +In the maillog file, you should immediately see a couple of logfile +records, as evidence that the queue manager has opened queue files: - created fast ETRN cache for some.customer.domain + Oct 2 10:51:19 localhost postfix/qmgr[51999]: 682E8440A4: + from=, size=12345, nrcpt=1 (queue active) + Oct 2 10:51:19 localhost postfix/qmgr[51999]: 02249440B7: + from=, size=4711, nrcpt=1 (queue active) -It will then do a "slow ETRN" once. The next time the same ETRN -command is given, Postfix will do "fast ETRN". +What happens next depends on whether the destination is reachable. -If Postfix logs that it cannot create a fast ETRN cache for -"some.customer.domain", then execute the command "postfix check". -You probably skipped some installation instructions so that the -necessary directories were not created. +Repeat the exercise with another domain that your server is willing +to relay to, but that has no mail queued. -If Postfix logs that it uses slow ETRN service for "some.customer.domain", -instead of creating a fast ETRN cache, then either "some.customer.domain" -was not found in the DNS, or it was not listed as a valid fast ETRN -destination. Check your fast_flush_domains or relay_domains settings. + helo my.client.name + etrn some.other.customer.domain + +This time, the "etrn" command should not trigger any mail deliveries +at all. + +Finally, repeat the exercise with a destination that your mail +server is not willing to relay to. It does not matter if your +server has mail queued for that destination. + + helo my.client.name + etrn not.a.customer.domain + +If your "fast ETRN" caching policy is left at its default setting, +then the "etrn" command should trigger delivery of all queued mail. diff --git a/postfix/HISTORY b/postfix/HISTORY index 28680ea86..27868f5c7 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -4300,10 +4300,12 @@ Apologies for any names omitted. rid of them. To disallow, specify "strict_rfc821_envelopes = yes". File: smtpd/smtpd.c. -20000926-8 +20000926-20001003 - First implementation of a logfile-based fast flush server, - which is the basis for ETRN and "sendmail -qRsite". + Feature: a "flush" server that keeps per-destination records + of deferred mail. It is the basis of a faster ETRN and + "sendmail -qRsite" implementation. This code was rewritten + half a dozen times. 20000928 @@ -4319,3 +4321,22 @@ Apologies for any names omitted. Robustness? Log errors from SASL library code as warnings not as fatal errors. Files: smtp*/*glue.c. + +20001001 + + Feature: in master.cf, specify ? after wakeup time to avoid + waking up services that aren't being used. + +20001003 + + Feature: the fast flush refresh and purge time interval + parameters can now be specified in seconds or in user-specified + units by providing an appropriate suffix: s (seconds), m + (minutes), h (hours), d (days), w (weeks). unit. This + was needed so that I could test the flush server code in + a reasonable way. Other time parameters will be migrated + as time permits. Files: global/mail_conf_time.c, + postconf/postconf.c. + + Unfeature: qmgr_hog_factor is now disabled by default. It + was just too confusing. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 151495069..dfa8a726f 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,4 +1,4 @@ -Incompatible changes with snapshot-20000928 +Incompatible changes with snapshot-20001003 =========================================== If this release does not work for you, you can go back to a previous @@ -12,13 +12,6 @@ again. After installing the new Postfix release: -- Check the output from "postconf qmgr_message_active_limit". The - recommended value has changed to 10000. - - If your setting is lower, either you need to remove the explicit - setting from the main.cf file (so that Postfix uses the recommended - default setting), or you need to update it. - - Check the output from "postconf hash_queue_names". The recommended setting now includes the names of the "active", "bounce", "defer", and "flush" directories. @@ -28,25 +21,32 @@ After installing the new Postfix release: file (so that Postfix uses the recommended default setting), or you need to update it. +- Check the output from "postconf qmgr_message_active_limit". The + recommended value has changed to 10000. + + If your setting is lower, either you need to remove the explicit + setting from the main.cf file (so that Postfix uses the recommended + default setting), or you need to update it. + - Add a new entry to the master.cf file for the new flush service: - flush unix - - n 18000? 0 flush + flush unix - - n 1000? 0 flush - This entry is not needed if you won't use the fast flush service - (this service is used by default; to disable, you need to specify - in the main.cf file an empty fast_flush_domains parameter: + This entry is not needed if you won't use the fast flush service. + This service is used by default; to disable the fast flush service, + you need to specify in the main.cf file: - fast_flush_domains = + fast_flush_policy = none - The 18000? requests that the "fast flush" service does some - cleaning up every 5 hours, but only if the fast flush service is - being used by some other Postfix service, and the 0 means that - Postfix should run as many flush servers as are needed, in order - to avoid deadlock conditions. + In the new master.cf entry, the 1000? requests that the "fast + flush" service does some cleaning up every 15 minutes, but only + if the fast flush service is actually being used. The 0 means + that Postfix should run as many flush servers as are needed. + Changing this may cause deadlock. Now you can start Postfix again. -Major changes with snapshot-20000929 +Major changes with snapshot-20001001 ==================================== In order to improve performance of one-to-one deliveries, Postfix @@ -55,22 +55,24 @@ by default now looks at up to 10000 messages at a time (was: 1000). Until now, Postfix did a rather lame effort at implementing the SMTP ETRN command - it attempted to deliver all mail in the queue, regardless of its destination. This is slow if your mail server -queues mail for lots of different sites. +queues mail for lots of different destinations. -This release introduces "fast ETRN", which delivers only mail that -is known to be queued for the specified site. Postfix now maintains -so-called "fast flush" logfiles with information about what mail -is queued for specific sites. A "fast flush" logfile is "flushed" -after Postfix receives an appropriate ETRN command, or after someone -executes the command "sendmail -qRsite" for an appropriate site. +This release introduces fast "ETRN" and "sendmail -qR". Unlike +their lame predecessor, these deliver only mail that is queued for +the specified destinations. -A missing "fast flush" logfile is created automatically when an -SMTP client issues the ETRN command - but only for destinations -that the local MTA is willing to relay mail to. This policy is -controlled with the "fast_etrn_domains" configuration parameter -(default: $relay_domains). Other destinations remain stuck with -the old "slow ETRN" service that attempts to deliver all mail in -the queue. +Postfix now maintains per-destination logfiles with information +about what mail is queued for specific destinations. By default, +these logfiles are maintained only for destinations that Postfix +is willing to relay to (as controlled by the relay_domains parameter). + +The maintenance policy for deferred mail logfiles is selected with +the "fast_flush_policy" configuration parameter. Possible values +are: "all" (maintain logs for all destinations), "relay" (maintain +logs for relay destinations) or "none" (maintain no logs). + +Postfix falls back to the old slow ETRN for destinations that are +not eligible for the fast "ETRN" and "sendmail -qR" service. See the file ETRN_README for details. diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index 1cac2bc00..ab0909982 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -343,17 +343,25 @@ mail_owner = postfix # FAST ETRN SERVICE # -# By default, Postfix does a rather lame effort at implementing the -# SMTP ETRN command - it attempts to deliver all queued mail regardless -# of its destination. This does not work well if your mail server -# queues mail for lots of sites. In order to enable a faster ETRN -# that only delivers mail that is known to be queued for a site, -# enable the fast flush cache. Currently, "fast ETRN" is available -# only for destinations that the local system is willing to relay -# mail to (as specified in the relay_domains parameter). +# Postfix maintains per-destination logfiles with information about +# deferred mail, so that mail can be flushed quickly with the SMTP +# "ETRN domain.name" command, or by executing "sendmail -qRdomain.name". # -#enable_fast_flush = yes -#enable_fast_flush = no +# By default, Postfix maintains deferred mail logfile information +# only for destinations that Postfix is willing to relay to (as +# specified in the relay_domains parameter). For other destinations, +# Postfix attempts to deliver ALL queued mail after receiving the +# SMTP "ETRN domain.name" command, or after execution of "sendmail +# -qRdomain.name". This can be slow when a lot of mail is queued. +# +# The fast_flush_policy controls what destinations are eligible for +# this "fast ETRN/sendmail -qR" service. Specify "all" to make all +# destinations eligible, "relay" for relay destinations only, and +# "none" to turn this feature off. +# +#fast_flush_policy = all +#fast_flush_policy = relay +#fast_flush_policy = none # SHOW SOFTWARE VERSION OR NOT # diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf index 2de53312c..15deb0142 100644 --- a/postfix/conf/master.cf +++ b/postfix/conf/master.cf @@ -75,7 +75,7 @@ qmgr fifo n - n 300 1 qmgr rewrite unix - - n - - trivial-rewrite bounce unix - - n - 0 bounce defer unix - - n - 0 bounce -flush unix - - n 18000? 0 flush +flush unix - - n 1000? 0 flush smtp unix - - n - - smtp showq unix n - n - - showq error unix - - n - - error diff --git a/postfix/html/flush.8.html b/postfix/html/flush.8.html index 8c6c97ad9..eb48f6b69 100644 --- a/postfix/html/flush.8.html +++ b/postfix/html/flush.8.html @@ -6,58 +6,58 @@ FLUSH(8) FLUSH(8) NAME - flush - Postfix fast flush daemon + flush - Postfix fast flush cache manager SYNOPSIS flush [generic Postfix daemon options] DESCRIPTION - The flush server maintains so-called "fast flush" logfiles - with information about what messages are queued for a spe- - cific site. This program expects to be run from the mas- - ter(8) process manager. + The flush server maintains a record of deferred mail by + destination. This information is used to improve the per- + formance of the SMTP ETRN request, and of its command-line + equivalent, sendmail -qR. This program expects to be run + from the master(8) process manager. + + The record is implemented as per-destination logfiles with + as contents the queue IDs of deferred mail. The files are + append-only, and are truncated when delivery is requested + for a specific site. + + Deferred mail by destination information is recorded only + for destinations that are eligible according to a config- + urable policy. The policy is specified with the + fast_flush_cache_policy configuration parameter: + + all Maintain per-destination deferred mail logfiles for + all destinations. + + relay Maintain per-destination deferred mail logfiles + only for destinations that this system is willing + to relay mail to ($relay_domains). + + none Do not maintain per-destination deferred mail log- + files. This server implements the following requests: - FLUSH_REQ_ENABLE sitename - Enable fast flush logging for the specified site. - - FLUSH_REQ_APPEND sitename queue_id - Append queue_id to the fast flush log for the spec- - ified site. + FLUSH_REQ_ADD sitename queue_id + Inform the cache manager that the specified message + is queued for the specified site. Depending on + caching policy, the cache manager stores or ignores + the information. FLUSH_REQ_SEND sitename - Arrange for the delivery of all messages that are - listed in the fast flush logfile for the specified - site. After the logfile is processed, the file is - truncated to length zero. + Request delivery of all messages that are queued + for the specified site. Depending on cache policy, + this triggers delivery of specific messages or of + all queued mail. The per-destination logfile is + discarded. TRIGGER_REQ_WAKEUP (wakeup signal from master) FLUSH_REQ_PURGE - Pretend that FLUSH_REQ_SEND was received for all - sites with a non-empty "fast flush" logfile, and - delete empty "fast flush" logfiles that have not - been updated in several days. This operation com- - pletes in the background because it can take a - noticeable amount of time. - - Fast flush logfiles are truncated only after a - FLUSH_REQ_SEND request, not when mail is actually - delivered, and therefore can accumulate redundant - or even outdated information. In order to maintain - sanity, FLUSH_REQ_PURGE must be requested occasion- - ally. - - The response to the client is one of: - - FLUSH_STAT_OK - The request completed normally. - - FLUSH_STAT_BAD - The flush server rejected the request (bad request - name, bad request parameter value). - + Delete empty per-destination logfiles that haven't + been updated in $fast_flush_purge_delay seconds. @@ -71,8 +71,32 @@ FLUSH(8) FLUSH(8) FLUSH(8) FLUSH(8) - FLUSH_STAT_UNKNOWN - The specified site has no fast flush log. + Refresh non-empty per-destination logfiles that + were not read in $fast_flush_refresh_delay seconds. + This is done by pretending that send requests were + received for the corresponding sites. + + Fast flush logfiles are truncated only after a + FLUSH_REQ_SEND request, not when mail is actually + delivered, and therefore can accumulate outdated or + redundant data. In order to maintain sanity, + FLUSH_REQ_PURGE should be requested at regular + imtervals. + + After an initial sanity check of request parame- + ters, this request proceeds in the background. + + The response to the client is one of: + + FLUSH_STAT_OK + The request completed normally. + + FLUSH_STAT_BAD + The flush server rejected the request (bad request + name, bad request parameter value). + + FLUSH_STAT_FAIL + The request failed. SECURITY The fast flush server is not security-sensitive. It does @@ -84,10 +108,43 @@ FLUSH(8) FLUSH(8) Problems and transactions are logged to syslogd(8). BUGS - In reality, this server schedules delivery of messages, - regardless of their destination. This limitation is due to - the fact that one queue runner has to handle mail for mul- - tiple destinations. + In reality, this server schedules delivery of all recipi- + ents of deferred messages. This limitation is due to the + fact that one queue runner has to handle mail for multiple + destinations. + +FILES + /var/spool/postfix/flush, location of "fast flush" logfiles. + +CONFIGURATION PARAMETERS + See the Postfix main.cf file for syntax details and for + default values. Use the postfix reload command after a + configuration change. + + fast_flush_cache_policy + What destinations can have a "fast flush" logfile: + all, relay (relay destinations) or none. + + + + + 2 + + + + + +FLUSH(8) FLUSH(8) + + + fast_flush_refresh_delay + Refresh a non-empty "fast flush" logfile that was + not read in this amount of time, by simulating a + send request for the corresponding destination. + + fast_flush_purge_delay + Remove an empty "fast flush" logfile that was not + updated in this amount of time. SEE ALSO smtpd(8) Postfix SMTP server @@ -128,7 +185,16 @@ FLUSH(8) FLUSH(8) - 2 + + + + + + + + + + 3 diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index e8d674f33..7f80d48ca 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -228,19 +228,6 @@ SMTPD(8) SMTPD(8) SMTP session before it is penalized with tarpit delays. -ETRN controls - smtpd_etrn_restrictions - Restrict what domain names can be used in ETRN com- - mands, and what clients may issue ETRN commands. - - fast_flush_domains - The destinations that this system is willing to - provide "fast ETRN" service for. By default, "fast - ETRN" service is available only for destinations - that the local system is willing to relay mail to. - For other destinations, Postfix simply attempts to - deliver all mail in the queue. - UCE control restrictions smtpd_client_restrictions Restrict what clients may connect to this mail sys- @@ -258,6 +245,19 @@ SMTPD(8) SMTPD(8) Restrict what sender addresses are allowed in MAIL FROM commands. + smtpd_recipient_restrictions + Restrict what recipient addresses are allowed in + RCPT TO commands. + + smtpd_etrn_restrictions + Restrict what domain names can be used in ETRN com- + mands, and what clients may issue ETRN commands. + + allow_untrusted_routing + Allow untrusted clients to specify addresses with + sender-specified routing. Enabling this opens up + nasty relay loopholes involving trusted backup MX + 4 @@ -269,60 +269,60 @@ SMTPD(8) SMTPD(8) SMTPD(8) SMTPD(8) - smtpd_recipient_restrictions - Restrict what recipient addresses are allowed in - RCPT TO commands. - - allow_untrusted_routing - Allow untrusted clients to specify addresses with - sender-specified routing. Enabling this opens up - nasty relay loopholes involving trusted backup MX hosts. restriction_classes - Declares the name of zero or more parameters that - contain a list of UCE restrictions. The names of - these parameters can then be used instead of the + Declares the name of zero or more parameters that + contain a list of UCE restrictions. The names of + these parameters can then be used instead of the restriction lists that they represent. maps_rbl_domains - List of DNS domains that publish the addresses of + List of DNS domains that publish the addresses of blacklisted hosts. relay_domains - Restrict what domains or networks this mail system + Restrict what domains or networks this mail system will relay mail from or to. UCE control responses access_map_reject_code - Server response when a client violates an access + Server response when a client violates an access database restriction. invalid_hostname_reject_code - Server response when a client violates the + Server response when a client violates the reject_invalid_hostname restriction. maps_rbl_reject_code - Server response when a client violates the + Server response when a client violates the maps_rbl_domains restriction. reject_code - Response code when the client matches a reject + Response code when the client matches a reject restriction. relay_domains_reject_code - Server response when a client attempts to violate + Server response when a client attempts to violate the mail relay policy. unknown_address_reject_code - Server response when a client violates the + Server response when a client violates the reject_unknown_address restriction. unknown_client_reject_code - Server response when a client without address to - name mapping violates the reject_unknown_clients + Server response when a client without address to + name mapping violates the reject_unknown_clients restriction. + unknown_hostname_reject_code + Server response when a client violates the + reject_unknown_hostname restriction. + +SEE ALSO + cleanup(8) message canonicalization + master(8) process manager + syslogd(8) system logging @@ -335,17 +335,8 @@ SMTPD(8) SMTPD(8) SMTPD(8) SMTPD(8) - unknown_hostname_reject_code - Server response when a client violates the - reject_unknown_hostname restriction. - -SEE ALSO - cleanup(8) message canonicalization - master(8) process manager - syslogd(8) system logging - LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) @@ -382,6 +373,15 @@ SMTPD(8) SMTPD(8) + + + + + + + + + diff --git a/postfix/man/man8/flush.8 b/postfix/man/man8/flush.8 index 7d09b791a..9deacb75f 100644 --- a/postfix/man/man8/flush.8 +++ b/postfix/man/man8/flush.8 @@ -4,7 +4,7 @@ .SH NAME flush \- -Postfix fast flush daemon +Postfix fast flush cache manager .SH SYNOPSIS .na .nf @@ -12,33 +12,56 @@ Postfix fast flush daemon .SH DESCRIPTION .ad .fi -The flush server maintains so-called "fast flush" logfiles with -information about what messages are queued for a specific site. +The flush server maintains a record of deferred mail by destination. +This information is used to improve the performance of the SMTP +\fBETRN\fR request, and of its command-line equivalent, +\fBsendmail -qR\fR. This program expects to be run from the \fBmaster\fR(8) process manager. +The record is implemented as per-destination logfiles with +as contents the queue IDs of deferred mail. The files are +append-only, and are truncated when delivery is requested +for a specific site. + +Deferred mail by destination information is recorded only for +destinations that are eligible according to a configurable policy. +The policy is specified with the \fBfast_flush_cache_policy\fR +configuration parameter: +.IP \fBall\fR +Maintain per-destination deferred mail logfiles for all destinations. +.IP \fBrelay\fR +Maintain per-destination deferred mail logfiles only for destinations +that this system is willing to relay mail to ($\fBrelay_domains\fR). +.IP \fBnone\fR +Do not maintain per-destination deferred mail logfiles. +.PP This server implements the following requests: -.IP "\fBFLUSH_REQ_ENABLE\fI sitename\fR" -Enable fast flush logging for the specified site. -.IP "\fBFLUSH_REQ_APPEND\fI sitename queue_id\fR" -Append \fIqueue_id\fR to the fast flush log for the -specified site. +.IP "\fBFLUSH_REQ_ADD\fI sitename queue_id\fR" +Inform the cache manager that the specified message is queued for +the specified site. Depending on caching policy, the cache manager +stores or ignores the information. .IP "\fBFLUSH_REQ_SEND\fI sitename\fR" -Arrange for the delivery of all messages that are listed in the fast -flush logfile for the specified site. After the logfile is processed, -the file is truncated to length zero. +Request delivery of all messages that are queued for the specified +site. Depending on cache policy, this triggers delivery of specific +messages or of all queued mail. The per-destination logfile is +discarded. .IP "\fBTRIGGER_REQ_WAKEUP\fR (wakeup signal from master)" .IP "\fBFLUSH_REQ_PURGE\fR" -Pretend that \fBFLUSH_REQ_SEND\fR was received for all sites with -a non-empty "fast flush" logfile, and delete empty "fast flush" -logfiles that have not been updated in several days. This operation -completes in the background because it can take a noticeable -amount of time. +Delete empty per-destination logfiles that haven't been updated in +$\fBfast_flush_purge_delay\fR seconds. +.sp +Refresh non-empty per-destination logfiles that were not read in +$\fBfast_flush_refresh_delay\fR seconds. This is done by pretending +that send requests were received for the corresponding sites. .sp Fast flush logfiles are truncated only after a \fBFLUSH_REQ_SEND\fR request, not when mail is actually delivered, and therefore can -accumulate redundant or even outdated information. In order to -maintain sanity, \fBFLUSH_REQ_PURGE\fR must be requested occasionally. +accumulate outdated or redundant data. In order to maintain sanity, +\fBFLUSH_REQ_PURGE\fR should be requested at regular imtervals. +.sp +After an initial sanity check of request parameters, this request +proceeds in the background. .PP The response to the client is one of: .IP \fBFLUSH_STAT_OK\fR @@ -46,8 +69,8 @@ The request completed normally. .IP \fBFLUSH_STAT_BAD\fR The flush server rejected the request (bad request name, bad request parameter value). -.IP \fBFLUSH_STAT_UNKNOWN\fR -The specified site has no fast flush log. +.IP \fBFLUSH_STAT_FAIL\fR +The request failed. .SH SECURITY .na .nf @@ -63,9 +86,31 @@ Problems and transactions are logged to \fBsyslogd\fR(8). .SH BUGS .ad .fi -In reality, this server schedules delivery of messages, regardless -of their destination. This limitation is due to the fact that +In reality, this server schedules delivery of all recipients +of deferred messages. This limitation is due to the fact that one queue runner has to handle mail for multiple destinations. +.SH FILES +.na +.nf +/var/spool/postfix/flush, location of "fast flush" logfiles. +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +See the Postfix \fBmain.cf\fR file for syntax details and for +default values. Use the \fBpostfix reload\fR command after a +configuration change. +.IP \fBfast_flush_cache_policy\fR +What destinations can have a "fast flush" logfile: \fBall\fR, +\fBrelay\fR (relay destinations) or \fBnone\fR. +.IP \fBfast_flush_refresh_delay\fR +Refresh a non-empty "fast flush" logfile that was not read in +this amount of time, by simulating a send request for the +corresponding destination. +.IP \fBfast_flush_purge_delay\fR +Remove an empty "fast flush" logfile that was not updated in +this amount of time. .SH SEE ALSO .na .nf diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 5e9628d4a..dbabd4ed4 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -165,18 +165,6 @@ Disconnect after a client has made this number of errors. Limit the number of times a client can issue a junk command such as NOOP, VRFY, ETRN or RSET in one SMTP session before it is penalized with tarpit delays. -.SH "ETRN controls" -.ad -.fi -.IP \fBsmtpd_etrn_restrictions\fR -Restrict what domain names can be used in \fBETRN\fR commands, -and what clients may issue \fBETRN\fR commands. -.IP \fBfast_flush_domains\fR -The destinations that this system is willing to provide "fast ETRN" -service for. By default, "fast ETRN" service is available only -for destinations that the local system is willing to relay mail to. -For other destinations, Postfix simply attempts to deliver all mail -in the queue. .SH "UCE control restrictions" .ad .fi @@ -192,6 +180,9 @@ Restrict what client hostnames are allowed in \fBHELO\fR and Restrict what sender addresses are allowed in \fBMAIL FROM\fR commands. .IP \fBsmtpd_recipient_restrictions\fR Restrict what recipient addresses are allowed in \fBRCPT TO\fR commands. +.IP \fBsmtpd_etrn_restrictions\fR +Restrict what domain names can be used in \fBETRN\fR commands, +and what clients may issue \fBETRN\fR commands. .IP \fBallow_untrusted_routing\fR Allow untrusted clients to specify addresses with sender-specified routing. Enabling this opens up nasty relay loopholes involving diff --git a/postfix/src/flush/Makefile.in b/postfix/src/flush/Makefile.in index 1409de758..2f0da3e52 100644 --- a/postfix/src/flush/Makefile.in +++ b/postfix/src/flush/Makefile.in @@ -66,11 +66,15 @@ flush.o: ../../include/valid_hostname.h flush.o: ../../include/htable.h flush.o: ../../include/dict.h flush.o: ../../include/argv.h +flush.o: ../../include/scan_dir.h flush.o: ../../include/mail_params.h flush.o: ../../include/mail_queue.h flush.o: ../../include/mail_proto.h flush.o: ../../include/iostuff.h flush.o: ../../include/mail_flush.h +flush.o: ../../include/flush_clnt.h flush.o: ../../include/mail_conf.h +flush.o: ../../include/mail_scan_dir.h flush.o: ../../include/maps.h +flush.o: ../../include/domain_list.h flush.o: ../../include/mail_server.h diff --git a/postfix/src/flush/flush.c b/postfix/src/flush/flush.c index 48aa7b9dd..98c1f8ed5 100644 --- a/postfix/src/flush/flush.c +++ b/postfix/src/flush/flush.c @@ -2,37 +2,60 @@ /* NAME /* flush 8 /* SUMMARY -/* Postfix fast flush daemon +/* Postfix fast flush cache manager /* SYNOPSIS /* \fBflush\fR [generic Postfix daemon options] /* DESCRIPTION -/* The flush server maintains so-called "fast flush" logfiles with -/* information about what messages are queued for a specific site. +/* The flush server maintains a record of deferred mail by destination. +/* This information is used to improve the performance of the SMTP +/* \fBETRN\fR request, and of its command-line equivalent, +/* \fBsendmail -qR\fR. /* This program expects to be run from the \fBmaster\fR(8) process /* manager. /* +/* The record is implemented as per-destination logfiles with +/* as contents the queue IDs of deferred mail. The files are +/* append-only, and are truncated when delivery is requested +/* for a specific site. +/* +/* Deferred mail by destination information is recorded only for +/* destinations that are eligible according to a configurable policy. +/* The policy is specified with the \fBfast_flush_cache_policy\fR +/* configuration parameter: +/* .IP \fBall\fR +/* Maintain per-destination deferred mail logfiles for all destinations. +/* .IP \fBrelay\fR +/* Maintain per-destination deferred mail logfiles only for destinations +/* that this system is willing to relay mail to ($\fBrelay_domains\fR). +/* .IP \fBnone\fR +/* Do not maintain per-destination deferred mail logfiles. +/* .PP /* This server implements the following requests: -/* .IP "\fBFLUSH_REQ_ENABLE\fI sitename\fR" -/* Enable fast flush logging for the specified site. -/* .IP "\fBFLUSH_REQ_APPEND\fI sitename queue_id\fR" -/* Append \fIqueue_id\fR to the fast flush log for the -/* specified site. +/* .IP "\fBFLUSH_REQ_ADD\fI sitename queue_id\fR" +/* Inform the cache manager that the specified message is queued for +/* the specified site. Depending on caching policy, the cache manager +/* stores or ignores the information. /* .IP "\fBFLUSH_REQ_SEND\fI sitename\fR" -/* Arrange for the delivery of all messages that are listed in the fast -/* flush logfile for the specified site. After the logfile is processed, -/* the file is truncated to length zero. +/* Request delivery of all messages that are queued for the specified +/* site. Depending on cache policy, this triggers delivery of specific +/* messages or of all queued mail. The per-destination logfile is +/* discarded. /* .IP "\fBTRIGGER_REQ_WAKEUP\fR (wakeup signal from master)" /* .IP "\fBFLUSH_REQ_PURGE\fR" -/* Pretend that \fBFLUSH_REQ_SEND\fR was received for all sites with -/* a non-empty "fast flush" logfile, and delete empty "fast flush" -/* logfiles that have not been updated in several days. This operation -/* completes in the background because it can take a noticeable -/* amount of time. +/* Delete empty per-destination logfiles that haven't been updated in +/* $\fBfast_flush_purge_delay\fR seconds. +/* .sp +/* Refresh non-empty per-destination logfiles that were not read in +/* $\fBfast_flush_refresh_delay\fR seconds. This is done by pretending +/* that send requests were received for the corresponding sites. /* .sp /* Fast flush logfiles are truncated only after a \fBFLUSH_REQ_SEND\fR -/* request, not when mail is actually delivered, and therefore can -/* accumulate redundant or even outdated information. In order to -/* maintain sanity, \fBFLUSH_REQ_PURGE\fR must be requested occasionally. +/* request, not when mail is actually delivered, and therefore can +/* accumulate outdated or redundant data. In order to maintain sanity, +/* \fBFLUSH_REQ_PURGE\fR should be requested at regular imtervals. +/* .sp +/* After an initial sanity check of request parameters, this request +/* proceeds in the background. /* .PP /* The response to the client is one of: /* .IP \fBFLUSH_STAT_OK\fR @@ -40,8 +63,8 @@ /* .IP \fBFLUSH_STAT_BAD\fR /* The flush server rejected the request (bad request name, bad /* request parameter value). -/* .IP \fBFLUSH_STAT_UNKNOWN\fR -/* The specified site has no fast flush log. +/* .IP \fBFLUSH_STAT_FAIL\fR +/* The request failed. /* SECURITY /* .ad /* .fi @@ -51,9 +74,27 @@ /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* BUGS -/* In reality, this server schedules delivery of messages, regardless -/* of their destination. This limitation is due to the fact that +/* In reality, this server schedules delivery of all recipients +/* of deferred messages. This limitation is due to the fact that /* one queue runner has to handle mail for multiple destinations. +/* FILES +/* /var/spool/postfix/flush, location of "fast flush" logfiles. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* See the Postfix \fBmain.cf\fR file for syntax details and for +/* default values. Use the \fBpostfix reload\fR command after a +/* configuration change. +/* .IP \fBfast_flush_cache_policy\fR +/* What destinations can have a "fast flush" logfile: \fBall\fR, +/* \fBrelay\fR (relay destinations) or \fBnone\fR. +/* .IP \fBfast_flush_refresh_delay\fR +/* Refresh a non-empty "fast flush" logfile that was not read in +/* this amount of time, by simulating a send request for the +/* corresponding destination. +/* .IP \fBfast_flush_purge_delay\fR +/* Remove an empty "fast flush" logfile that was not updated in +/* this amount of time. /* SEE ALSO /* smtpd(8) Postfix SMTP server /* qmgr(8) Postfix queue manager @@ -97,9 +138,11 @@ #include #include #include +#include #include #include #include +#include /* Single server skeleton. */ @@ -107,28 +150,97 @@ /* Application-specific. */ -#define STR(x) vstring_str(x) + /* + * Tunable parameters. + */ +int var_fflush_refresh; +int var_fflush_purge; +char *var_relay_domains; + + /* + * Flush policy stuff. + */ +#define FLUSH_POLICY_UNKNOWN 0 +#define FLUSH_POLICY_ALL 1 +#define FLUSH_POLICY_RELAY 2 +#define FLUSH_POLICY_NONE 3 + +static DOMAIN_LIST *flush_domains; +static int flush_policy = FLUSH_POLICY_UNKNOWN; + + /* + * Some hard-wired policy: how many queue IDs we remember while we're + * flushing a logfile. + */ #define FLUSH_DUP_FILTER_SIZE 10000 /* graceful degradation */ -#define FLUSH_MAX_UNUSED (7 * 24 * 60 * 60) -/* flush_append - append queue ID to per-site fast flush log */ + /* + * Silly little macros. + */ -static int flush_append(const char *site, const char *queue_id) +#define STR(x) vstring_str(x) +#define STREQ(x,y) (strcmp(x,y) == 0) + +/* flush_policy_init - initialize fast flush policy stuff */ + +static int flush_policy_init(void) { - char *myname = "flush_append"; + + if (STREQ(var_fflush_policy, FFLUSH_POLICY_ALL)) { + flush_policy = FLUSH_POLICY_ALL; + } else if (STREQ(var_fflush_policy, FFLUSH_POLICY_RELAY)) { + flush_domains = domain_list_init(var_relay_domains); + flush_policy = FLUSH_POLICY_RELAY; + } else if (STREQ(var_fflush_policy, FFLUSH_POLICY_NONE)) { + flush_policy = FLUSH_POLICY_NONE; + } else { + msg_fatal("invalid %s configuration parameter value: %s", + VAR_FFLUSH_POLICY, var_fflush_policy); + } +} + +/* flush_policy_ok - check caching policy */ + +static int flush_policy_ok(const char *site) +{ + if (flush_policy == FLUSH_POLICY_UNKNOWN) + flush_policy_init(); + + switch (flush_policy) { + case FLUSH_POLICY_ALL: + return (1); + case FLUSH_POLICY_RELAY: + return (domain_list_match(flush_domains, site)); + case FLUSH_POLICY_NONE: + return (0); + default: + msg_panic("invalid fast flush policy %d", flush_policy); + } +} + +/* flush_add_service - append queue ID to per-site fast flush log */ + +static int flush_add_service(const char *site, const char *queue_id) +{ + char *myname = "flush_add_service"; VSTREAM *log; if (msg_verbose) msg_info("%s: site %s queue_id %s", myname, site, queue_id); /* - * Open the logfile. + * If this site is not eligible for caching, just ignore the request. */ - if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, site, O_APPEND | O_WRONLY, 0600)) == 0) { - if (errno != ENOENT) - msg_fatal("%s: open fast flush log for site %s: %m", myname, site); - return (FLUSH_STAT_UNKNOWN); - } + if (flush_policy_ok(site) == 0) + return (FLUSH_STAT_OK); + + /* + * Open the logfile or bust. + */ + if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, site, + O_CREAT | O_APPEND | O_WRONLY, 0600)) == 0) + msg_fatal("%s: open fast flush log for site %s: %m", + myname, site); /* * We must lock the logfile, so that we don't lose information due to @@ -158,11 +270,11 @@ static int flush_append(const char *site, const char *queue_id) return (FLUSH_STAT_OK); } -/* flush_site - flush mail queued for site */ +/* flush_send_service - flush mail queued for site */ -static int flush_site(const char *site) +static int flush_send_service(const char *site) { - char *myname = "flush_site"; + char *myname = "flush_send_service"; VSTRING *queue_id; VSTRING *queue_file; VSTREAM *log; @@ -178,12 +290,19 @@ static int flush_site(const char *site) msg_info("%s: site %s", myname, site); /* - * Open the logfile. + * If this site is not eligible for caching, deliver all queued mail. + */ + if (flush_policy_ok(site) == 0) + return (mail_flush_deferred()); + + /* + * Open the logfile. If the file does not exist, then there is no queued + * mail for this destination. */ if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, site, O_RDWR, 0600)) == 0) { if (errno != ENOENT) msg_fatal("%s: open fast flush log for site %s: %m", myname, site); - return (FLUSH_STAT_UNKNOWN); + return (FLUSH_STAT_OK); } /* @@ -198,11 +317,10 @@ static int flush_site(const char *site) /* * This is the part that dominates running time: schedule the listed * queue files for delivery by updating their file time stamps. This - * should take no more than a couple seconds under normal conditions - * (sites that receive millions of messages in a day should not use fast - * flush service). Filter out duplicate names to avoid hammering the file - * system, with some finite limit on the amount of memory that we are - * willing to sacrifice. Graceful degradation. + * should take no more than a couple seconds under normal conditions. + * Filter out duplicate names to avoid hammering the file system, with + * some finite limit on the amount of memory that we are willing to + * sacrifice. Graceful degradation. */ queue_id = vstring_alloc(10); queue_file = vstring_alloc(10); @@ -228,11 +346,12 @@ static int flush_site(const char *site) msg_warn("%s: update %s time stamps: %m", myname, STR(queue_file)); } else if (mail_queue_rename(STR(queue_id), MAIL_QUEUE_DEFERRED, - MAIL_QUEUE_INCOMING) < 0 - && errno != ENOENT) - msg_warn("%s: rename from %s to %s: %m", - STR(queue_file), MAIL_QUEUE_DEFERRED, - MAIL_QUEUE_INCOMING); + MAIL_QUEUE_INCOMING) < 0) { + if (errno != ENOENT) + msg_warn("%s: rename from %s to %s: %m", + STR(queue_file), MAIL_QUEUE_DEFERRED, + MAIL_QUEUE_INCOMING); + } } else { if (msg_verbose) msg_info("%s: site %s: skip file %s as duplicate", @@ -247,8 +366,7 @@ static int flush_site(const char *site) * Truncate the fast flush log. */ if (count > 0 && ftruncate(vstream_fileno(log), (off_t) 0) < 0) - msg_fatal("%s: truncate fast flush log for site %s: %m", - myname, site); + msg_fatal("%s: truncate fast flush log for site %s: %m", myname, site); /* * Request delivery and clean up. @@ -267,34 +385,11 @@ static int flush_site(const char *site) return (FLUSH_STAT_OK); } -/* flush_enable - enable fast flush logging for site */ +/* flush_purge_service - housekeeping */ -static int flush_enable(const char *site) +static int flush_purge_service(void) { - char *myname = "flush_enable"; - VSTREAM *log; - - if (msg_verbose) - msg_info("%s: site %s", myname, site); - - /* - * Open or create the logfile. Multiple requests may arrive in parallel, - * so allow for the possibility that the file already exists. - */ - if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, site, O_CREAT | O_RDWR, 0600)) == 0) - msg_fatal("%s: open fast flush log for site %s: %m", myname, site); - - if (vstream_fclose(log) != 0) - msg_warn("write fast flush log for site %s: %m", site); - - return (FLUSH_STAT_OK); -} - -/* flush_purge - housekeeping */ - -static void flush_purge(void) -{ - char *myname = "flush_purge"; + char *myname = "flush_purge_service"; SCAN_DIR *scan; char *site; struct stat st; @@ -302,13 +397,14 @@ static void flush_purge(void) scan = scan_dir_open(MAIL_QUEUE_FLUSH); while ((site = mail_scan_dir_next(scan)) != 0) { + mail_queue_path(path, MAIL_QUEUE_FLUSH, site); if (valid_hostname(site) == 0) { - msg_warn("%s: bad fast flush logfile name: %s", myname, STR(path)); + msg_warn("%s: bad fast flush logfile name: %s", myname, site); if (unlink(STR(path)) < 0) msg_warn("remove %s: %m", STR(path)); continue; } - if (stat(mail_queue_path(path, MAIL_QUEUE_FLUSH, site), &st) < 0) { + if (stat(STR(path), &st) < 0) { if (errno != ENOENT) msg_warn("%s: stat %s: %m", myname, STR(path)); else if (msg_verbose) @@ -316,22 +412,28 @@ static void flush_purge(void) continue; } if (st.st_size == 0) { - if (st.st_mtime + FLUSH_MAX_UNUSED < event_time()) { + if (st.st_mtime + var_fflush_purge < event_time()) { if (unlink(STR(path)) < 0) msg_warn("remove %s: %m", STR(path)); else if (msg_verbose) - msg_info("%s: unlink %s, unused for %d days", - myname, STR(path), FLUSH_MAX_UNUSED / 84600); + msg_info("%s: unlink %s, empty and unchanged for %d days", + myname, STR(path), var_fflush_purge / 86400); } else if (msg_verbose) msg_info("%s: skip site %s - empty log", myname, site); - } else { + } else if (st.st_atime + var_fflush_refresh < event_time()) { if (msg_verbose) msg_info("%s: flush site %s", myname, site); - flush_site(site); + flush_send_service(site); + } else { + if (msg_verbose) + msg_info("%s: skip site %s, unread for <%d hours(s) ", + myname, site, var_fflush_refresh / 3600); } } scan_dir_close(scan); vstring_free(path); + + return (FLUSH_STAT_OK); } /* flush_service - perform service for client */ @@ -340,13 +442,13 @@ static void flush_service(VSTREAM *client_stream, char *unused_service, char **argv) { VSTRING *request = vstring_alloc(10); - VSTRING *site = vstring_alloc(10); - VSTRING *queue_id = vstring_alloc(10); - int status = FLUSH_STAT_BAD; + VSTRING *site = 0; + VSTRING *queue_id = 0; static char wakeup[] = { /* master wakeup request */ TRIGGER_REQ_WAKEUP, 0, }; + int status = FLUSH_STAT_OK; /* * Sanity check. This service takes no command-line arguments. @@ -364,44 +466,51 @@ static void flush_service(VSTREAM *client_stream, char *unused_service, * * All connection-management stuff is handled by the common code in * single_server.c. - * - * Note that the purge operation only acknowledges receipt of the request - * and proceeds in the background. All other operations send their result - * status after the operation is completed. */ -#define STREQ(x,y) (strcmp((x), (y)) == 0) - if (mail_scan(client_stream, "%s", request) == 1) { - if (STREQ(STR(request), FLUSH_REQ_APPEND)) { + if (STREQ(STR(request), FLUSH_REQ_ADD)) { + site = vstring_alloc(10); + queue_id = vstring_alloc(10); if (mail_scan(client_stream, "%s %s", site, queue_id) == 2 && valid_hostname(STR(site)) - && mail_queue_id_ok(STR(queue_id))) - status = flush_append(STR(site), STR(queue_id)); - mail_print(client_stream, "%d", status); + && mail_queue_id_ok(STR(queue_id))) { + status = flush_add_service(STR(site), STR(queue_id)); + } } else if (STREQ(STR(request), FLUSH_REQ_SEND)) { + site = vstring_alloc(10); if (mail_scan(client_stream, "%s", site) == 1 - && valid_hostname(STR(site))) - status = flush_site(STR(site)); - mail_print(client_stream, "%d", status); - } else if (STREQ(STR(request), FLUSH_REQ_ENABLE)) { - if (mail_scan(client_stream, "%s", site) == 1 - && valid_hostname(STR(site))) - status = flush_enable(STR(site)); - mail_print(client_stream, "%d", status); + && valid_hostname(STR(site))) { + status = flush_send_service(STR(site)); + } } else if (STREQ(STR(request), FLUSH_REQ_PURGE) || STREQ(STR(request), wakeup)) { - mail_print(client_stream, "%d", FLUSH_STAT_OK); - flush_purge(); + status = flush_purge_service(); } } + mail_print(client_stream, "%d", status); vstring_free(request); - vstring_free(site); - vstring_free(queue_id); + if (site) + vstring_free(site); + if (queue_id) + vstring_free(queue_id); } /* main - pass control to the single-threaded skeleton */ int main(int argc, char **argv) { - single_server_main(argc, argv, flush_service, 0); + static CONFIG_TIME_TABLE time_table[] = { + VAR_FFLUSH_REFRESH, DEF_FFLUSH_REFRESH, &var_fflush_refresh, 1, 0, + VAR_FFLUSH_PURGE, DEF_FFLUSH_PURGE, &var_fflush_purge, 1, 0, + 0, + }; + static CONFIG_STR_TABLE str_table[] = { + VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0, + 0, + }; + + single_server_main(argc, argv, flush_service, + MAIL_SERVER_TIME_TABLE, time_table, + MAIL_SERVER_STR_TABLE, str_table, + 0); } diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 7c0498826..9c61b72a7 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -17,7 +17,8 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \ record.c remove.c resolve_clnt.c resolve_local.c rewrite_clnt.c \ sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \ timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \ - tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c + tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \ + flush_clnt.c mail_conf_time.c OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ debug_peer.o debug_process.o defer.o deliver_completed.o \ deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \ @@ -36,7 +37,8 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ record.o remove.o resolve_clnt.o resolve_local.o rewrite_clnt.o \ sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \ timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \ - tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o + tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \ + flush_clnt.o mail_conf_time.o HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ config.h debug_peer.h debug_process.h defer.h deliver_completed.h \ deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \ @@ -51,7 +53,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ quote_821_local.h quote_822_local.h rec_streamlf.h rec_type.h \ recipient_list.h record.h resolve_clnt.h resolve_local.h \ rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \ - sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h + sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h TESTSRC = rec2stream.c stream2rec.c recdump.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ @@ -64,7 +66,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \ mail_addr_map mail_date maps mynetworks mypwd namadr_list \ off_cvt peer_name quote_822_local rec2stream recdump resolve_clnt \ resolve_local rewrite_clnt stream2rec string_list tok822_parse \ - quote_821_local + quote_821_local mail_conf_time LIBS = ../../lib/libutil.a LIB_DIR = ../../lib @@ -202,6 +204,11 @@ peer_name: $(LIB) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o +mail_conf_time: $(LIB) $(LIBS) + mv $@.o junk + $(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) + mv junk $@.o + tests: tok822_test tok822_test: tok822_parse tok822_parse.in tok822_parse.ref @@ -310,8 +317,7 @@ defer.o: mail_queue.h defer.o: ../../include/vstream.h defer.o: mail_proto.h defer.o: ../../include/iostuff.h -defer.o: mail_params.h -defer.o: mail_flush.h +defer.o: flush_clnt.h defer.o: bounce.h defer.o: defer.h deliver_completed.o: deliver_completed.c @@ -386,6 +392,16 @@ file_id.o: ../../include/msg.h file_id.o: ../../include/vstring.h file_id.o: ../../include/vbuf.h file_id.o: file_id.h +flush_clnt.o: flush_clnt.c +flush_clnt.o: ../../include/sys_defs.h +flush_clnt.o: ../../include/msg.h +flush_clnt.o: ../../include/vstream.h +flush_clnt.o: ../../include/vbuf.h +flush_clnt.o: mail_proto.h +flush_clnt.o: ../../include/iostuff.h +flush_clnt.o: mail_flush.h +flush_clnt.o: flush_clnt.h +flush_clnt.o: mail_params.h header_opts.o: header_opts.c header_opts.o: ../../include/sys_defs.h header_opts.o: ../../include/msg.h @@ -503,6 +519,17 @@ mail_conf_str.o: ../../include/sys_defs.h mail_conf_str.o: ../../include/msg.h mail_conf_str.o: ../../include/mymalloc.h mail_conf_str.o: mail_conf.h +mail_conf_time.o: mail_conf_time.c +mail_conf_time.o: ../../include/sys_defs.h +mail_conf_time.o: ../../include/msg.h +mail_conf_time.o: ../../include/mymalloc.h +mail_conf_time.o: ../../include/dict.h +mail_conf_time.o: ../../include/vstream.h +mail_conf_time.o: ../../include/vbuf.h +mail_conf_time.o: ../../include/argv.h +mail_conf_time.o: ../../include/stringops.h +mail_conf_time.o: ../../include/vstring.h +mail_conf_time.o: mail_conf.h mail_connect.o: mail_connect.c mail_connect.o: ../../include/sys_defs.h mail_connect.o: ../../include/msg.h @@ -541,13 +568,11 @@ mail_error.o: mail_error.h mail_error.o: ../../include/name_mask.h mail_flush.o: mail_flush.c mail_flush.o: ../../include/sys_defs.h -mail_flush.o: ../../include/msg.h +mail_flush.o: mail_proto.h mail_flush.o: ../../include/vstream.h mail_flush.o: ../../include/vbuf.h -mail_flush.o: mail_proto.h mail_flush.o: ../../include/iostuff.h mail_flush.o: mail_flush.h -mail_flush.o: mail_params.h mail_open_ok.o: mail_open_ok.c mail_open_ok.o: ../../include/sys_defs.h mail_open_ok.o: ../../include/msg.h @@ -620,7 +645,6 @@ mail_scan.o: ../../include/vstring_vstream.h mail_scan.o: ../../include/mymalloc.h mail_scan.o: mail_proto.h mail_scan.o: ../../include/iostuff.h -mail_scan.o: mail_params.h mail_scan_dir.o: mail_scan_dir.c mail_scan_dir.o: ../../include/sys_defs.h mail_scan_dir.o: ../../include/scan_dir.h diff --git a/postfix/src/global/defer.c b/postfix/src/global/defer.c index 1d934830f..83e8776b0 100644 --- a/postfix/src/global/defer.c +++ b/postfix/src/global/defer.c @@ -115,8 +115,7 @@ #include "mail_queue.h" #include "mail_proto.h" -#include "mail_params.h" -#include "mail_flush.h" +#include "flush_clnt.h" #include "bounce.h" #include "defer.h" @@ -155,12 +154,11 @@ int vdefer_append(int flags, const char *id, const char *recipient, vstring_free(why); /* - * Notify the fast flush service. + * Notify the fast flush service. XXX Should not this belong in the + * bounce/defer daemon? Well, doing it here is more robust. */ - if (*var_fast_flush_domains - && (rcpt_domain = strrchr(recipient, '@')) != 0 - && *++rcpt_domain != 0) - mail_flush_append(rcpt_domain, id); + if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0) + flush_add(rcpt_domain, id); return (-1); } diff --git a/postfix/src/global/deliver_request.c b/postfix/src/global/deliver_request.c index 3263c2d63..fee68b991 100644 --- a/postfix/src/global/deliver_request.c +++ b/postfix/src/global/deliver_request.c @@ -40,8 +40,6 @@ /* opens the queue file, and acquires a shared lock. /* A null result means that the client sent bad information or that /* it went away unexpectedly. -/* If the fast flush service is enabled, deliver_request_read() -/* initializes the client-side fast flush duplicate filter. /* /* The \fBflags\fR structure member is the bit-wise OR of zero or more /* of the following: @@ -101,8 +99,6 @@ #include "mail_queue.h" #include "mail_proto.h" -#include "mail_params.h" -#include "mail_flush.h" #include "mail_open_ok.h" #include "recipient_list.h" #include "deliver_request.h" @@ -316,16 +312,8 @@ DELIVER_REQUEST *deliver_request_read(VSTREAM *stream) request = deliver_request_alloc(); if (deliver_request_get(stream, request) < 0) { deliver_request_free(request); - return (0); + request = 0; } - - /* - * Make sure the mail flush dupfilter sees no false positive if we're - * repeatedly delivering the same message. - */ - if (*var_fast_flush_domains) - mail_flush_append_init(); - return (request); } diff --git a/postfix/src/global/flush_clnt.c b/postfix/src/global/flush_clnt.c new file mode 100644 index 000000000..3e28b8825 --- /dev/null +++ b/postfix/src/global/flush_clnt.c @@ -0,0 +1,188 @@ +/*++ +/* NAME +/* flush_clnt 3 +/* SUMMARY +/* fast flush cache manager client interface +/* SYNOPSIS +/* #include +/* +/* int flush_add(site, queue_id) +/* const char *site; +/* const char *queue_id; +/* +/* int flush_send(site) +/* const char *site; +/* +/* int flush_purge() +/* DESCRIPTION +/* The following routines operate through the "fast flush" service. +/* This service maintains a cache of what mail is queued. The cache +/* is maintained for eligible destinations. A destination is the +/* right-hand side of a user@domain email address. +/* +/* flush_add() informs the "fast flush" cache manager that mail is +/* queued for the specified site with the specified queue ID. +/* +/* flush_send() requests delivery of all mail that is queued for +/* the specified destination. +/* +/* flush_purge() requests the "fast flush" cache manager to refresh +/* cached information that was not used or not updated for some +/* configurable amount of time. +/* DIAGNOSTICS +/* The result codes and their meanings are (see flush_clnt(5h)): +/* .IP MAIL_FLUSH_OK +/* The request completed successfully. +/* .IP MAIL_FLUSH_FAIL +/* The request failed (the request could not be sent to the server, +/* or the server reported failure). +/* .IP MAIL_FLUSH_BAD +/* The "fast flush" server rejected the request (invalid request +/* parameter). +/* SEE ALSO +/* flush(8) Postfix fast flush cache manager +/* 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 "sys_defs.h" +#include +#include + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include +#include +#include +#include + +/* Application-specific. */ + +#define STR(x) vstring_str(x) + +/* flush_clnt - generic fast flush service client */ + +static int flush_clnt(const char *format,...) +{ + VSTREAM *flush; + int status; + va_list ap; + + /* + * Connect to the fast flush service over local IPC. + */ + if ((flush = mail_connect(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, + BLOCKING)) == 0) + return (FLUSH_STAT_FAIL); + + /* + * Do not get stuck forever. + */ + vstream_control(flush, + VSTREAM_CTL_TIMEOUT, var_ipc_timeout, + VSTREAM_CTL_END); + + /* + * Send a request with the site name, and receive the request acceptance + * status. + */ + va_start(ap, format); + mail_vprint(flush, format, ap); + va_end(ap); + if (mail_scan(flush, "%d", &status) != 1) + status = FLUSH_STAT_FAIL; + + /* + * Clean up. + */ + vstream_fclose(flush); + + return (status); +} + +/* flush_purge - house keeping */ + +int flush_purge(void) +{ + char *myname = "flush_purge"; + int status; + + if (msg_verbose) + msg_info("%s", myname); + + /* + * Don't bother the server if the service is turned off. + */ + if (strcmp(var_fflush_policy, FFLUSH_POLICY_NONE) == 0) + status = FLUSH_STAT_OK; + else + status = flush_clnt("%s", FLUSH_REQ_PURGE); + + if (msg_verbose) + msg_info("%s: status %d", myname, status); + + return (status); +} + +/* flush_send - deliver mail queued for site */ + +int flush_send(const char *site) +{ + char *myname = "flush_send"; + int status; + + if (msg_verbose) + msg_info("%s: site %s", myname, site); + + /* + * Don't bother the server if the service is turned off. + */ + if (strcmp(var_fflush_policy, FFLUSH_POLICY_NONE) == 0) + status = mail_flush_deferred(); + else + status = flush_clnt("%s %s", FLUSH_REQ_SEND, site); + + if (msg_verbose) + msg_info("%s: site %s status %d", myname, site, status); + + return (status); +} + +/* flush_add - inform "fast flush" cache manager */ + +int flush_add(const char *site, const char *queue_id) +{ + char *myname = "flush_add"; + int status; + + if (msg_verbose) + msg_info("%s: site %s id %s", myname, site, queue_id); + + /* + * Don't bother the server if the service is turned off. + */ + if (strcmp(var_fflush_policy, FFLUSH_POLICY_NONE) == 0) + status = FLUSH_STAT_OK; + else + status = flush_clnt("%s %s %s", FLUSH_REQ_ADD, site, queue_id); + + if (msg_verbose) + msg_info("%s: site %s id %s status %d", myname, site, queue_id, + status); + + return (status); +} diff --git a/postfix/src/global/flush_clnt.h b/postfix/src/global/flush_clnt.h new file mode 100644 index 000000000..7838e7a14 --- /dev/null +++ b/postfix/src/global/flush_clnt.h @@ -0,0 +1,47 @@ +#ifndef _FLUSH_CLNT_H_INCLUDED_ +#define _FLUSH_CLNT_H_INCLUDED_ + +/*++ +/* NAME +/* flush_clnt 3h +/* SUMMARY +/* flush backed up mail +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * External interface. + */ +extern int flush_add(const char *, const char *); +extern int flush_send(const char *); +extern int flush_purge(void); + + /* + * Mail flush server requests. + */ +#define FLUSH_REQ_ADD "add" /* append queue ID to site log */ +#define FLUSH_REQ_SEND "send" /* flush mail queued for site */ +#define FLUSH_REQ_PURGE "purge" /* refresh or delete old info */ + + /* + * Mail flush server status codes. + */ +#define FLUSH_STAT_FAIL -1 /* request failed */ +#define FLUSH_STAT_OK 0 /* request executed */ +#define FLUSH_STAT_BAD 3 /* invalid parameter */ + + +/* 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 diff --git a/postfix/src/global/mail_conf.h b/postfix/src/global/mail_conf.h index 1d77f145c..55dbf5836 100644 --- a/postfix/src/global/mail_conf.h +++ b/postfix/src/global/mail_conf.h @@ -46,9 +46,11 @@ extern const char *mail_conf_lookup_eval(const char *); extern char *get_mail_conf_str(const char *, const char *, int, int); extern int get_mail_conf_int(const char *, int, int, int); extern int get_mail_conf_bool(const char *, int); +extern int get_mail_conf_time(const char *, const char *, int, int); extern char *get_mail_conf_raw(const char *, const char *, int, int); extern int get_mail_conf_int2(const char *, const char *, int, int, int); +extern int get_mail_conf_time2(const char *, const char *, const char *, int, int); /* * Lookup with function-call defaults. @@ -56,6 +58,7 @@ extern int get_mail_conf_int2(const char *, const char *, int, int, int); extern char *get_mail_conf_str_fn(const char *, const char *(*) (void), int, int); extern int get_mail_conf_int_fn(const char *, int (*) (void), int, int); extern int get_mail_conf_bool_fn(const char *, int (*) (void)); +extern int get_mail_conf_time_fn(const char *, const char *(*) (void), int, int); extern char *get_mail_conf_raw_fn(const char *, const char *(*) (void), int, int); /* @@ -64,6 +67,7 @@ extern char *get_mail_conf_raw_fn(const char *, const char *(*) (void), int, int extern void set_mail_conf_str(const char *, const char *); extern void set_mail_conf_int(const char *, int); extern void set_mail_conf_bool(const char *, int); +extern void set_mail_conf_time(const char *, const char *); /* * Tables that allow us to selectively copy values from the global @@ -91,9 +95,18 @@ typedef struct { int *target; /* pointer to global variable */ } CONFIG_BOOL_TABLE; +typedef struct { + const char *name; /* config variable name */ + const char *defval; /* default value */ + int *target; /* pointer to global variable */ + int min; /* lower bound or zero */ + int max; /* upper bound or zero */ +} CONFIG_TIME_TABLE; + extern void get_mail_conf_str_table(CONFIG_STR_TABLE *); extern void get_mail_conf_int_table(CONFIG_INT_TABLE *); extern void get_mail_conf_bool_table(CONFIG_BOOL_TABLE *); +extern void get_mail_conf_time_table(CONFIG_TIME_TABLE *); extern void get_mail_conf_raw_table(CONFIG_STR_TABLE *); /* @@ -122,9 +135,18 @@ typedef struct { int *target; /* pointer to global variable */ } CONFIG_BOOL_FN_TABLE; +typedef struct { + const char *name; /* config variable name */ + const char *(*defval) (void); /* default value provider */ + int *target; /* pointer to global variable */ + int min; /* lower bound or zero */ + int max; /* upper bound or zero */ +} CONFIG_TIME_FN_TABLE; + extern void get_mail_conf_str_fn_table(CONFIG_STR_FN_TABLE *); extern void get_mail_conf_int_fn_table(CONFIG_INT_FN_TABLE *); extern void get_mail_conf_bool_fn_table(CONFIG_BOOL_FN_TABLE *); +extern void get_mail_conf_time_fn_table(CONFIG_TIME_FN_TABLE *); extern void get_mail_conf_raw_fn_table(CONFIG_STR_FN_TABLE *); /* LICENSE diff --git a/postfix/src/global/mail_conf_time.c b/postfix/src/global/mail_conf_time.c new file mode 100644 index 000000000..7a6c1ec28 --- /dev/null +++ b/postfix/src/global/mail_conf_time.c @@ -0,0 +1,260 @@ +/*++ +/* NAME +/* mail_conf_time 3 +/* SUMMARY +/* time interval configuration parameter support +/* SYNOPSIS +/* #include +/* +/* int get_mail_conf_time(name, defval, min, max); +/* const char *name; +/* const char *defval; +/* int min; +/* int max; +/* +/* int get_mail_conf_time_fn(name, defval, min, max); +/* const char *name; +/* const char *(*defval)(); +/* int min; +/* int max; +/* +/* void set_mail_conf_time(name, value) +/* const char *name; +/* const char *value; +/* +/* void get_mail_conf_time_table(table) +/* CONFIG_INT_TABLE *table; +/* +/* void get_mail_conf_time_fn_table(table) +/* CONFIG_INT_TABLE *table; +/* AUXILIARY FUNCTIONS +/* int get_mail_conf_time2(name1, name2, defval, min, max); +/* const char *name1; +/* const char *name2; +/* const char *defval; +/* int min; +/* int max; +/* DESCRIPTION +/* This module implements configuration parameter support +/* for time interval values. By default, times are specified +/* in units of seconds, but the conversion routines understand +/* one-letter suffixes to specify an explicit time unit: s +/* (seconds), m (minutes), h (hours), d (days) or w (weeks). +/* +/* get_mail_conf_time() looks up the named entry in the global +/* configuration dictionary. The default value is returned +/* when no value was found. +/* \fImin\fR is zero or specifies a lower limit on the integer +/* value or string length; \fImax\fR is zero or specifies an +/* upper limit on the integer value or string length. +/* +/* get_mail_conf_time_fn() is similar but specifies a function that +/* provides the default value. The function is called only +/* when the default value is needed. +/* +/* set_mail_conf_time() updates the named entry in the global +/* configuration dictionary. This has no effect on values that +/* have been looked up earlier via the get_mail_conf_XXX() routines. +/* +/* get_mail_conf_time_table() and get_mail_conf_time_fn_table() initialize +/* lists of variables, as directed by their table arguments. A table +/* must be terminated by a null entry. +/* +/* get_mail_conf_time2() concatenates the two names and is otherwise +/* identical to get_mail_conf_time(). +/* DIAGNOSTICS +/* Fatal errors: malformed numerical value, unknown time unit. +/* SEE ALSO +/* config(3) general configuration +/* mail_conf_str(3) string-valued configuration parameters +/* 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 +#include /* sscanf() */ + +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + +#include "mail_conf.h" + +#define MINUTE (60) +#define HOUR (60 * MINUTE) +#define DAY (24 * HOUR) +#define WEEK (7 * DAY) + +/* convert_mail_conf_time - look up and convert integer parameter value */ + +static int convert_mail_conf_time(const char *name, int *intval) +{ + const char *strval; + char unit; + char junk; + + if ((strval = mail_conf_lookup_eval(name)) != 0) { + if (sscanf(strval, "%d%c%c", intval, &unit, &junk) == 2) { + switch (unit) { + case 'w': + *intval *= WEEK; + return (1); + case 'd': + *intval *= DAY; + return (1); + case 'h': + *intval *= HOUR; + return (1); + case 'm': + *intval *= MINUTE; + return (1); + case 's': + return (1); + break; + default: + msg_fatal("bad time unit: %s", strval); + } + } + if (sscanf(strval, "%d%c", intval, &junk) != 1) + msg_fatal("bad numerical configuration: %s = %s", name, strval); + return (1); + } + return (0); +} + +/* check_mail_conf_time - validate integer value */ + +static void check_mail_conf_time(const char *name, int intval, int min, int max) +{ + if (min && intval < min) + msg_fatal("invalid %s: %d (min %d)", name, intval, min); + if (max && intval > max) + msg_fatal("invalid %s: %d (max %d)", name, intval, max); +} + +/* get_mail_conf_time - evaluate integer-valued configuration variable */ + +int get_mail_conf_time(const char *name, const char *defval, int min, int max) +{ + int intval; + + if (convert_mail_conf_time(name, &intval) == 0) + set_mail_conf_time(name, defval); + if (convert_mail_conf_time(name, &intval) == 0) + msg_panic("get_mail_conf_time: parameter not found: %s", name); + check_mail_conf_time(name, intval, min, max); + return (intval); +} + +/* get_mail_conf_time2 - evaluate integer-valued configuration variable */ + +int get_mail_conf_time2(const char *name1, const char *name2, + const char *defval, int min, int max) +{ + int intval; + char *name; + + name = concatenate(name1, name2, (char *) 0); + if (convert_mail_conf_time(name, &intval) == 0) + set_mail_conf_time(name, defval); + if (convert_mail_conf_time(name, &intval) == 0) + msg_panic("get_mail_conf_time2: parameter not found: %s", name); + check_mail_conf_time(name, intval, min, max); + myfree(name); + return (intval); +} + +/* get_mail_conf_time_fn - evaluate integer-valued configuration variable */ + +typedef const char *(*stupid_indent_time) (void); + +int get_mail_conf_time_fn(const char *name, stupid_indent_time defval, + int min, int max) +{ + int intval; + + if (convert_mail_conf_time(name, &intval) == 0) + set_mail_conf_time(name, defval()); + if (convert_mail_conf_time(name, &intval) == 0) + msg_panic("get_mail_conf_time_fn: parameter not found: %s", name); + check_mail_conf_time(name, intval, min, max); + return (intval); +} + +/* set_mail_conf_time - update integer-valued configuration dictionary entry */ + +void set_mail_conf_time(const char *name, const char *value) +{ + mail_conf_update(name, value); +} + +/* get_mail_conf_time_table - look up table of integers */ + +void get_mail_conf_time_table(CONFIG_TIME_TABLE *table) +{ + while (table->name) { + table->target[0] = get_mail_conf_time(table->name, table->defval, + table->min, table->max); + table++; + } +} + +/* get_mail_conf_time_fn_table - look up integers, defaults are functions */ + +void get_mail_conf_time_fn_table(CONFIG_TIME_FN_TABLE *table) +{ + while (table->name) { + table->target[0] = get_mail_conf_time_fn(table->name, table->defval, + table->min, table->max); + table++; + } +} + +#ifdef TEST + + /* + * Stand-alone driver program for regression testing. + */ +#include + +int main(int unused_argc, char **unused_argv) +{ + static int seconds; + static int minutes; + static int hours; + static int days; + static int weeks; + static CONFIG_TIME_TABLE time_table[] = { + "seconds", "10s", &seconds, 0, 0, + "minutes", "10m", &minutes, 0, 0, + "hours", "10h", &hours, 0, 0, + "days", "10d", &days, 0, 0, + "weeks", "10w", &weeks, 0, 0, + 0, + }; + + get_mail_conf_time_table(time_table); + vstream_printf("seconds = %d\n", seconds); + vstream_printf("minutes = %d\n", minutes); + vstream_printf("hours = %d\n", hours); + vstream_printf("days = %d\n", days); + vstream_printf("weeks = %d\n", weeks); + vstream_fflush(VSTREAM_OUT); +} + +#endif diff --git a/postfix/src/global/mail_flush.c b/postfix/src/global/mail_flush.c index 9a236e26a..5e30e529a 100644 --- a/postfix/src/global/mail_flush.c +++ b/postfix/src/global/mail_flush.c @@ -2,70 +2,18 @@ /* NAME /* mail_flush 3 /* SUMMARY -/* mail flush service client interface +/* flush backed up mail /* SYNOPSIS /* #include /* /* int mail_flush_deferred() -/* -/* int mail_flush_purge() -/* -/* int mail_flush_enable(site) -/* const char *site; -/* -/* int mail_flush_site(site) -/* const char *site; -/* -/* int mail_flush_append(site, queue_id) -/* const char *site; -/* const char *queue_id; -/* -/* void mail_flush_append_init() /* DESCRIPTION -/* This module deals with delivery of delayed mail. +/* This module triggers delivery of backed up mail. /* /* mail_flush_deferred() triggers delivery of all deferred /* or incoming mail. -/* -/* The following services are available only for sites that have a -/* "fast flush" logfile. These files list all mail that is queued -/* for a given site, and are created on demand when, for example, -/* an eligible SMTP client issues the ETRN command. -/* -/* mail_flush_enable() enables the "fast flush" service for -/* the named site. -/* -/* mail_flush_site() uses the "fast flush" service to trigger -/* delivery of messages queued for the specified site. -/* -/* mail_flush_append() appends a record to the "fast flush" -/* logfile for the specified site, with the queue ID of mail -/* that still should be delivered. This routine uses a little -/* duplicate filter to avoid appending multiple identical -/* records when one has to defer multi-recipient mail. -/* -/* mail_flush_append_init() initializes a duplicate filter that is used -/* by mail_flush_append(). mail_flush_append_init() must be called once -/* before calling mail_flush_append() and must be called whenever -/* the application opens a new queue file, to prevent false -/* positives with the duplicate filter when repeated attempts -/* are made to deliver the same message. -/* -/* mail_flush_purge() requests the "fast flush" service to -/* flush all its "fast flush" logfiles. This is necessary -/* once a day or so, in order to prevent accumulation of -/* too much outdated information. /* DIAGNOSTICS -/* The result codes and their meaning are (see mail_flush(5h)): -/* .IP MAIL_FLUSH_OK -/* The request completed normally. -/* .IP MAIL_FLUSH_FAIL -/* The request failed. -/* .IP MAIL_FLUSH_UNKNOWN -/* The specified site has no "fast flush" logfile. -/* .IP MAIL_FLUSH_BAD -/* The "fast flush" server rejected the request (invalid request -/* parameter). +/* The result is 0 in case of success, -1 in case of failure. /* LICENSE /* .ad /* .fi @@ -80,28 +28,13 @@ /* System library. */ #include "sys_defs.h" -#include -#include /* Utility library. */ -#include -#include -#include - /* Global library. */ #include #include -#include - -/* Application-specific. */ - -#define STR(x) vstring_str(x) - -static VSTRING *mail_flush_saved_site; -static VSTRING *mail_flush_saved_id; -static int mail_flush_saved_status; /* mail_flush_deferred - flush deferred queue */ @@ -120,135 +53,3 @@ int mail_flush_deferred(void) return (mail_trigger(MAIL_CLASS_PUBLIC, MAIL_SERVICE_QUEUE, qmgr_trigger, sizeof(qmgr_trigger))); } - -/* mail_flush_append_init - initialize repeat filter */ - -void mail_flush_append_init(void) -{ - if (mail_flush_saved_site == 0) { - mail_flush_saved_site = vstring_alloc(10); - mail_flush_saved_id = vstring_alloc(10); - } - vstring_strcpy(mail_flush_saved_site, ""); - vstring_strcpy(mail_flush_saved_id, ""); -} - -/* mail_flush_cached - see if request repeats */ - -static int mail_flush_cached(const char *site, const char *queue_id) -{ - if (strcmp(STR(mail_flush_saved_site), site) == 0 - && strcmp(STR(mail_flush_saved_id), queue_id) == 0) { - return (1); - } else { - vstring_strcpy(mail_flush_saved_site, site); - vstring_strcpy(mail_flush_saved_id, queue_id); - return (0); - } -} - -/* mail_flush_clnt - generic fast flush service client */ - -static int mail_flush_clnt(const char *format,...) -{ - VSTREAM *flush; - int status; - va_list ap; - - /* - * Connect to the fast flush service over local IPC. - */ - if ((flush = mail_connect(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, - BLOCKING)) == 0) - return (FLUSH_STAT_FAIL); - - /* - * Do not get stuck forever. - */ - vstream_control(flush, - VSTREAM_CTL_TIMEOUT, var_ipc_timeout, - VSTREAM_CTL_END); - - /* - * Send a request with the site name, and receive the request completion - * status. - */ - va_start(ap, format); - mail_vprint(flush, format, ap); - va_end(ap); - if (mail_scan(flush, "%d", &status) != 1) - status = FLUSH_STAT_FAIL; - - /* - * Clean up. - */ - vstream_fclose(flush); - - return (status); -} - -/* mail_flush_enable - enable fast flush logging for site */ - -int mail_flush_enable(const char *site) -{ - char *myname = "mail_flush_enable"; - int status; - - if (msg_verbose) - msg_info("%s: site %s", myname, site); - status = mail_flush_clnt("%s %s", FLUSH_REQ_ENABLE, site); - if (msg_verbose) - msg_info("%s: site %s status %d", myname, site, status); - - return (status); -} - -/* mail_flush_purge - house keeping */ - -int mail_flush_purge(void) -{ - char *myname = "mail_flush_purge"; - int status; - - if (msg_verbose) - msg_info("%s", myname); - status = mail_flush_clnt("%s", FLUSH_REQ_SEND); - if (msg_verbose) - msg_info("%s: status %d", myname, status); - - return (status); -} - -/* mail_flush_site - flush deferred mail for site */ - -int mail_flush_site(const char *site) -{ - char *myname = "mail_flush_site"; - int status; - - if (msg_verbose) - msg_info("%s: site %s", myname, site); - status = mail_flush_clnt("%s %s", FLUSH_REQ_SEND, site); - if (msg_verbose) - msg_info("%s: site %s status %d", myname, site, status); - - return (status); -} - -/* mail_flush_append - append record to fast flush log */ - -int mail_flush_append(const char *site, const char *queue_id) -{ - char *myname = "mail_flush_append"; - - if (msg_verbose) - msg_info("%s: site %s id %s", myname, site, queue_id); - if (mail_flush_cached(site, queue_id) == 0) - mail_flush_saved_status = - mail_flush_clnt("%s %s %s", FLUSH_REQ_APPEND, site, queue_id); - if (msg_verbose) - msg_info("%s: site %s id %s status %d", myname, site, queue_id, - mail_flush_saved_status); - - return (mail_flush_saved_status); -} diff --git a/postfix/src/global/mail_flush.h b/postfix/src/global/mail_flush.h index bf25a0f7e..9d951682f 100644 --- a/postfix/src/global/mail_flush.h +++ b/postfix/src/global/mail_flush.h @@ -11,32 +11,9 @@ /* DESCRIPTION /* .nf - /* - * External interface. - */ + /* External interface. */ + extern int mail_flush_deferred(void); -extern int mail_flush_purge(void); -extern int mail_flush_enable(const char *); -extern int mail_flush_site(const char *); -extern int mail_flush_append(const char *, const char *); -extern void mail_flush_append_init(void); - - /* - * Mail flush server requests. - */ -#define FLUSH_REQ_APPEND "append"/* append queue ID to site log */ -#define FLUSH_REQ_SEND "send" /* flush mail queued for site */ -#define FLUSH_REQ_ENABLE "enable"/* flush mail queued for site */ -#define FLUSH_REQ_PURGE "purge" /* flush mail queued for site */ - - /* - * Mail flush server status codes. - */ -#define FLUSH_STAT_FAIL -1 /* everyone */ -#define FLUSH_STAT_OK 0 /* everyone */ -#define FLUSH_STAT_UNKNOWN 2 /* mail_flush_site() only */ -#define FLUSH_STAT_BAD 3 /* mail_flush_site() only */ - /* LICENSE /* .ad diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index 6f67a8ff4..34f58f81e 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -58,7 +58,7 @@ /* int var_ownreq_special; /* int var_daemon_timeout; /* char *var_syslog_facility; -/* char *var_fast_flush_domains; +/* char *var_fflush_policy; /* /* void mail_params_init() /* DESCRIPTION @@ -165,8 +165,7 @@ time_t var_starttime; int var_ownreq_special; int var_daemon_timeout; char *var_syslog_facility; -char *var_relay_domains; -char *var_fast_flush_domains; +char *var_fflush_policy; /* check_myhostname - lookup hostname and validate */ @@ -277,8 +276,7 @@ void mail_params_init() VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0, VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0, VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1, - VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0, - VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fast_flush_domains, 0, 0, + VAR_FFLUSH_POLICY, DEF_FFLUSH_POLICY, &var_fflush_policy, 1, 0, 0, }; static CONFIG_STR_FN_TABLE function_str_defaults_2[] = { diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index c0f7520c9..14ee16569 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -490,7 +490,7 @@ extern int var_min_delivery_slots; extern int var_qmgr_fudge; #define VAR_QMGR_HOG "qmgr_site_hog_factor" -#define DEF_QMGR_HOG 90 +#define DEF_QMGR_HOG 100 extern int var_qmgr_hog; /* @@ -1067,9 +1067,21 @@ extern char *var_filter_xport; /* * Fast flush service support. */ -#define VAR_FFLUSH_DOMAINS "fast_flush_domains" -#define DEF_FFLUSH_DOMAINS "$relay_domains" -extern char *var_fast_flush_domains; +#define VAR_FFLUSH_POLICY "fast_flush_policy" +#define DEF_FFLUSH_POLICY FFLUSH_POLICY_RELAY +extern char *var_fflush_policy; + +#define FFLUSH_POLICY_ALL "all" +#define FFLUSH_POLICY_RELAY "relay" +#define FFLUSH_POLICY_NONE "none" + +#define VAR_FFLUSH_PURGE "fast_flush_purge_delay" +#define DEF_FFLUSH_PURGE "7d" +extern int var_fflush_purge; + +#define VAR_FFLUSH_REFRESH "fast_flush_refresh_delay" +#define DEF_FFLUSH_REFRESH "12h" +extern int var_fflush_refresh; /* LICENSE /* .ad diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index b33abbdce..36a91dc5e 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-20001001" +#define DEF_MAIL_VERSION "Snapshot-20001003" extern char *var_mail_version; /* LICENSE diff --git a/postfix/src/master/mail_server.h b/postfix/src/master/mail_server.h index 4e3c9b74e..d03313b1e 100644 --- a/postfix/src/master/mail_server.h +++ b/postfix/src/master/mail_server.h @@ -19,7 +19,8 @@ #define MAIL_SERVER_INT_TABLE 1 #define MAIL_SERVER_STR_TABLE 2 #define MAIL_SERVER_BOOL_TABLE 3 -#define MAIL_SERVER_RAW_TABLE 4 +#define MAIL_SERVER_TIME_TABLE 4 +#define MAIL_SERVER_RAW_TABLE 5 #define MAIL_SERVER_PRE_INIT 10 #define MAIL_SERVER_POST_INIT 11 diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c index f6c80ee7e..7a1c5dab6 100644 --- a/postfix/src/master/multi_server.c +++ b/postfix/src/master/multi_server.c @@ -56,6 +56,11 @@ /* global Postfix configuration file. Tables are loaded in the /* order as specified, and multiple instances of the same type /* are allowed. +/* .IP "MAIL_SERVER_TIME_TABLE (CONFIG_TIME_TABLE *)" +/* A table with configurable parameters, to be loaded from the +/* global Postfix configuration file. Tables are loaded in the +/* order as specified, and multiple instances of the same type +/* are allowed. /* .IP "MAIL_SERVER_RAW_TABLE (CONFIG_STR_TABLE *)" /* A table with configurable parameters, to be loaded from the /* global Postfix configuration file. Tables are loaded in the @@ -469,6 +474,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) case MAIL_SERVER_BOOL_TABLE: get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *)); break; + case MAIL_SERVER_TIME_TABLE: + get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *)); + break; case MAIL_SERVER_RAW_TABLE: get_mail_conf_raw_table(va_arg(ap, CONFIG_STR_TABLE *)); break; diff --git a/postfix/src/master/single_server.c b/postfix/src/master/single_server.c index 2227d11e6..b1319c33d 100644 --- a/postfix/src/master/single_server.c +++ b/postfix/src/master/single_server.c @@ -51,6 +51,11 @@ /* global Postfix configuration file. Tables are loaded in the /* order as specified, and multiple instances of the same type /* are allowed. +/* .IP "MAIL_SERVER_TIME_TABLE (CONFIG_TIME_TABLE *)" +/* A table with configurable parameters, to be loaded from the +/* global Postfix configuration file. Tables are loaded in the +/* order as specified, and multiple instances of the same type +/* are allowed. /* .IP "MAIL_SERVER_RAW_TABLE (CONFIG_STR_TABLE *)" /* A table with configurable parameters, to be loaded from the /* global Postfix configuration file. Tables are loaded in the @@ -441,6 +446,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) case MAIL_SERVER_BOOL_TABLE: get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *)); break; + case MAIL_SERVER_TIME_TABLE: + get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *)); + break; case MAIL_SERVER_RAW_TABLE: get_mail_conf_raw_table(va_arg(ap, CONFIG_STR_TABLE *)); break; diff --git a/postfix/src/master/trigger_server.c b/postfix/src/master/trigger_server.c index 8ea502a68..8a958ff45 100644 --- a/postfix/src/master/trigger_server.c +++ b/postfix/src/master/trigger_server.c @@ -58,6 +58,11 @@ /* global Postfix configuration file. Tables are loaded in the /* order as specified, and multiple instances of the same type /* are allowed. +/* .IP "MAIL_SERVER_TIME_TABLE (CONFIG_TIME_TABLE *)" +/* A table with configurable parameters, to be loaded from the +/* global Postfix configuration file. Tables are loaded in the +/* order as specified, and multiple instances of the same type +/* are allowed. /* .IP "MAIL_SERVER_RAW_TABLE (CONFIG_STR_TABLE *)" /* A table with configurable parameters, to be loaded from the /* global Postfix configuration file. Tables are loaded in the @@ -441,6 +446,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. case MAIL_SERVER_BOOL_TABLE: get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *)); break; + case MAIL_SERVER_TIME_TABLE: + get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *)); + break; case MAIL_SERVER_RAW_TABLE: get_mail_conf_raw_table(va_arg(ap, CONFIG_STR_TABLE *)); break; diff --git a/postfix/src/nqmgr/Makefile.in b/postfix/src/nqmgr/Makefile.in index 2dbf6abc5..6a006a7cc 100644 --- a/postfix/src/nqmgr/Makefile.in +++ b/postfix/src/nqmgr/Makefile.in @@ -95,7 +95,6 @@ qmgr_active.o: ../../include/recipient_list.h qmgr_active.o: ../../include/bounce.h qmgr_active.o: ../../include/defer.h qmgr_active.o: ../../include/rec_type.h -qmgr_active.o: ../../include/mail_flush.h qmgr_active.o: qmgr.h qmgr_active.o: ../../include/scan_dir.h qmgr_active.o: ../../include/maps.h @@ -264,6 +263,7 @@ qmgr_scan.o: ../../include/msg.h qmgr_scan.o: ../../include/mymalloc.h qmgr_scan.o: ../../include/scan_dir.h qmgr_scan.o: ../../include/mail_scan_dir.h +qmgr_scan.o: ../../include/flush_clnt.h qmgr_scan.o: qmgr.h qmgr_scan.o: ../../include/vstream.h qmgr_scan.o: ../../include/vbuf.h diff --git a/postfix/src/nqmgr/qmgr_active.c b/postfix/src/nqmgr/qmgr_active.c index 5de091bea..9ba5a7dab 100644 --- a/postfix/src/nqmgr/qmgr_active.c +++ b/postfix/src/nqmgr/qmgr_active.c @@ -103,7 +103,6 @@ #include #include #include -#include /* Application-specific. */ @@ -227,13 +226,6 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) */ if (message->refcount == 0) qmgr_active_done(message); - - /* - * Make sure the mail flush dupfilter sees no false positive if we're - * repeatedly trying to deliver the same message. - */ - else if (*var_fast_flush_domains) - mail_flush_append_init(); } } diff --git a/postfix/src/nqmgr/qmgr_message.c b/postfix/src/nqmgr/qmgr_message.c index e294bd530..dfbb93e62 100644 --- a/postfix/src/nqmgr/qmgr_message.c +++ b/postfix/src/nqmgr/qmgr_message.c @@ -697,7 +697,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) * Optionally defer deliveries over specific transports, unless the * restriction is lifted temporarily. */ - if (*var_defer_xports && (message->qflags & QMGR_SCAN_ALL) == 0) { + if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DEAD) == 0) { if (defer_xport_argv == 0) defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,"); for (cpp = defer_xport_argv->argv; *cpp; cpp++) diff --git a/postfix/src/nqmgr/qmgr_scan.c b/postfix/src/nqmgr/qmgr_scan.c index e0d9fc079..71532fcfc 100644 --- a/postfix/src/nqmgr/qmgr_scan.c +++ b/postfix/src/nqmgr/qmgr_scan.c @@ -67,6 +67,7 @@ /* Global library. */ #include +#include /* Application-specific. */ @@ -100,6 +101,14 @@ static void qmgr_scan_start(QMGR_SCAN *scan_info) if (scan_info->nflags & QMGR_FLUSH_DEAD) qmgr_enable_all(); + /* + * Optionally inform the fast flush cache manager that we're attempting + * to deliver all queued mail. + */ + if ((scan_info->nflags & QMGR_FLUSH_DEAD) + && (scan_info->nflags & QMGR_SCAN_ALL)) + flush_purge(); + /* * Start or restart the scan. */ diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in index 1235c7ebb..deebdbacf 100644 --- a/postfix/src/postconf/Makefile.in +++ b/postfix/src/postconf/Makefile.in @@ -10,7 +10,7 @@ DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= MAKES = bool_table.h bool_vars.h int_table.h int_vars.h str_table.h \ - str_vars.h + str_vars.h time_table.h time_vars.h PROG = postconf SAMPLES = ../../conf/main.cf.default INC_DIR = ../../include @@ -88,11 +88,13 @@ postconf.o: ../../include/iostuff.h postconf.o: ../../include/mail_version.h postconf.o: ../../include/mail_params.h postconf.o: ../../include/mail_addr.h +postconf.o: time_vars.h postconf.o: bool_vars.h postconf.o: int_vars.h postconf.o: str_vars.h postconf.o: local_vars.h postconf.o: smtp_vars.h +postconf.o: time_table.h postconf.o: bool_table.h postconf.o: int_table.h postconf.o: str_table.h diff --git a/postfix/src/postconf/extract.awk b/postfix/src/postconf/extract.awk index ebe866e29..3e0663982 100644 --- a/postfix/src/postconf/extract.awk +++ b/postfix/src/postconf/extract.awk @@ -18,6 +18,12 @@ print | "sed 's/[ ][ ]*/ /g' | sort -u >bool_table.h" } } +/^(static| )*CONFIG_TIME_TABLE .*\{/,/\};/ { + if ($1 ~ /VAR/) { + print "int " substr($3,2,length($3)-2) ";" > "time_vars.h" + print | "sed 's/[ ][ ]*/ /g' | sort -u >time_table.h" + } +} # Workaround for broken gawk versions. diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index 9062d63af..30a7cee47 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -116,6 +116,7 @@ DICT *text_table; /* * Declarations generated by scanning actual C source files. */ +#include "time_vars.h" #include "bool_vars.h" #include "int_vars.h" #include "str_vars.h" @@ -129,6 +130,11 @@ DICT *text_table; /* * Lookup tables generated by scanning actual C source files. */ +static CONFIG_TIME_TABLE time_table[] = { +#include "time_table.h" + 0, +}; + static CONFIG_BOOL_TABLE bool_table[] = { #include "bool_table.h" 0, @@ -394,6 +400,7 @@ static void read_parameters(void) static void hash_parameters(void) { + CONFIG_TIME_TABLE *ctt; CONFIG_BOOL_TABLE *cbt; CONFIG_INT_TABLE *cit; CONFIG_STR_TABLE *cst; @@ -401,6 +408,8 @@ static void hash_parameters(void) param_table = htable_create(100); + for (ctt = time_table; ctt->name; ctt++) + htable_enter(param_table, ctt->name, (char *) ctt); for (cbt = bool_table; cbt->name; cbt++) htable_enter(param_table, cbt->name, (char *) cbt); for (cit = int_table; cit->name; cit++) @@ -458,6 +467,29 @@ static void print_bool(int mode, CONFIG_BOOL_TABLE *cbt) } } +/* print_time - print relative time parameter */ + +static void print_time(int mode, CONFIG_TIME_TABLE * ctt) +{ + const char *value; + + if (mode & SHOW_DEFS) { + show_strval(mode, ctt->name, ctt->defval); + } else { + value = dict_lookup(CONFIG_DICT, ctt->name); + if ((mode & SHOW_NONDEF) == 0) { + if (value == 0) { + show_strval(mode, ctt->name, ctt->defval); + } else { + show_strval(mode, ctt->name, value); + } + } else { + if (value != 0) + show_strval(mode, ctt->name, value); + } + } +} + /* print_int - print integer parameter */ static void print_int(int mode, CONFIG_INT_TABLE *cit) @@ -560,6 +592,8 @@ static void print_parameter(int mode, char *ptr) /* * This is gross, but the best we can do on short notice. */ + if (INSIDE(ptr, time_table)) + print_time(mode, (CONFIG_TIME_TABLE *) ptr); if (INSIDE(ptr, bool_table)) print_bool(mode, (CONFIG_BOOL_TABLE *) ptr); if (INSIDE(ptr, int_table)) diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index 23c7d75cd..040e3b044 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -93,7 +93,6 @@ qmgr_active.o: ../../include/recipient_list.h qmgr_active.o: ../../include/bounce.h qmgr_active.o: ../../include/defer.h qmgr_active.o: ../../include/rec_type.h -qmgr_active.o: ../../include/mail_flush.h qmgr_active.o: qmgr.h qmgr_active.o: ../../include/scan_dir.h qmgr_active.o: ../../include/maps.h @@ -236,6 +235,7 @@ qmgr_scan.o: ../../include/msg.h qmgr_scan.o: ../../include/mymalloc.h qmgr_scan.o: ../../include/scan_dir.h qmgr_scan.o: ../../include/mail_scan_dir.h +qmgr_scan.o: ../../include/flush_clnt.h qmgr_scan.o: qmgr.h qmgr_scan.o: ../../include/vstream.h qmgr_scan.o: ../../include/vbuf.h diff --git a/postfix/src/qmgr/qmgr_active.c b/postfix/src/qmgr/qmgr_active.c index 5de091bea..9ba5a7dab 100644 --- a/postfix/src/qmgr/qmgr_active.c +++ b/postfix/src/qmgr/qmgr_active.c @@ -103,7 +103,6 @@ #include #include #include -#include /* Application-specific. */ @@ -227,13 +226,6 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) */ if (message->refcount == 0) qmgr_active_done(message); - - /* - * Make sure the mail flush dupfilter sees no false positive if we're - * repeatedly trying to deliver the same message. - */ - else if (*var_fast_flush_domains) - mail_flush_append_init(); } } diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index 31f1a0e38..110f1e64d 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -580,7 +580,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) * Optionally defer deliveries over specific transports, unless the * restriction is lifted temporarily. */ - if (*var_defer_xports && (message->qflags & QMGR_SCAN_ALL) == 0) { + if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DEAD) == 0) { if (defer_xport_argv == 0) defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,"); for (cpp = defer_xport_argv->argv; *cpp; cpp++) diff --git a/postfix/src/qmgr/qmgr_scan.c b/postfix/src/qmgr/qmgr_scan.c index e0d9fc079..71532fcfc 100644 --- a/postfix/src/qmgr/qmgr_scan.c +++ b/postfix/src/qmgr/qmgr_scan.c @@ -67,6 +67,7 @@ /* Global library. */ #include +#include /* Application-specific. */ @@ -100,6 +101,14 @@ static void qmgr_scan_start(QMGR_SCAN *scan_info) if (scan_info->nflags & QMGR_FLUSH_DEAD) qmgr_enable_all(); + /* + * Optionally inform the fast flush cache manager that we're attempting + * to deliver all queued mail. + */ + if ((scan_info->nflags & QMGR_FLUSH_DEAD) + && (scan_info->nflags & QMGR_SCAN_ALL)) + flush_purge(); + /* * Start or restart the scan. */ diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in index 66a63f31f..acbbef24b 100644 --- a/postfix/src/sendmail/Makefile.in +++ b/postfix/src/sendmail/Makefile.in @@ -59,10 +59,10 @@ sendmail.o: ../../include/msg.h sendmail.o: ../../include/mymalloc.h sendmail.o: ../../include/vstream.h sendmail.o: ../../include/vbuf.h -sendmail.o: ../../include/vstring.h sendmail.o: ../../include/msg_vstream.h sendmail.o: ../../include/msg_syslog.h sendmail.o: ../../include/vstring_vstream.h +sendmail.o: ../../include/vstring.h sendmail.o: ../../include/username.h sendmail.o: ../../include/fullname.h sendmail.o: ../../include/argv.h @@ -70,6 +70,7 @@ sendmail.o: ../../include/safe.h sendmail.o: ../../include/iostuff.h sendmail.o: ../../include/stringops.h sendmail.o: ../../include/set_ugid.h +sendmail.o: ../../include/connect.h sendmail.o: ../../include/mail_queue.h sendmail.o: ../../include/mail_proto.h sendmail.o: ../../include/mail_params.h @@ -85,3 +86,4 @@ sendmail.o: ../../include/tok822.h sendmail.o: ../../include/resolve_clnt.h sendmail.o: ../../include/mail_flush.h sendmail.o: ../../include/mail_stream.h +sendmail.o: ../../include/smtp_stream.h diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 72eddfd3b..34d6860b8 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -120,7 +120,7 @@ smtpd.o: ../../include/off_cvt.h smtpd.o: ../../include/debug_peer.h smtpd.o: ../../include/mail_error.h smtpd.o: ../../include/name_mask.h -smtpd.o: ../../include/mail_flush.h +smtpd.o: ../../include/flush_clnt.h smtpd.o: ../../include/mail_stream.h smtpd.o: ../../include/mail_queue.h smtpd.o: ../../include/tok822.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 58b6b7e1d..3f2dec418 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -151,18 +151,6 @@ /* Limit the number of times a client can issue a junk command /* such as NOOP, VRFY, ETRN or RSET in one SMTP session before /* it is penalized with tarpit delays. -/* .SH "ETRN controls" -/* .ad -/* .fi -/* .IP \fBsmtpd_etrn_restrictions\fR -/* Restrict what domain names can be used in \fBETRN\fR commands, -/* and what clients may issue \fBETRN\fR commands. -/* .IP \fBfast_flush_domains\fR -/* The destinations that this system is willing to provide "fast ETRN" -/* service for. By default, "fast ETRN" service is available only -/* for destinations that the local system is willing to relay mail to. -/* For other destinations, Postfix simply attempts to deliver all mail -/* in the queue. /* .SH "UCE control restrictions" /* .ad /* .fi @@ -178,6 +166,9 @@ /* Restrict what sender addresses are allowed in \fBMAIL FROM\fR commands. /* .IP \fBsmtpd_recipient_restrictions\fR /* Restrict what recipient addresses are allowed in \fBRCPT TO\fR commands. +/* .IP \fBsmtpd_etrn_restrictions\fR +/* Restrict what domain names can be used in \fBETRN\fR commands, +/* and what clients may issue \fBETRN\fR commands. /* .IP \fBallow_untrusted_routing\fR /* Allow untrusted clients to specify addresses with sender-specified /* routing. Enabling this opens up nasty relay loopholes involving @@ -279,7 +270,7 @@ #include #include #include -#include +#include #include #include #include @@ -307,6 +298,7 @@ */ int var_smtpd_rcpt_limit; int var_smtpd_tmout; +char *var_relay_domains; int var_smtpd_soft_erlim; int var_smtpd_hard_erlim; int var_queue_minfree; /* XXX use off_t */ @@ -349,7 +341,6 @@ bool var_smtpd_sasl_enable; char *var_smtpd_sasl_opts; char *var_smtpd_sasl_realm; char *var_filter_xport; -char *var_fast_flush_domains; /* * Global state, for stand-alone mode queue file cleanup. When this is @@ -1083,10 +1074,6 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "501 Error: invalid parameter syntax"); return (-1); } - if (SMTPD_STAND_ALONE(state)) { - smtpd_chat_reply(state, "458 Unable to queue messages"); - return (-1); - } /* * XXX The implementation borrows heavily from the code that implements @@ -1094,43 +1081,22 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) * rejected. RFC 1985 requires that 459 be sent when the server refuses * to perform the request. */ + if (SMTPD_STAND_ALONE(state)) { + smtpd_chat_reply(state, "458 Unable to queue messages"); + return (-1); + } if ((err = smtpd_check_etrn(state, argv[1].strval)) != 0) { smtpd_chat_reply(state, "%s", err); return (-1); } - if (!*var_fast_flush_domains) { - mail_flush_deferred(); - smtpd_chat_reply(state, "250 Queuing started"); - return (0); - } - - /* - * Create a fast ETRN cache file on the fly for an eligible site. - */ - switch (mail_flush_site(argv[1].strval)) { - case FLUSH_STAT_UNKNOWN: - if (smtpd_check_etrn_cache_policy_ok(state, argv[1].strval)) { - if (mail_flush_enable(argv[1].strval) != FLUSH_STAT_OK) { - msg_warn("can't create fast ETRN cache for %s", argv[1].strval); - } else { - msg_info("created fast ETRN cache for %s (client=%s)", - argv[1].strval, state->namaddr); - } - } else { - msg_info("using slow ETRN service for %s (client=%s)", - argv[1].strval, state->namaddr); - } - /* Fallthrough. */ - case FLUSH_STAT_FAIL: - mail_flush_deferred(); - /* Fallthrough. */ + switch (flush_send(argv[1].strval)) { case FLUSH_STAT_OK: smtpd_chat_reply(state, "250 Queuing started"); return (0); + case FLUSH_STAT_BAD: + msg_warn("bad ETRN %.100s... from %s", argv[1].strval, state->namaddr); default: smtpd_chat_reply(state, "458 Unable to queue messages"); - msg_warn("bad ETRN destination %.100s... from %s", - argv[1].strval, state->namaddr); return (-1); } } @@ -1460,6 +1426,7 @@ int main(int argc, char **argv) 0, }; static CONFIG_STR_TABLE str_table[] = { + VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0, VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0, VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0, VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0, diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 0183280a1..09dfad479 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -27,10 +27,6 @@ /* char *smtpd_check_etrn(state, destination) /* SMTPD_STATE *state; /* char *destination; -/* -/* int smtpd_check_etrn_cache_policy_ok(state, destination) -/* SMTPD_STATE *state; -/* char *destination; /* DESCRIPTION /* This module implements additional checks on SMTP client requests. /* A client request is validated in the context of the session state. @@ -183,11 +179,6 @@ /* Restrictions on the hostname that is sent with the HELO/EHLO /* command. /* .PP -/* smtpd_check_etrn_cache_policy_ok() returns "true" if it is OK to -/* create a fast ETRN cache file for the specified destination. -/* The default policy ($smtpd_fast_flush_domains) is that the local MTA -/* must be willing to relay mail to that destination. -/* /* smtpd_check_size() checks if a message with the given size can /* be received (zero means that the message size is unknown). The /* message is rejected when: @@ -328,7 +319,6 @@ static MAPS *relocated_maps; */ static DOMAIN_LIST *relay_domains; static NAMADR_LIST *mynetworks; -static DOMAIN_LIST *fast_flush_domains; /* * Pre-parsed restriction lists. @@ -454,7 +444,6 @@ void smtpd_check_init(void) */ mynetworks = namadr_list_init(var_mynetworks); relay_domains = domain_list_init(var_relay_domains); - fast_flush_domains = domain_list_init(var_fast_flush_domains); /* * Pre-parse and pre-open the recipient maps. @@ -916,7 +905,7 @@ static int has_my_addr(char *host) msg_info("%s: host %s", myname, host); /* - * If we can't lookup the host, say we're not listed. + * If we can't lookup the host, play safe and assume it is OK. */ #define YUP 1 #define NOPE 0 @@ -924,12 +913,12 @@ static int has_my_addr(char *host) if ((hp = gethostbyname(host)) == 0) { if (msg_verbose) msg_info("%s: host %s: not found", myname, host); - return (NOPE); + return (YUP); } if (hp->h_addrtype != AF_INET || hp->h_length != sizeof(addr)) { msg_warn("address type %d length %d for %s", hp->h_addrtype, hp->h_length, host); - return (NOPE); + return (YUP); } for (cpp = hp->h_addr_list; *cpp; cpp++) { memcpy((char *) &addr, *cpp, sizeof(addr)); @@ -1928,41 +1917,6 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain) SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); } -/* smtpd_check_etrn_cache_policy_ok - is it OK to create a fast ETRN cache? */ - -int smtpd_check_etrn_cache_policy_ok(SMTPD_STATE *unused_state, char *domain) -{ - - /* - * Fast ETRN cache files are created on demand. Anything else would make - * the feature unusable. However, it should not be possible that some - * network vandal abuses this feature to create lots of bogus fast ETRN - * cache files. - * - * By default, Postfix accepts ETRN commands from everywhere, but will - * create fast ETRN cache files only for destinations that Postfix is - * willing to relay mail to. - */ - - /* - * The domain name must exist. - */ - if (dns_lookup_types(domain, 0, (DNS_RR **) 0, (VSTRING *) 0, - (VSTRING *) 0, T_A, T_MX, 0) != DNS_OK) - return (0); - - /* - * The domain name must be an authorized relay destination. - */ - if (domain_list_match(fast_flush_domains, domain) == 0) - return (0); - - /* - * Must be OK then. - */ - return (1); -} - /* smtpd_check_rcptmap - permit if recipient address matches lookup table */ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient) diff --git a/postfix/src/smtpd/smtpd_check.h b/postfix/src/smtpd/smtpd_check.h index e28c4421d..00f923a8f 100644 --- a/postfix/src/smtpd/smtpd_check.h +++ b/postfix/src/smtpd/smtpd_check.h @@ -20,7 +20,6 @@ extern char *smtpd_check_rcptmap(SMTPD_STATE *, char *); extern char *smtpd_check_size(SMTPD_STATE *, off_t); extern char *smtpd_check_rcpt(SMTPD_STATE *, char *); extern char *smtpd_check_etrn(SMTPD_STATE *, char *); -extern int smtpd_check_etrn_cache_policy_ok(SMTPD_STATE *, char *); /* LICENSE /* .ad