Related links:
All qmail/mess822-related patches and scripts here are in the public domain.
The qmail-realrcptto
patch copies logic from qmail-send
,
qmail-lspawn
, qmail-getpw
, and
qmail-local
into qmail-smtpd
and
qmail-qmtpd
, so that if a local delivery (i.e., one for a domain
in /var/qmail/control/locals
or virtualdomains
)
would eventually bounce due to a missing .qmail
file, then that
recipient address is rejected during the SMTP or QMTP protocol conversation.
There are other qmail patches around that do similar jobs (badrcptto, etc.);
the focus of this patch is to get this functionality with no additional
administrative effort, rather than qmail-smtpd
's running speed.
You just set up your .qmail
files, as you would have to do
anyway, and the rest is automatic, though slower than a CDB lookup.
Addresses which use the default delivery instructions are never rejected by
this patch, because they would never be bounced due to the lack of a
.qmail
file. If you're not sure whether this patch will reject
mail for certain addresses on your system, you can check using the qtraceaddr script below. If it reports
“bounce message due to lack of a .qmail file
”, then
qmail-realrcptto will reject mail for that address; otherwise mail will be
accpeted.
This makes less work for the qmail machine, since these undeliverable addresses are rejected before ever entering the qmail queue (but it makes more work - to perform the check itself - in cases that would not bounce). Joe-job double bounces are also eliminated.
Note that with this patch, qmail-smtpd
and
qmail-qmtpd
will always use the latest versions of the control
files envnoathost
, locals
,
percenthack
, and virtualdomains
, while
qmail-send
will use its cached copy in memory until it receives
SIGHUP
or is restarted. (Even after SIGHUP
,
qmail-send
still uses the old envnoathost
and
percenthack
.) So after control files are changed, and before
qmail-send
is notified, it is possible that a message recipient
might be accepted through the network even though it would bounce later, or a
message recipient might be rejected through the network even though the
delivery would succeed.
If QMAILRRTDENYALL=1
is set in the environment for
qmail-smptd
and qmail-qmtpd
, then each individual
recipient address will be accepted, but the whole message will be rejected,
to stop attackers from probing for valid addresses. It's still possible to
probe by sending empty, single-recipient messages, and then sending the real
message with all the recipients that weren't rejected.
This patch is less effective when there are .qmail-default
files, or when qmaild
does not have sufficient filesystem
permissions to stat()
users' .qmail
files, since in
those cases, qmail-smtpd
cannot know that the delivery would
later bounce due to the lack of a .qmail
file. For example, I'm
told that this patch is not useful for virtual domains managed with vpopmail,
since an applicable .qmail-default
file always exists. (I'm not
familiar with vpopmail myself.) The patch may still be useful for other
local or virtual domains on the same server, if they are not managed by
vpopmail.
The qmail-branch patch
enhances the .qmail
delivery instruction language, narrowing the
gap between qmail-local
and procmail
. If you have
a sequence of lines like:
?label command arg ... ... :label
qmail-local
will deliver the message to the command just as it
does for a |command
line, and if the command exits with status
99, qmail-local
will skip down to the :label
line;
delivery instructions in the intervening lines are ignored. If the
command exits with status other than 99, the result is the same as
with a |command
line. :label
lines are
otherwise ignored, just like #comment
lines.
A label is a (possibly empty) sequence of non-space, non-tab, nonzero
bytes. Text following a label on a ":
" line is
ignored. If there is no command on a ?label
line, it's
an unconditional jump. If a command exits 99 and the corresponding
label is not found, all following delivery instructions are skipped
(as with |command
). There are no backward jumps.
This makes the .qmail
language a little more useful, IMO,
but not enough to cause trouble. :) (You get if-then-else, but no
loops.) The syntax is a little ugly, but it gets the job done. The
same functionality is already available with |command
lines, but then you need multiple .qmail
files, which
exposes extra addresses to outside senders, so it gets a little more
complicated.
A .qmail
file using this feature might look like:
# Sort out mail from Sue. ?test [ "$SENDER" = sue@somewhere.org ] || exit 99 /home/b1ff/mail/sue/ # Skip all further processing. ?done :test # Is this a copy of a mailing list message? ?test iftocc `cat lists` || exit 99 # Bounce this copy. |cat duplicate; exit 100 :test # Deliver to the default mailbox. /home/b1ff/mail/main/
Another way of tackling this problem is to do all deliveries for a given
address from a single shell script, and then to deliver to just that shell
script in the .qmail
file. This requires manually rewinding the
standard input between deliveries; you can do this with
seek0. This is more error-prone, but faster,
since a shell is spawned only once per message. I might write a wrapper for
qmail-local
that checks for such a delivery script called
.qmailx
adjacent to .qmail
, executes it without
forking if it exists, and executes qmail-local
without forking
otherwise.
The qtraceaddr Perl script illustrates how qmail
decides how to deliver messages for any addresses given on the command line.
If your qmail installation used non-default values for
conf-qmail
, conf-break
, or the alias
user, you can specify them in the $QMAIL
,
$QMAILBREAK
, and $QMAILALIAS
environment variables.
For example:
# env QMAILBREAK=+ /path/to/qtraceaddr address@example.org
The mess822-nonroot
patch prevents mess822 from installing its own leapsecs.dat
file in /etc
. This is useful for installing mess822 as a
non-root user or when the existing /etc/leapsecs.dat
file is
more up-to-date than the one in mess822.