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 <the dude <dude@site>> 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".
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
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
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
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
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 \
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 >$@
--- /dev/null
+<html> <head> </head> <body> <pre>
+
+
+
+FLUSHD(8) FLUSHD(8)
+
+
+<b>NAME</b>
+ flushd - Postfix fast flush daemon
+
+<b>SYNOPSIS</b>
+ <b>flushd</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+ 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 <a href="master.8.html"><b>mas-</b>
+ <b>ter</b>(8)</a> 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.
+
+<b>SECURITY</b>
+ 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.
+
+<b>DIAGNOSTICS</b>
+ Problems and transactions are logged to <b>syslogd</b>(8).
+
+<b>BUGS</b>
+ 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.
+
+<b>CONFIGURATION</b> <b>PARAMETERS</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
+ command after a configuration change.
+
+ <b>fast</b><i>_</i><b>flush</b><i>_</i><b>maps</b>
+ 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.
+
+ <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
+ Maximal length of strings in a fast flush client
+ request.
+
+<b>SEE</b> <b>ALSO</b>
+ <a href="smtp.8.html">smtp(8)</a> Postfix SMTP client
+ smtpd) Postfix SMTP server
+ <a href="qmgr.8.html">qmgr(8)</a> Postfix queue manager
+ syslogd(8) system logging
+
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
+<b>AUTHOR(S)</b>
+ Wietse Venema
+ IBM T.J. Watson Research
+ P.O. Box 704
+ Yorktown Heights, NY 10598, USA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+</pre> </body> </html>
The interval between queue runs. Use the
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead.
- <b>-t</b> Extract recipients from message headers. This
- requires that no recipients be specified on the
- command line.
-
- <b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ <b>-qR</b><i>site</i>
+ Schedule immediate delivery of all mail that is
+ queued for the named <i>site</i>. This functionality is
+ available only for sites that are configured for
+ the <b>fast</b> <b>flush</b> service support as described in
+ <b>flushd</b>(8). For other sites, this command is
SENDMAIL(1) SENDMAIL(1)
+ equivalent to using the slower <b>sendmail</b> <b>-q</b> instead.
+
+ <b>-qS</b><i>site</i>
+ The site name is ignored. This command is equiva-
+ lent to using the slower <b>sendmail</b> <b>-q</b> instead.
+
+ <b>-t</b> Extract recipients from message headers. This
+ requires that no recipients be specified on the
+ command line.
+
+ <b>-v</b> Enable verbose logging for debugging purposes. Mul-
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>SECURITY</b>
- 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.
<b>DIAGNOSTICS</b>
- Problems are logged to <b>syslogd</b>(8) and to the standard
+ Problems are logged to <b>syslogd</b>(8) and to the standard
error stream.
<b>ENVIRONMENT</b>
<b>MAIL</b><i>_</i><b>DEBUG</b>
Enable debugging with an external command, as spec-
- ified with the <b>debugger</b><i>_</i><b>command</b> configuration
+ ified with the <b>debugger</b><i>_</i><b>command</b> configuration
parameter.
<b>FILES</b>
/etc/postfix, configuration files
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- See the Postfix <b>main.cf</b> file for syntax details and for
- default values. Use the <b>postfix</b> <b>reload</b> command after a
+ See the Postfix <b>main.cf</b> file for syntax details and for
+ default values. Use the <b>postfix</b> <b>reload</b> command after a
configuration change.
<b>alias</b><i>_</i><b>database</b>
- Default alias database(s) for <b>newaliases</b>. The
- default value for this parameter is system-spe-
+ Default alias database(s) for <b>newaliases</b>. The
+ default value for this parameter is system-spe-
cific.
<b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
The amount of original message context that is sent
along with a non-delivery notification.
- <b>database</b><i>_</i><b>type</b>
- Default alias etc. database type. On many UNIX sys-
- tems the default type is either <b>dbm</b> or <b>hash</b>.
-
- <b>debugger</b><i>_</i><b>command</b>
- Command that is executed after a Postfix daemon has
- initialized.
-
- <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
- Increment in verbose logging level when a remote
- host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
- parameter.
SENDMAIL(1) SENDMAIL(1)
+ <b>database</b><i>_</i><b>type</b>
+ Default alias etc. database type. On many UNIX sys-
+ tems the default type is either <b>dbm</b> or <b>hash</b>.
+
+ <b>debugger</b><i>_</i><b>command</b>
+ Command that is executed after a Postfix daemon has
+ initialized.
+
+ <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
+ Increment in verbose logging level when a remote
+ host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
+ parameter.
+
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
- 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
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
<b>fork</b><i>_</i><b>attempts</b>
- Number of attempts to <b>fork</b>() a process before giv-
+ Number of attempts to <b>fork</b>() a process before giv-
ing up.
<b>fork</b><i>_</i><b>delay</b>
- Delay in seconds between successive <b>fork</b>()
+ Delay in seconds between successive <b>fork</b>()
attempts.
<b>hopcount</b><i>_</i><b>limit</b>
Limit the number of <b>Received:</b> message headers.
<b>mail</b><i>_</i><b>owner</b>
- The owner of the mail queue and of most Postfix
+ The owner of the mail queue and of most Postfix
processes.
<b>command</b><i>_</i><b>directory</b>
- Directory with Postfix support commands (default:
+ Directory with Postfix support commands (default:
<b>$program</b><i>_</i><b>directory</b>).
<b>daemon</b><i>_</i><b>directory</b>
- Directory with Postfix daemon programs (default:
+ Directory with Postfix daemon programs (default:
<b>$program</b><i>_</i><b>directory</b>).
<b>queue</b><i>_</i><b>directory</b>
- 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.
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b>
- The time between successive scans of the deferred
+ The time between successive scans of the deferred
queue.
<b>SEE</b> <b>ALSO</b>
<a href="pickup.8.html">pickup(8)</a> mail pickup daemon
<a href="postalias.1.html">postalias(1)</a> maintain alias database
- <a href="postdrop.1.html">postdrop(1)</a> privileged posting agent
- <a href="postfix.1.html">postfix(1)</a> mail system control
- <a href="postkick.1.html">postkick(1)</a> kick a Postfix daemon
- <a href="qmgr.8.html">qmgr(8)</a> queue manager
- <a href="showq.8.html">showq(8)</a> list mail queue
- <a href="smtpd.8.html">smtpd(8)</a> SMTP server
- syslogd(8) system logging
-
-<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
- software.
-
-
SENDMAIL(1) SENDMAIL(1)
+ <a href="postdrop.1.html">postdrop(1)</a> privileged posting agent
+ <a href="postfix.1.html">postfix(1)</a> mail system control
+ <a href="postkick.1.html">postkick(1)</a> kick a Postfix daemon
+ <a href="qmgr.8.html">qmgr(8)</a> queue manager
+ <a href="showq.8.html">showq(8)</a> list mail queue
+ <a href="smtpd.8.html">smtpd(8)</a> SMTP server
+ flushd(8) fast flush service
+ syslogd(8) system logging
+
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
-
-
-
-
-
-
-
-
-
-
-
-
-
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 \
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 $? >$@
.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.
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
--- /dev/null
+.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
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+/*++
+/* 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 <sys_defs.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <utime.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <events.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <vstring_vstream.h>
+#include <myflock.h>
+#include <valid_hostname.h>
+#include <htable.h>
+#include <dict.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <mail_proto.h>
+#include <mail_flush.h>
+#include <mail_conf.h>
+#include <maps.h>
+
+/* Single server skeleton. */
+
+#include <mail_server.h>
+
+ /*
+ * 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);
+}
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 =
lint $(DEFS) $(SRCS) $(LINTFIX)
clean:
- rm -f *.o $(LIB) *core $(TESTPROG) junk
+ rm -f *.o $(LIB) *core $(TESTPROG) junk
rm -rf printfck
tidy: clean
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
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
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
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
/*
* 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 */
/* NAME
/* mail_flush 3
/* SUMMARY
-/* flush backed up mail
+/* mail flush service client interface
/* SYNOPSIS
/* #include <mail_flush.h>
/*
/*
/* 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
/* System library. */
#include "sys_defs.h"
+#include <unistd.h>
+#include <stdarg.h>
/* Utility library. */
+#include <msg.h>
+#include <vstream.h>
+
/* Global library. */
#include <mail_proto.h>
#include <mail_flush.h>
+#include <mail_params.h>
/* mail_flush_deferred - flush deferred queue */
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);
}
/* 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)
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
+/**INDENT** Error@33: Unmatched #endif */
#endif
#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
#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
#include <make_dirs.h>
#include <split_at.h>
#include <sane_fsops.h>
+#include <valid_hostname.h>
/* Global library. */
{
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);
#define MAIL_QUEUE_DEFER "defer"
#define MAIL_QUEUE_BOUNCE "bounce"
#define MAIL_QUEUE_CORRUPT "corrupt"
+#define MAIL_QUEUE_FLUSH "flush"
/*
* Queue file modes.
/* 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
/* Global library. */
#include "mail_proto.h"
+#include "mail_params.h"
/*
* Provision for the user to register type-specific input conversion
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);
}
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;
* 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
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 */
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 */
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[] = {
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 *);
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,
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);
}
/*
MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE,
MAIL_QUEUE_DEFER, 0600, RECURSE,
MAIL_QUEUE_BOUNCE, 0600, RECURSE,
+ MAIL_QUEUE_FLUSH, 0600, RECURSE,
0,
};
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
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 */
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 */
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[] = {
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 *);
#include <recipient_list.h>
#include <mail_params.h>
#include <deliver_request.h>
+#include <mail_flush.h>
/* Application-specific. */
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,
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);
}
/*
sendmail.o: ../../include/resolve_clnt.h
sendmail.o: ../../include/mail_flush.h
sendmail.o: ../../include/mail_stream.h
+sendmail.o: ../../include/sys_exits.h
/* .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.
/* qmgr(8) queue manager
/* showq(8) list mail queue
/* smtpd(8) SMTP server
+/* flushd(8) fast flush service
/* syslogd(8) system logging
/* LICENSE
/* .ad
#include <tok822.h>
#include <mail_flush.h>
#include <mail_stream.h>
+#include <sys_exits.h>
/* Application-specific. */
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)
int err;
int n;
int flags = SM_FLAG_DEFAULT;
+ char *site_to_flush = 0;
/*
* Be consistent with file permissions.
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':
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");
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:
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
*/
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 <the dude
+ * <dude@site>>. 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.
/*
* 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");
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,
};
/* 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
static MAPS *canonical_maps;
static MAPS *virtual_maps;
static MAPS *relocated_maps;
+static MAPS *fflush_maps;
/*
* Pre-opened access control lists.
static ARGV *helo_restrctions;
static ARGV *mail_restrctions;
static ARGV *rcpt_restrctions;
-static ARGV *etrn_restrctions;
static HTABLE *smtpd_rest_classes;
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
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.
int status;
char *saved_etrn_name;
char *err;
+ const char *pattern;
+ ARGV *restrictions;
/*
* Initialize.
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);
}
"helo_restrictions", &helo_restrctions,
"sender_restrictions", &mail_restrctions,
"recipient_restrictions", &rcpt_restrctions,
- "etrn_restrictions", &etrn_restrctions,
0,
};
/* 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
/* 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
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
/*
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()
(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