From: Wietse Venema Date: Wed, 27 Sep 2000 05:00:00 +0000 (-0500) Subject: snapshot-20000927 X-Git-Tag: v20010228~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6609114c5095519fdf3d941326917ed51641ac05;p=thirdparty%2Fpostfix.git snapshot-20000927 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index c8c9a9596..4e9246e8d 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -4292,3 +4292,15 @@ Apologies for any names omitted. Cleanup: deleted the per-recipient bounce protocol. Future bounce logfiles will support per-recipient bounce addresses. Files: global/bounce.c, bounce/bounce_recip_service. + +20000925 + + Workaround: sendmail allows MAIL FROM and RCPT TO envelope + addresses like > so we will never get + rid of them. To disallow, specify "strict_rfc821_envelopes + = yes". File: smtpd/smtpd.c. + +20000926-8 + + First implementation of a logfile-based fast flush server, + which is the basis for ETRN and "sendmail -qRsite". diff --git a/postfix/Makefile.in b/postfix/Makefile.in index fcc8c66e6..6cf1ec72b 100644 --- a/postfix/Makefile.in +++ b/postfix/Makefile.in @@ -6,7 +6,7 @@ DIRS = src/util src/global src/dns src/master src/postfix src/smtpstone \ src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \ src/showq src/postalias src/postcat src/postconf src/postdrop \ src/postkick src/postlock src/postlog src/postmap src/postsuper \ - src/nqmgr src/spawn # src/base64 proto man html + src/nqmgr src/spawn src/flushd # src/base64 proto man html default: update diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf index 473cfa386..b3b1fa7f7 100644 --- a/postfix/conf/master.cf +++ b/postfix/conf/master.cf @@ -75,6 +75,7 @@ bounce unix - - n - 0 bounce defer unix - - n - 0 bounce smtp unix - - n - - smtp showq unix n - n - - showq +flush unix n - n - - flushd error unix - - n - - error local unix - n n - - local lmtp unix - - n - - lmtp diff --git a/postfix/conf/postfix-script-nosgid b/postfix/conf/postfix-script-nosgid index 5dd1ef238..425fe6acd 100755 --- a/postfix/conf/postfix-script-nosgid +++ b/postfix/conf/postfix-script-nosgid @@ -187,7 +187,7 @@ check) chmod 755 pid chown $mail_owner pid } - for dir in incoming active bounce defer deferred saved corrupt; do + for dir in incoming active bounce defer deferred flush saved corrupt; do test -d $dir || { $WARN creating missing Postfix $dir directory mkdir $dir || exit 1 diff --git a/postfix/conf/postfix-script-sgid b/postfix/conf/postfix-script-sgid index 780b475b0..1c6231f13 100755 --- a/postfix/conf/postfix-script-sgid +++ b/postfix/conf/postfix-script-sgid @@ -188,7 +188,7 @@ check) chmod 755 pid chown $mail_owner pid } - for dir in incoming active bounce defer deferred saved corrupt; do + for dir in incoming active bounce defer deferred flush saved corrupt; do test -d $dir || { $WARN creating missing Postfix $dir directory mkdir $dir || exit 1 diff --git a/postfix/html/Makefile.in b/postfix/html/Makefile.in index 4431a1bf9..35f235000 100644 --- a/postfix/html/Makefile.in +++ b/postfix/html/Makefile.in @@ -5,7 +5,7 @@ SHELL = /bin/sh DAEMONS = bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \ lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \ showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \ - nqmgr.8.html spawn.8.html + nqmgr.8.html spawn.8.html flushd.8.html COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \ postconf.1.html postfix.1.html postkick.1.html postlock.1.html \ postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \ @@ -36,6 +36,9 @@ defer.8.html: bounce.8.html error.8.html: ../src/error/error.c srctoman $? | nroff -man | man2html | postlink >$@ +flushd.8.html: ../src/flushd/flushd.c + srctoman $? | nroff -man | man2html | postlink >$@ + cleanup.8.html: ../src/cleanup/cleanup.c srctoman $? | nroff -man | man2html | postlink >$@ diff --git a/postfix/html/flushd.8.html b/postfix/html/flushd.8.html new file mode 100644 index 000000000..dc67ace3c --- /dev/null +++ b/postfix/html/flushd.8.html @@ -0,0 +1,134 @@ +
+
+
+
+FLUSHD(8)                                               FLUSHD(8)
+
+
+NAME
+       flushd - Postfix fast flush daemon
+
+SYNOPSIS
+       flushd [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.
+
+       This server implements the following requests:
+
+       FLUSH_REQ_ADD sitename queue_id
+              Append a record to the per-site fast flush  logfile
+              for the specified queue ID.
+
+       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.
+
+       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_UNKNOWN
+              The specified site has no fast flush logfile and is
+              not configured to have one.
+
+SECURITY
+       The fast flush server is moderately security-sensitive. It
+       does  not  talk  to the network, but it does talk to local
+       unprivileged users, in order to emulate "sendmail -qRsite"
+       behavior.   For  this  reason all strings in a request are
+       truncated at ine_length_limit.
+
+       The fast flush server can run chrooted at fixed low privi-
+       lege.
+
+DIAGNOSTICS
+       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
+
+
+
+                                                                1
+
+
+
+
+
+FLUSHD(8)                                               FLUSHD(8)
+
+
+       multiple destinations.
+
+CONFIGURATION PARAMETERS
+       The following main.cf parameters are  especially  relevant
+       to  this  program. See the Postfix main.cf file for syntax
+       details and for default values.  Use  the  postfix  reload
+       command after a configuration change.
+
+       fast_flush_maps
+              The  table with names of destinations that this MTA
+              provides the  fast  flush  service  for,  and  with
+              clients  that  may issue the ETRN command for those
+              destinations. Postfix maintains fast flush logfiles
+              only for destinations listed in this table.
+
+       line_length_limit
+              Maximal  length  of  strings in a fast flush client
+              request.
+
+SEE ALSO
+       smtp(8) Postfix SMTP client
+       smtpd) Postfix SMTP server
+       qmgr(8) Postfix queue manager
+       syslogd(8) system logging
+
+LICENSE
+       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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                2
+
+
+
diff --git a/postfix/html/sendmail.1.html b/postfix/html/sendmail.1.html index 8c037cbe0..5da935a3f 100644 --- a/postfix/html/sendmail.1.html +++ b/postfix/html/sendmail.1.html @@ -185,12 +185,12 @@ SENDMAIL(1) SENDMAIL(1) The interval between queue runs. Use the queue_run_delay configuration parameter instead. - -t Extract recipients from message headers. This - requires that no recipients be specified on the - command line. - - -v Enable verbose logging for debugging purposes. Mul- - tiple -v options make the software increasingly + -qRsite + Schedule immediate delivery of all mail that is + queued for the named site. This functionality is + available only for sites that are configured for + the fast flush service support as described in + flushd(8). For other sites, this command is @@ -203,16 +203,28 @@ SENDMAIL(1) SENDMAIL(1) SENDMAIL(1) SENDMAIL(1) + equivalent to using the slower sendmail -q instead. + + -qSsite + The site name is ignored. This command is equiva- + lent to using the slower sendmail -q instead. + + -t Extract recipients from message headers. This + requires that no recipients be specified on the + command line. + + -v Enable verbose logging for debugging purposes. Mul- + tiple -v options make the software increasingly verbose. SECURITY - By design, this program is not set-user (or group) id. - However, it must handle data from untrusted users or - untrusted machines. Thus, the usual precautions need to + By design, this program is not set-user (or group) id. + However, it must handle data from untrusted users or + untrusted machines. Thus, the usual precautions need to be taken against malicious inputs. DIAGNOSTICS - Problems are logged to syslogd(8) and to the standard + Problems are logged to syslogd(8) and to the standard error stream. ENVIRONMENT @@ -224,7 +236,7 @@ SENDMAIL(1) SENDMAIL(1) MAIL_DEBUG Enable debugging with an external command, as spec- - ified with the debugger_command configuration + ified with the debugger_command configuration parameter. FILES @@ -232,31 +244,19 @@ SENDMAIL(1) SENDMAIL(1) /etc/postfix, configuration files CONFIGURATION PARAMETERS - See the Postfix main.cf file for syntax details and for - default values. Use the postfix reload command after a + See the Postfix main.cf file for syntax details and for + default values. Use the postfix reload command after a configuration change. alias_database - Default alias database(s) for newaliases. The - default value for this parameter is system-spe- + Default alias database(s) for newaliases. The + default value for this parameter is system-spe- cific. bounce_size_limit The amount of original message context that is sent along with a non-delivery notification. - database_type - Default alias etc. database type. On many UNIX sys- - tems the default type is either dbm or hash. - - debugger_command - Command that is executed after a Postfix daemon has - initialized. - - debug_peer_level - Increment in verbose logging level when a remote - host matches a pattern in the debug_peer_list - parameter. @@ -269,60 +269,60 @@ SENDMAIL(1) SENDMAIL(1) SENDMAIL(1) SENDMAIL(1) + database_type + Default alias etc. database type. On many UNIX sys- + tems the default type is either dbm or hash. + + debugger_command + Command that is executed after a Postfix daemon has + initialized. + + debug_peer_level + Increment in verbose logging level when a remote + host matches a pattern in the debug_peer_list + parameter. + debug_peer_list - List of domain or network patterns. When a remote - host matches a pattern, increase the verbose log- - ging level by the amount specified in the + List of domain or network patterns. When a remote + host matches a pattern, increase the verbose log- + ging level by the amount specified in the debug_peer_level parameter. fork_attempts - Number of attempts to fork() a process before giv- + Number of attempts to fork() a process before giv- ing up. fork_delay - Delay in seconds between successive fork() + Delay in seconds between successive fork() attempts. hopcount_limit Limit the number of Received: message headers. mail_owner - The owner of the mail queue and of most Postfix + The owner of the mail queue and of most Postfix processes. command_directory - Directory with Postfix support commands (default: + Directory with Postfix support commands (default: $program_directory). daemon_directory - Directory with Postfix daemon programs (default: + Directory with Postfix daemon programs (default: $program_directory). queue_directory - Top-level directory of the Postfix queue. This is + Top-level directory of the Postfix queue. This is also the root directory of Postfix daemons that run chrooted. queue_run_delay - The time between successive scans of the deferred + The time between successive scans of the deferred queue. SEE ALSO pickup(8) mail pickup daemon postalias(1) maintain alias database - postdrop(1) privileged posting agent - postfix(1) mail system control - postkick(1) kick a Postfix daemon - qmgr(8) queue manager - showq(8) list mail queue - smtpd(8) SMTP server - syslogd(8) system logging - -LICENSE - The Secure Mailer license must be distributed with this - software. - - @@ -335,6 +335,19 @@ SENDMAIL(1) SENDMAIL(1) SENDMAIL(1) SENDMAIL(1) + postdrop(1) privileged posting agent + postfix(1) mail system control + postkick(1) kick a Postfix daemon + qmgr(8) queue manager + showq(8) list mail queue + smtpd(8) SMTP server + flushd(8) fast flush service + syslogd(8) system logging + +LICENSE + The Secure Mailer license must be distributed with this + software. + AUTHOR(S) Wietse Venema IBM T.J. Watson Research @@ -365,19 +378,6 @@ SENDMAIL(1) SENDMAIL(1) - - - - - - - - - - - - - diff --git a/postfix/man/Makefile.in b/postfix/man/Makefile.in index b66cb3de3..f82ef9269 100644 --- a/postfix/man/Makefile.in +++ b/postfix/man/Makefile.in @@ -5,7 +5,7 @@ SHELL = /bin/sh DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \ man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \ man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \ - man8/nqmgr.8 man8/spawn.8 + man8/nqmgr.8 man8/spawn.8 man8/flushd.8 COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \ man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \ man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \ @@ -38,6 +38,9 @@ man8/cleanup.8: ../src/cleanup/cleanup.c man8/error.8: ../src/error/error.c ../mantools/srctoman $? >$@ +man8/flushd.8: ../src/flushd/flushd.c + ../mantools/srctoman $? >$@ + man8/local.8: ../src/local/local.c ../mantools/srctoman $? >$@ diff --git a/postfix/man/man1/sendmail.1 b/postfix/man/man1/sendmail.1 index fc7821722..641e544aa 100644 --- a/postfix/man/man1/sendmail.1 +++ b/postfix/man/man1/sendmail.1 @@ -135,6 +135,16 @@ Flush the mail queue. This is implemented by kicking the .IP "\fB-q\fIinterval\fR (ignored)" The interval between queue runs. Use the \fBqueue_run_delay\fR configuration parameter instead. +.IP \fB-qR\fIsite\fR +Schedule immediate delivery of all mail that is queued for the named +\fIsite\fR. +This functionality is available only for sites that are configured +for the \fBfast flush\fR service support as described in +\fBflushd\fR(8). For other sites, this command is equivalent to +using the slower \fBsendmail -q\fR instead. +.IP \fB-qS\fIsite\fR +The site name is ignored. This command is equivalent to using +the slower \fBsendmail -q\fR instead. .IP \fB-t\fR Extract recipients from message headers. This requires that no recipients be specified on the command line. @@ -228,6 +238,7 @@ postkick(1) kick a Postfix daemon qmgr(8) queue manager showq(8) list mail queue smtpd(8) SMTP server +flushd(8) fast flush service syslogd(8) system logging .SH LICENSE .na diff --git a/postfix/man/man8/flushd.8 b/postfix/man/man8/flushd.8 new file mode 100644 index 000000000..74a5c23d8 --- /dev/null +++ b/postfix/man/man8/flushd.8 @@ -0,0 +1,94 @@ +.TH FLUSHD 8 +.ad +.fi +.SH NAME +flushd +\- +Postfix fast flush daemon +.SH SYNOPSIS +.na +.nf +\fBflushd\fR [generic Postfix daemon options] +.SH DESCRIPTION +.ad +.fi +The flush server maintains so-called "fast flush" logfiles with +information about what messages are queued for a specific site. +This program expects to be run from the \fBmaster\fR(8) process +manager. + +This server implements the following requests: +.IP "FLUSH_REQ_ADD sitename queue_id" +Append a record to the per-site fast flush logfile for the specified +queue ID. +.IP "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. +.PP +The response to the client is one of: +.IP FLUSH_STAT_OK +The request completed normally. +.IP FLUSH_STAT_BAD +The flush server rejected the request (bad request name, bad +request parameter value). +.IP FLUSH_STAT_UNKNOWN +The specified site has no fast flush logfile and is not configured +to have one. +.SH SECURITY +.na +.nf +.ad +.fi +The fast flush server is moderately security-sensitive. It does not +talk to the network, but it does talk to local unprivileged users, in +order to emulate "sendmail -qRsite" behavior. For this reason all +strings in a request are truncated at \fline_length_limit\fR. + +The fast flush server can run chrooted at fixed low privilege. +.SH DIAGNOSTICS +.ad +.fi +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 +one queue runner has to handle mail for multiple destinations. +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +The following \fBmain.cf\fR parameters are especially relevant to +this program. 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_maps\fR +The table with names of destinations that this MTA provides the +fast flush service for, and with clients that may issue the ETRN +command for those destinations. Postfix maintains fast flush logfiles +only for destinations listed in this table. +.IP \fBline_length_limit\fR +Maximal length of strings in a fast flush client request. +.SH SEE ALSO +.na +.nf +smtp(8) Postfix SMTP client +smtpd) Postfix SMTP server +qmgr(8) Postfix queue manager +syslogd(8) system logging +.SH LICENSE +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH AUTHOR(S) +.na +.nf +Wietse Venema +IBM T.J. Watson Research +P.O. Box 704 +Yorktown Heights, NY 10598, USA diff --git a/postfix/src/flushd/.indent.pro b/postfix/src/flushd/.indent.pro new file mode 120000 index 000000000..5c837eca6 --- /dev/null +++ b/postfix/src/flushd/.indent.pro @@ -0,0 +1 @@ +../../.indent.pro \ No newline at end of file diff --git a/postfix/src/flushd/Makefile.in b/postfix/src/flushd/Makefile.in new file mode 100644 index 000000000..7345e631c --- /dev/null +++ b/postfix/src/flushd/Makefile.in @@ -0,0 +1,76 @@ +SHELL = /bin/sh +SRCS = flushd.c +OBJS = flushd.o +HDRS = +TESTSRC = +WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) +CFLAGS = $(DEBUG) $(OPT) $(DEFS) +TESTPROG= +PROG = flushd +INC_DIR = ../../include +LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a + +.c.o:; $(CC) $(CFLAGS) -c $*.c + +$(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + +Makefile: Makefile.in + (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs; cat $?) >$@ + +test: $(TESTPROG) + +update: ../../libexec/$(PROG) + +../../libexec/$(PROG): $(PROG) + cp $(PROG) ../../libexec + +printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + +lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + +clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -rf printfck + +tidy: clean + +depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ + done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @$(EXPORT) make -f Makefile.in Makefile 1>&2 + +# do not edit below this line - it is generated by 'make depend' +flushd.o: flushd.c +flushd.o: ../../include/sys_defs.h +flushd.o: ../../include/msg.h +flushd.o: ../../include/events.h +flushd.o: ../../include/vstream.h +flushd.o: ../../include/vbuf.h +flushd.o: ../../include/vstring.h +flushd.o: ../../include/vstring_vstream.h +flushd.o: ../../include/myflock.h +flushd.o: ../../include/valid_hostname.h +flushd.o: ../../include/htable.h +flushd.o: ../../include/dict.h +flushd.o: ../../include/argv.h +flushd.o: ../../include/mail_params.h +flushd.o: ../../include/mail_queue.h +flushd.o: ../../include/mail_proto.h +flushd.o: ../../include/iostuff.h +flushd.o: ../../include/mail_flush.h +flushd.o: ../../include/mail_conf.h +flushd.o: ../../include/maps.h +flushd.o: ../../include/mail_server.h diff --git a/postfix/src/flushd/flushd.c b/postfix/src/flushd/flushd.c new file mode 100644 index 000000000..189e28723 --- /dev/null +++ b/postfix/src/flushd/flushd.c @@ -0,0 +1,375 @@ +/*++ +/* NAME +/* flushd 8 +/* SUMMARY +/* Postfix fast flush daemon +/* SYNOPSIS +/* \fBflushd\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. +/* This program expects to be run from the \fBmaster\fR(8) process +/* manager. +/* +/* This server implements the following requests: +/* .IP "FLUSH_REQ_ADD sitename queue_id" +/* Append a record to the per-site fast flush logfile for the specified +/* queue ID. +/* .IP "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. +/* .PP +/* The response to the client is one of: +/* .IP FLUSH_STAT_OK +/* The request completed normally. +/* .IP FLUSH_STAT_BAD +/* The flush server rejected the request (bad request name, bad +/* request parameter value). +/* .IP FLUSH_STAT_UNKNOWN +/* The specified site has no fast flush logfile and is not configured +/* to have one. +/* SECURITY +/* .ad +/* .fi +/* The fast flush server is moderately security-sensitive. It does not +/* talk to the network, but it does talk to local unprivileged users, in +/* order to emulate "sendmail -qRsite" behavior. For this reason all +/* strings in a request are truncated at \fline_length_limit\fR. +/* +/* The fast flush server can run chrooted at fixed low privilege. +/* 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 +/* one queue runner has to handle mail for multiple destinations. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* The following \fBmain.cf\fR parameters are especially relevant to +/* this program. 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_maps\fR +/* The table with names of destinations that this MTA provides the +/* fast flush service for, and with clients that may issue the ETRN +/* command for those destinations. Postfix maintains fast flush logfiles +/* only for destinations listed in this table. +/* .IP \fBline_length_limit\fR +/* Maximal length of strings in a fast flush client request. +/* SEE ALSO +/* smtp(8) Postfix SMTP client +/* smtpd) Postfix SMTP server +/* qmgr(8) Postfix queue manager +/* syslogd(8) system logging +/* 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 +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include +#include +#include + +/* Single server skeleton. */ + +#include + + /* + * Tunable parameters. + */ +char *var_fflush_maps; + +/* Application-specific. */ + +#define STR(x) vstring_str(x) +#define MAX_DUP_FILTER 10000 + +static MAPS *fflush_maps; + +/* flush_append - append queue ID to per-site fast flush logfile */ + +static int flush_append(const char *site, const char *queue_id) +{ + char *myname = "flush_append"; + VSTREAM *log; + + if (msg_verbose) + msg_info("%s: site %s queue_id %s", myname, site, queue_id); + + /* + * Open or create the logfile. We allow for the fact that a logfile + * exists for a site that is no longer listed in the fast flush maps. + */ + if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, site, O_WRONLY, 0600)) == 0) { + if (errno != ENOENT) + msg_fatal("%s: open fast flush log for site %s: %m", myname, site); + if (maps_find(fflush_maps, site, 0) == 0) { + msg_warn("no fast flush support configured for site %s", site); + return (FLUSH_STAT_UNKNOWN); + } + log = mail_queue_open(MAIL_QUEUE_FLUSH, site, O_CREAT | O_WRONLY, 0600); + if (log == 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 + * concurrent access. If the lock takes too long, the Postfix watchdog + * will eventually take care of the problem, but it will take a while. + */ + if (myflock(vstream_fileno(log), MYFLOCK_EXCLUSIVE) < 0) + msg_fatal("%s: lock fast flush log for site %s: %m", myname, site); + + /* + * Append the queue ID. With 15 bits if microsecond time, a queue ID is + * not recycled often enough for false hits to be a problem. If it does, + * then we could add other signature information, such as the file size + * in bytes. + */ + vstream_fprintf(log, "%s\n", queue_id); + + /* + * Clean up. + */ + if (myflock(vstream_fileno(log), MYFLOCK_NONE) < 0) + msg_fatal("%s: unlock fast flush logfile for site %s: %m", + myname, site); + if (vstream_fclose(log) != 0) + msg_warn("write fast flush logfile for site %s: %m", site); + + return (FLUSH_STAT_OK); +} + +/* flush_site - flush mail queued for site */ + +static int flush_site(const char *site) +{ + char *myname = "flush_site"; + VSTRING *queue_id; + VSTRING *queue_file; + VSTREAM *log; + struct utimbuf tbuf; + static char qmgr_trigger[] = { + QMGR_REQ_SCAN_DEFERRED, /* scan deferred queue */ + QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ + }; + HTABLE *dup_filter; + + if (msg_verbose) + msg_info("%s: site %s", myname, site); + + /* + * Open the logfile. + */ + 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); + if (maps_find(fflush_maps, site, 0)) { + msg_warn("no fast flush log for site %s", site); + return (FLUSH_STAT_OK); + } else { + msg_warn("no fast flush support configured for site %s", site); + return (FLUSH_STAT_UNKNOWN); + } + } + + /* + * We must lock the logfile, so that we don't lose information when it is + * truncated. Unfortunately, this means that the file can be locked for a + * significant amount of time. If things really get stuck the Postfix + * watchdog will take care of it. + */ + if (myflock(vstream_fileno(log), MYFLOCK_EXCLUSIVE) < 0) + msg_fatal("%s: lock fast flush log for site %s: %m", myname, 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 do not use fast + * flush routinely). 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); + dup_filter = htable_create(10); + tbuf.actime = tbuf.modtime = event_time(); + while (vstring_get_nonl(queue_id, log) != VSTREAM_EOF) { + if (dup_filter->used >= MAX_DUP_FILTER + || htable_find(dup_filter, STR(queue_id)) == 0) { + if (msg_verbose) + msg_info("%s: site %s: update %s time stamps", + myname, site, STR(queue_file)); + if (dup_filter->used <= MAX_DUP_FILTER) + htable_enter(dup_filter, STR(queue_id), 0); + + mail_queue_path(queue_file, MAIL_QUEUE_DEFERRED, STR(queue_id)); + if (utime(STR(queue_file), &tbuf) == 0) + continue; + if (errno != ENOENT) + msg_fatal("%s: update %s time stamps: %m", + myname, STR(queue_file)); + + mail_queue_path(queue_file, MAIL_QUEUE_INCOMING, STR(queue_id)); + if (utime(STR(queue_file), &tbuf) == 0) + continue; + if (errno != ENOENT) + msg_fatal("%s: update %s time stamps: %m", + myname, STR(queue_file)); + } else { + if (msg_verbose) + msg_info("%s: site %s: skip file %s as duplicate", + myname, site, STR(queue_file)); + } + } + htable_free(dup_filter, (void (*) (char *)) 0); + vstring_free(queue_file); + vstring_free(queue_id); + + /* + * Truncate the fast flush logfile. + */ + if (ftruncate(vstream_fileno(log), (off_t) 0) < 0) + msg_fatal("%s: truncate fast flush logfile for site %s: %m", + myname, site); + + /* + * Request delivery and clean up. + */ + if (myflock(vstream_fileno(log), MYFLOCK_NONE) < 0) + msg_fatal("%s: unlock fast flush logfile for site %s: %m", + myname, site); + if (vstream_fclose(log) != 0) + msg_warn("read fast flush logfile for site %s: %m", site); + if (msg_verbose) + msg_info("%s: requesting delivery for site %s", myname, site); + mail_trigger(MAIL_CLASS_PUBLIC, MAIL_SERVICE_QUEUE, + qmgr_trigger, sizeof(qmgr_trigger)); + + return (FLUSH_STAT_OK); +} + +/* flush_service - perform service for client */ + +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; + int status = FLUSH_STAT_BAD; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * Vandalism control. Read no unlimited amounts of garbage from a public + * socket. + */ + vstring_ctl(request, VSTRING_CTL_MAXLEN, var_line_limit, VSTRING_CTL_END); + vstring_ctl(site, VSTRING_CTL_MAXLEN, var_line_limit, VSTRING_CTL_END); + + /* + * This routine runs whenever a client connects to the UNIX-domain socket + * dedicated to the fast flush service. What we see below is a little + * protocol to (1) read a request from the client (the name of the site) + * and (2) acknowledge that we have received the request. Since the site + * name maps onto the file system, make sure the site name is a valid + * SMTP hostname. + * + * All connection-management stuff is handled by the common code in + * single_server.c. + */ +#define STREQ(x,y) (strcmp((x), (y)) == 0) + + if (mail_scan(client_stream, "%s %s", request, site) == 2 + && valid_hostname(STR(site))) { + if (STREQ(STR(request), FLUSH_REQ_ADD)) { + queue_id = vstring_alloc(10); + vstring_ctl(queue_id, VSTRING_CTL_MAXLEN, var_line_limit, + VSTRING_CTL_END); + if (mail_scan(client_stream, "%s", queue_id) == 1) + status = flush_append(STR(site), STR(queue_id)); + vstring_free(queue_id); + } else if (STREQ(STR(request), FLUSH_REQ_SEND)) { + status = flush_site(STR(site)); + } + } + mail_print(client_stream, "%d", status); + vstring_free(site); + vstring_free(request); +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(char *unused_name, char **unused_argv) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + +/* pre_jail_init - pre-chroot initialization */ + +static void pre_jail_init(char *unused_service, char **unused_argv) +{ + fflush_maps = maps_create(VAR_FFLUSH_MAPS, var_fflush_maps, + DICT_FLAG_LOCK); +} + +/* pre_accept_init - check map status */ + + +/* main - pass control to the single-threaded skeleton */ + +int main(int argc, char **argv) +{ + static CONFIG_STR_TABLE str_table[] = { + VAR_FFLUSH_MAPS, DEF_FFLUSH_MAPS, &var_fflush_maps, 0, 0, + 0, + }; + + single_server_main(argc, argv, flush_service, + MAIL_SERVER_PRE_INIT, pre_jail_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, + MAIL_SERVER_STR_TABLE, str_table, + 0); +} diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 3168c858e..b09b2ec4a 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -55,7 +55,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ TESTSRC = rec2stream.c stream2rec.c recdump.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused + -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) INCL = @@ -221,7 +221,7 @@ lint: lint $(DEFS) $(SRCS) $(LINTFIX) clean: - rm -f *.o $(LIB) *core $(TESTPROG) junk + rm -f *.o $(LIB) *core $(TESTPROG) junk rm -rf printfck tidy: clean @@ -257,11 +257,13 @@ bounce.o: defer.h bounce.o: bounce.h bounce_log.o: bounce_log.c bounce_log.o: ../../include/sys_defs.h +bounce_log.o: ../../include/msg.h bounce_log.o: ../../include/mymalloc.h bounce_log.o: ../../include/vstream.h bounce_log.o: ../../include/vbuf.h bounce_log.o: ../../include/vstring.h bounce_log.o: ../../include/vstring_vstream.h +bounce_log.o: ../../include/stringops.h bounce_log.o: mail_queue.h bounce_log.o: bounce_log.h canon_addr.o: canon_addr.c @@ -537,11 +539,13 @@ 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: mail_proto.h +mail_flush.o: ../../include/msg.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 @@ -591,6 +595,7 @@ mail_queue.o: ../../include/dir_forest.h mail_queue.o: ../../include/make_dirs.h mail_queue.o: ../../include/split_at.h mail_queue.o: ../../include/sane_fsops.h +mail_queue.o: ../../include/valid_hostname.h mail_queue.o: file_id.h mail_queue.o: mail_params.h mail_queue.o: mail_queue.h @@ -613,6 +618,7 @@ 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/clnt_stream.c b/postfix/src/global/clnt_stream.c index 4513247c3..6fd200bc6 100644 --- a/postfix/src/global/clnt_stream.c +++ b/postfix/src/global/clnt_stream.c @@ -74,7 +74,7 @@ /* * CLNT_STREAM is an opaque structure. None of the access methods can easily - * be implemented as a macro, and access is not performance critica anyway. + * be implemented as a macro, and access is not performance critical anyway. */ struct CLNT_STREAM { VSTREAM *vstream; /* buffered I/O */ diff --git a/postfix/src/global/mail_flush.c b/postfix/src/global/mail_flush.c index 42a48a6ab..e7b8fc8ca 100644 --- a/postfix/src/global/mail_flush.c +++ b/postfix/src/global/mail_flush.c @@ -2,7 +2,7 @@ /* NAME /* mail_flush 3 /* SUMMARY -/* flush backed up mail +/* mail flush service client interface /* SYNOPSIS /* #include /* @@ -10,17 +10,34 @@ /* /* int mail_flush_site(site) /* const char *site; +/* +/* int mail_flush_append(site, queue_id) +/* const char *site; +/* const char *queue_id; /* DESCRIPTION -/* This module triggers delivery of backed up mail. +/* This module deals with delivery of backed up mail. /* /* mail_flush_deferred() triggers delivery of all deferred /* or incoming mail. /* -/* mail_flush_site() triggers delivery of all mail queued for -/* the named site. This routine may degenerate into a -/* mail_flush_deferred() call. +/* mail_flush_site() uses the "fash flush" service to trigger +/* delivery of messages queued for the specified site. +/* This service is available only for sites that are configured +/* to have a deferred mail logfile. +/* +/* mail_flush_append() appends a record to the "fash flush" +/* logfile of the specified site, with the queue ID of mail +/* that should still be delivered. /* DIAGNOSTICS -/* The result is 0 in case of success, -1 in case of failure. +/* 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 (mail_flush_site() only)" +/* The specified site is not configured for the fast flush service. +/* .IP "MAIL_FLUSH_BAD (mail_flush_site() only)" +/* The fast flush server rejected the request. /* LICENSE /* .ad /* .fi @@ -35,13 +52,19 @@ /* System library. */ #include "sys_defs.h" +#include +#include /* Utility library. */ +#include +#include + /* Global library. */ #include #include +#include /* mail_flush_deferred - flush deferred queue */ @@ -61,14 +84,74 @@ int mail_flush_deferred(void) qmgr_trigger, sizeof(qmgr_trigger))); } -/* mail_flush_site - flush deferred mail for site */ +/* mail_flush_clnt - generic fast flush service client */ -int mail_flush_site(const char *unused_site) +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_PUBLIC, 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; /* - * Until we have dedicated per-site queues, this call will degenerate - * into a mail_flush_deferred() call. + * Clean up. */ - return (mail_flush_deferred()); + vstream_fclose(flush); + + 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"; + int status; + + if (msg_verbose) + msg_info("%s: site %s id %s", myname, site, queue_id); + status = mail_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/mail_flush.h b/postfix/src/global/mail_flush.h index defd15c2a..dfce76229 100644 --- a/postfix/src/global/mail_flush.h +++ b/postfix/src/global/mail_flush.h @@ -11,13 +11,29 @@ /* DESCRIPTION /* .nf - /* External interface. */ - + /* + * External interface. + */ extern int mail_flush_deferred(void); extern int mail_flush_site(const char *); +extern int mail_flush_append(const char *, const char *); + + /* + * Mail flush server requests. + */ +#define FLUSH_REQ_ADD "add" /* add queue ID to site log */ +#define FLUSH_REQ_SEND "send" /* 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 /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) @@ -26,5 +42,6 @@ extern int mail_flush_site(const char *); /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ +/**INDENT** Error@33: Unmatched #endif */ #endif diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 6902977b5..a49f6746c 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1064,6 +1064,13 @@ extern void mail_params_init(void); #define DEF_FILTER_XPORT "" extern char *var_filter_xport; + /* + * Fast flush support. + */ +#define VAR_FFLUSH_MAPS "fast_flush_maps" +#define DEF_FFLUSH_MAPS "" +extern char *var_fflush_maps; + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 275680c51..78b76c864 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -40,6 +40,7 @@ #define MAIL_SERVICE_SMTPD "smtpd" #define MAIL_SERVICE_SHOWQ "showq" #define MAIL_SERVICE_ERROR "error" +#define MAIL_SERVICE_FLUSH "flush" /* * Well-known socket or FIFO directories. The main difference is in file diff --git a/postfix/src/global/mail_queue.c b/postfix/src/global/mail_queue.c index f5645ffac..73ede8534 100644 --- a/postfix/src/global/mail_queue.c +++ b/postfix/src/global/mail_queue.c @@ -126,6 +126,7 @@ #include #include #include +#include /* Global library. */ @@ -281,6 +282,15 @@ int mail_queue_id_ok(const char *queue_id) { const char *cp; + /* + * Must be in valid hostname form. + */ + if (valid_hostname(queue_id)) + return (1); + + /* + * Must be in time+inum form. + */ for (cp = queue_id; *cp; cp++) if (!ISALNUM(*cp)) return (0); diff --git a/postfix/src/global/mail_queue.h b/postfix/src/global/mail_queue.h index acba6a3d0..9486eb8ff 100644 --- a/postfix/src/global/mail_queue.h +++ b/postfix/src/global/mail_queue.h @@ -27,6 +27,7 @@ #define MAIL_QUEUE_DEFER "defer" #define MAIL_QUEUE_BOUNCE "bounce" #define MAIL_QUEUE_CORRUPT "corrupt" +#define MAIL_QUEUE_FLUSH "flush" /* * Queue file modes. diff --git a/postfix/src/global/mail_scan.c b/postfix/src/global/mail_scan.c index 0538c40bf..dfe96e237 100644 --- a/postfix/src/global/mail_scan.c +++ b/postfix/src/global/mail_scan.c @@ -33,6 +33,8 @@ /* White space in the format string is ignored. /* .IP %s /* The corresponding argument has type (VSTRING *). +/* If the string has a size limit, no more characters will be read +/* into the string than is specified via that size limit. /* .IP %d /* The corresponding argument has type (int *). /* .IP %ld @@ -98,6 +100,7 @@ /* Global library. */ #include "mail_proto.h" +#include "mail_params.h" /* * Provision for the user to register type-specific input conversion @@ -145,7 +148,8 @@ void mail_scan_register(int letter, const char *name, MAIL_SCAN_FN scanner) static int mail_scan_any(VSTREAM *stream, VSTRING *vp, char *what) { - if (vstring_fgets_null(vp, stream) == 0) { + if ((vp->maxlen ? vstring_fgets_null_bound(vp, stream, vp->maxlen) + : vstring_fgets_null(vp, stream)) == 0) { msg_warn("mail_scan_any: got EOF; expected: %s", what); return (-1); } @@ -230,9 +234,10 @@ int mail_vscan(VSTREAM *stream, const char *fmt, va_list ap) static VSTRING *tmp; MAIL_SCAN *tp; - if (tmp == 0) + if (tmp == 0) { tmp = vstring_alloc(100); - + tmp->maxlen = var_line_limit; /* good enough for numbers */ + } for (count = 0, error = 0, cp = fmt; error == 0 && *cp != 0; cp++) { if (ISSPACE(*cp)) continue; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index c6cebe89f..138e4030f 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-20000924" +#define DEF_MAIL_VERSION "Snapshot-20000927" extern char *var_mail_version; /* LICENSE diff --git a/postfix/src/nqmgr/qmgr.c b/postfix/src/nqmgr/qmgr.c index 7c1d11a95..af253cecc 100644 --- a/postfix/src/nqmgr/qmgr.c +++ b/postfix/src/nqmgr/qmgr.c @@ -332,12 +332,14 @@ char *var_relocated_maps; char *var_virtual_maps; char *var_defer_xports; bool var_allow_min_user; +char *var_fflush_maps; static QMGR_SCAN *qmgr_incoming; static QMGR_SCAN *qmgr_deferred; MAPS *qmgr_relocated; MAPS *qmgr_virtual; +MAPS *qmgr_fflush; /* qmgr_deferred_run_event - queue manager heartbeat */ @@ -471,6 +473,9 @@ static void qmgr_pre_init(char *unused_name, char **unused_argv) if (*var_virtual_maps) qmgr_virtual = maps_create("virtual", var_virtual_maps, DICT_FLAG_LOCK); + if (*var_fflush_maps) + qmgr_fflush = maps_create(VAR_FFLUSH_MAPS, var_fflush_maps, + DICT_FLAG_LOCK); } /* qmgr_post_init - post-jail initialization */ @@ -508,6 +513,7 @@ int main(int argc, char **argv) VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0, VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0, VAR_DEFER_XPORTS, DEF_DEFER_XPORTS, &var_defer_xports, 0, 0, + VAR_FFLUSH_MAPS, DEF_FFLUSH_MAPS, &var_fflush_maps, 0, 0, 0, }; static CONFIG_INT_TABLE int_table[] = { diff --git a/postfix/src/nqmgr/qmgr.h b/postfix/src/nqmgr/qmgr.h index 2da9dea0b..b06219759 100644 --- a/postfix/src/nqmgr/qmgr.h +++ b/postfix/src/nqmgr/qmgr.h @@ -275,6 +275,7 @@ extern int qmgr_message_count; extern int qmgr_recipient_count; extern MAPS *qmgr_relocated; extern MAPS *qmgr_virtual; +extern MAPS *qmgr_fflush; extern void qmgr_message_free(QMGR_MESSAGE *); extern void qmgr_message_update_warn(QMGR_MESSAGE *); diff --git a/postfix/src/nqmgr/qmgr_deliver.c b/postfix/src/nqmgr/qmgr_deliver.c index 1c92881aa..8d70552c7 100644 --- a/postfix/src/nqmgr/qmgr_deliver.c +++ b/postfix/src/nqmgr/qmgr_deliver.c @@ -124,7 +124,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) QMGR_MESSAGE *message = entry->message; mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld", - message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT, + message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT, message->queue_name, message->queue_id, message->data_offset, message->data_size, entry->queue->name, message->sender, @@ -212,6 +212,12 @@ static void qmgr_deliver_update(int unused_event, char *context) if (queue->window == 0) qmgr_defer_todo(queue, queue->reason); } + + /* + * Optionally add this message to the fast flush log for this site. + */ + if (qmgr_fflush && maps_find(qmgr_fflush, queue->name, 0)) + mail_flush_append(queue->name, message->queue_id); } /* diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index ccd3f09af..e93ab349a 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -117,6 +117,7 @@ static struct queue_info queue_info[] = { MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE, MAIL_QUEUE_DEFER, 0600, RECURSE, MAIL_QUEUE_BOUNCE, 0600, RECURSE, + MAIL_QUEUE_FLUSH, 0600, RECURSE, 0, }; diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index ad3320b48..aa974a8c6 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -135,6 +135,7 @@ qmgr_deliver.o: ../../include/mail_proto.h qmgr_deliver.o: ../../include/recipient_list.h qmgr_deliver.o: ../../include/mail_params.h qmgr_deliver.o: ../../include/deliver_request.h +qmgr_deliver.o: ../../include/mail_flush.h qmgr_deliver.o: qmgr.h qmgr_deliver.o: ../../include/scan_dir.h qmgr_deliver.o: ../../include/maps.h diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c index 374008e92..f8ae84f02 100644 --- a/postfix/src/qmgr/qmgr.c +++ b/postfix/src/qmgr/qmgr.c @@ -292,12 +292,14 @@ bool var_allow_min_user; int var_qmgr_fudge; int var_qmgr_hog; int var_local_rcpt_lim; /* XXX */ +char *var_fflush_maps; static QMGR_SCAN *qmgr_incoming; static QMGR_SCAN *qmgr_deferred; MAPS *qmgr_relocated; MAPS *qmgr_virtual; +MAPS *qmgr_fflush; /* qmgr_deferred_run_event - queue manager heartbeat */ @@ -434,6 +436,9 @@ static void qmgr_pre_init(char *unused_name, char **unused_argv) if (*var_virtual_maps) qmgr_virtual = maps_create("virtual", var_virtual_maps, DICT_FLAG_LOCK); + if (*var_fflush_maps) + qmgr_fflush = maps_create(VAR_FFLUSH_MAPS, var_fflush_maps, + DICT_FLAG_LOCK); } /* qmgr_post_init - post-jail initialization */ @@ -471,6 +476,7 @@ int main(int argc, char **argv) VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0, VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0, VAR_DEFER_XPORTS, DEF_DEFER_XPORTS, &var_defer_xports, 0, 0, + VAR_FFLUSH_MAPS, DEF_FFLUSH_MAPS, &var_fflush_maps, 0, 0, 0, }; static CONFIG_INT_TABLE int_table[] = { diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index 45ceac8e9..71fe6d777 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -242,6 +242,7 @@ extern int qmgr_message_count; extern int qmgr_recipient_count; extern MAPS *qmgr_relocated; extern MAPS *qmgr_virtual; +extern MAPS *qmgr_fflush; extern void qmgr_message_free(QMGR_MESSAGE *); extern void qmgr_message_update_warn(QMGR_MESSAGE *); diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index 466d5360d..0c6685c98 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -62,6 +62,7 @@ #include #include #include +#include /* Application-specific. */ @@ -119,7 +120,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) QMGR_MESSAGE *message = entry->message; mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld", - message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT, + message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT, message->queue_name, message->queue_id, message->data_offset, message->data_size, entry->queue->name, message->sender, @@ -207,6 +208,12 @@ static void qmgr_deliver_update(int unused_event, char *context) if (queue->window == 0) qmgr_defer_todo(queue, queue->reason); } + + /* + * Optionally add this message to the fast flush log for this site. + */ + if (qmgr_fflush && maps_find(qmgr_fflush, queue->name, 0)) + mail_flush_append(queue->name, message->queue_id); } /* diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in index 66a63f31f..66f780f0b 100644 --- a/postfix/src/sendmail/Makefile.in +++ b/postfix/src/sendmail/Makefile.in @@ -85,3 +85,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/sys_exits.h diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index 4863cd99c..412d57972 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -129,6 +129,16 @@ /* .IP "\fB-q\fIinterval\fR (ignored)" /* The interval between queue runs. Use the \fBqueue_run_delay\fR /* configuration parameter instead. +/* .IP \fB-qR\fIsite\fR +/* Schedule immediate delivery of all mail that is queued for the named +/* \fIsite\fR. +/* This functionality is available only for sites that are configured +/* for the \fBfast flush\fR service support as described in +/* \fBflushd\fR(8). For other sites, this command is equivalent to +/* using the slower \fBsendmail -q\fR instead. +/* .IP \fB-qS\fIsite\fR +/* The site name is ignored. This command is equivalent to using +/* the slower \fBsendmail -q\fR instead. /* .IP \fB-t\fR /* Extract recipients from message headers. This requires that no /* recipients be specified on the command line. @@ -210,6 +220,7 @@ /* qmgr(8) queue manager /* showq(8) list mail queue /* smtpd(8) SMTP server +/* flushd(8) fast flush service /* syslogd(8) system logging /* LICENSE /* .ad @@ -270,6 +281,7 @@ #include #include #include +#include /* Application-specific. */ @@ -547,6 +559,30 @@ static void flush_queue(void) msg_warn("Cannot flush mail queue - mail system is down"); } +/* flush_site - flush mail for site */ + +static void flush_site(const char *site) +{ + int code; + + switch (code = mail_flush_site(site)) { + default: + msg_panic("flush_site: unknown result code %d", code); + case FLUSH_STAT_OK: + break; + case FLUSH_STAT_UNKNOWN: + msg_warn("No \"sendmail -qR\" support for site %s", site); + msg_warn("Using the slower \"sendmail -q\" instead"); + flush_queue(); + break; + case FLUSH_STAT_BAD: + msg_fatal("invalid request: %s", site); + case FLUSH_STAT_FAIL: + msg_warn("Cannot flush mail queue - mail system is down"); + break; + } +} + /* sendmail_cleanup - callback for the runtime error handler */ static void sendmail_cleanup(void) @@ -591,6 +627,7 @@ int main(int argc, char **argv) int err; int n; int flags = SM_FLAG_DEFAULT; + char *site_to_flush = 0; /* * Be consistent with file permissions. @@ -777,11 +814,20 @@ int main(int argc, char **argv) sender = optarg; break; case 'q': - if (optarg[0] && !ISDIGIT(optarg[0])) + if (ISDIGIT(optarg[0])) { + if (mode == SM_MODE_DAEMON) { + if (msg_verbose) + msg_info("-%c%s option ignored", c, optarg); + + } + } else if (optarg[0] == 'R') { + site_to_flush = optarg + 1; + } else if (optarg[0] == 'S') { + msg_warn( + "-qS is not implemented - using \"sendmail -q\" instead"); + mode = SM_MODE_FLUSHQ; + } else { msg_fatal("-q%c is not implemented", optarg[0]); - if (mode == SM_MODE_DAEMON) { - if (msg_verbose) - msg_info("-%c%s option ignored", c, optarg); } break; case 't': @@ -801,6 +847,9 @@ int main(int argc, char **argv) if (extract_recipients && mode != SM_MODE_ENQUEUE) msg_fatal("-t can be used only in delivery mode"); + if (site_to_flush && mode != SM_MODE_ENQUEUE) + msg_fatal("-t can be used only in delivery mode"); + if (extract_recipients && argv[OPTIND]) msg_fatal("cannot handle command-line recipients with -t"); @@ -814,7 +863,10 @@ int main(int argc, char **argv) msg_panic("unknown operation mode: %d", mode); /* NOTREACHED */ case SM_MODE_ENQUEUE: - enqueue(flags, sender, full_name, argv + OPTIND); + if (site_to_flush) + flush_site(site_to_flush); + else + enqueue(flags, sender, full_name, argv + OPTIND); exit(0); break; case SM_MODE_MAILQ: diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 765719bf5..b57481f60 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -343,6 +343,7 @@ bool var_smtpd_sasl_enable; char *var_smtpd_sasl_opts; char *var_smtpd_sasl_realm; char *var_filter_xport; +char *var_fflush_maps; /* * Global state, for stand-alone mode queue file cleanup. When this is @@ -527,7 +528,21 @@ static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg, */ if (msg_verbose) msg_info("%s: input: %s", myname, STR(arg->vstrval)); - tree = tok822_parse(STR(arg->vstrval)); + + /* + * Workaround: Sendmail allows arbitrary nesting of <>, so that overpaid + * peecee programmers can get away with monstrosities such as >. By peeling off the outermost <> we can deal with the + * most common problem instance. Don't destroy the input so that we can + * provide accurate diagnostics. + */ + if (arg->strval[0] == '<' && vstring_end(arg->vstrval)[-1] == '>') { + vstring_end(arg->vstrval)[-1] = 0; + tree = tok822_parse(STR(arg->vstrval) + 1); + vstring_end(arg->vstrval)[-1] = '>'; + } else { + tree = tok822_parse(STR(arg->vstrval)); + } /* * Find trouble. @@ -1092,7 +1107,7 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) /* * XXX The preliminary implementation causes a full deferred queue scan. */ - if (mail_flush_site(argv[1].strval) < 0) + if (mail_flush_site(argv[1].strval) != 0) smtpd_chat_reply(state, "458 Unable to queue messages"); else smtpd_chat_reply(state, "250 Queuing started"); @@ -1446,6 +1461,7 @@ int main(int argc, char **argv) VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0, VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 1, 0, VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0, + VAR_FFLUSH_MAPS, DEF_FFLUSH_MAPS, &var_fflush_maps, 0, 0, 0, }; diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 37402f192..28acfb048 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -175,9 +175,6 @@ /* smtpd_check_etrn() validates the domain name provided with the /* ETRN command, and other client-provided information. Relevant /* configuration parameters: -/* .IP smtpd_etrn_restrictions -/* Restrictions on the hostname that is sent with the HELO/EHLO -/* command. /* .PP /* smtpd_check_size() checks if a message with the given size can /* be received (zero means that the message size is unknown). The @@ -313,6 +310,7 @@ static MAPS *rcpt_canon_maps; static MAPS *canonical_maps; static MAPS *virtual_maps; static MAPS *relocated_maps; +static MAPS *fflush_maps; /* * Pre-opened access control lists. @@ -327,7 +325,6 @@ static ARGV *client_restrctions; static ARGV *helo_restrctions; static ARGV *mail_restrctions; static ARGV *rcpt_restrctions; -static ARGV *etrn_restrctions; static HTABLE *smtpd_rest_classes; @@ -458,6 +455,8 @@ void smtpd_check_init(void) DICT_FLAG_LOCK); relocated_maps = maps_create(VAR_RELOCATED_MAPS, var_relocated_maps, DICT_FLAG_LOCK); + fflush_maps = maps_create(VAR_FFLUSH_MAPS, var_fflush_maps, + DICT_FLAG_LOCK); /* * Reply is used as a cache for resolved addresses, and error_text is @@ -475,7 +474,6 @@ void smtpd_check_init(void) helo_restrctions = smtpd_check_parse(var_helo_checks); mail_restrctions = smtpd_check_parse(var_mail_checks); rcpt_restrctions = smtpd_check_parse(var_rcpt_checks); - etrn_restrctions = smtpd_check_parse(var_etrn_checks); /* * Parse the pre-defined restriction classes. @@ -1879,6 +1877,8 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain) int status; char *saved_etrn_name; char *err; + const char *pattern; + ARGV *restrictions; /* * Initialize. @@ -1906,14 +1906,29 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain) SMTPD_CHECK_ETRN_RETURN(err); /* - * Apply restrictions in the order as specified. + * Apply restrictions in the order as specified. If the domain is not + * configured for ETRN, reject the request. */ - state->recursion = 0; - status = setjmp(smtpd_check_buf); - if (status == 0 && etrn_restrctions->argc) - status = generic_checks(state, etrn_restrctions, domain, - SMTPD_NAME_ETRN, CHECK_ETRN_ACL); - + if (*var_fflush_maps == 0 + || (pattern = maps_find(fflush_maps, domain, 0)) == 0) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + "458 Unable to start queueing for %s", + domain); + } else if (strchr(pattern, ':') != 0) { + msg_warn("A fast flush map has an entry with lookup table: %s", + pattern); + msg_warn("do not specify lookup tables inside fast flush maps"); + msg_warn("define a restriction class and specify its name instead"); + status = SMTPD_CHECK_OK; + } else { + restrictions = argv_split(pattern, " \t\r\n"); + state->recursion = 0; + status = setjmp(smtpd_check_buf); + if (status == 0) + status = generic_checks(state, restrictions, domain, + SMTPD_NAME_ETRN, CHECK_ETRN_ACL); + argv_free(restrictions); + } SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); } @@ -2208,7 +2223,6 @@ static REST_TABLE rest_table[] = { "helo_restrictions", &helo_restrctions, "sender_restrictions", &mail_restrctions, "recipient_restrictions", &rcpt_restrctions, - "etrn_restrictions", &etrn_restrctions, 0, }; diff --git a/postfix/src/util/vstring_vstream.c b/postfix/src/util/vstring_vstream.c index 078d255e1..303fc49c6 100644 --- a/postfix/src/util/vstring_vstream.c +++ b/postfix/src/util/vstring_vstream.c @@ -27,6 +27,10 @@ /* VSTRING *vp; /* VSTREAM *fp; /* int bound; +/* +/* int vstring_get_null_bound(vp, fp, bound) +/* VSTRING *vp; +/* VSTREAM *fp; /* DESCRIPTION /* The routines in this module each read one newline or null-terminated /* string from an input stream. In all cases the result is either the @@ -41,12 +45,15 @@ /* vstring_get_null() reads a null-terminated string from the named /* stream. /* -/* vstring_get_bound() and vstring_get_nonl_bound() read no more -/* than \fIbound\fR characters. Otherwise they behave like the -/* unbounded versions documented above. +/* vstring_get_bound(), vstring_get_nonl_bound() and +/* vstring_get_null_bound() read no more than \fIbound\fR characters. +/* Otherwise they behave like the unbounded versions documented above. /* DIAGNOSTICS /* Fatal errors: memory allocation failure. /* Panic: improper string bound. +/* BUGS +/* This code should honor the bound information that is already +/* part of a VSTRING. /* LICENSE /* .ad /* .fi @@ -154,6 +161,22 @@ int vstring_get_nonl_bound(VSTRING *vp, VSTREAM *fp, int bound) return (c == '\n' ? c : VSTRING_GET_RESULT(vp)); } +/* vstring_get_null_bound - read null-terminated string, up to bound */ + +int vstring_get_null_bound(VSTRING *vp, VSTREAM *fp, int bound) +{ + int c; + + if (bound <= 0) + msg_panic("vstring_get_null_bound: invalid bound %d", bound); + + VSTRING_RESET(vp); + while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0) + VSTRING_ADDCH(vp, c); + VSTRING_TERMINATE(vp); + return (c == 0 ? c : VSTRING_GET_RESULT(vp)); +} + #ifdef TEST /* diff --git a/postfix/src/util/vstring_vstream.h b/postfix/src/util/vstring_vstream.h index 897167ca6..fa4d00f84 100644 --- a/postfix/src/util/vstring_vstream.h +++ b/postfix/src/util/vstring_vstream.h @@ -24,6 +24,7 @@ extern int vstring_get_nonl(VSTRING *, VSTREAM *); extern int vstring_get_null(VSTRING *, VSTREAM *); extern int vstring_get_bound(VSTRING *, VSTREAM *, int); extern int vstring_get_nonl_bound(VSTRING *, VSTREAM *, int); +extern int vstring_get_null_bound(VSTRING *, VSTREAM *, int); /* * Backwards compatibility for code that still uses the vstring_fgets() @@ -39,6 +40,8 @@ extern int vstring_get_nonl_bound(VSTRING *, VSTREAM *, int); (vstring_get_bound((s), (p), (l)) == VSTREAM_EOF ? 0 : (s)) #define vstring_fgets_nonl_bound(s, p, l) \ (vstring_get_nonl_bound((s), (p), (l)) == VSTREAM_EOF ? 0 : (s)) +#define vstring_fgets_null_bound(s, p, l) \ + (vstring_get_null_bound((s), (p), (l)) == VSTREAM_EOF ? 0 : (s)) /* LICENSE /* .ad