qmail (original) (raw)
Related links:
- qmail.org, with lots of patches, tools, documentation, and more.
- A searchable archive of the qmail mailing list.
- Life with qmail, detailed instructions for installing and configuring qmail.
All qmail/mess822-related patches and scripts here are in the public domain.
The qmail-realrcptto patch
The qmail-realrcptto patch copies logic from qmail-send
,qmail-lspawn
, qmail-getpw
, andqmail-local
into qmail-smtpd
andqmail-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
andqmail-qmtpd
will always use the latest versions of the control files envnoathost
, locals
,percenthack
, and virtualdomains
, whileqmail-send
will use its cached copy in memory until it receivesSIGHUP
or is restarted. (Even after SIGHUP
,qmail-send
still uses the old envnoathost
andpercenthack
.) So after control files are changed, and beforeqmail-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 forqmail-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
The qmail-branch patchenhances 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 ; 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 withseek0. This is more error-prone, but faster, since a shell is spawned only once per message. I might write a wrapper forqmail-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 script
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 forconf-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
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.