Qmail setup as described so far can provide full email service. This setup is, however, rather minimal, and lacks many administrative, maintenance, and troubleshooting features. Because qmail is designed to be modular, these deficiencies are easily remedied with additional programs.
There are a great number of patches available for qmail that provide various sundry features, behavioral tweaks, and even minor bug fixes. There are two schools of thought on how to approach qmail with its plethora of patches. One is to come up with some "official" collection of patches (or just all the patches that sound sufficiently nifty or useful), apply them all, and go from there. The other is to treat qmail more like an efficient mechanism to achieve exactly what needs to be done and no more. This book falls into the latter category. There are several projects that provide "mega"-patches or that package qmail in a way that includes many patches, such as qmailrocks (http://www.qmailrocks.com), Bill Shupp's megapatch (http://www.shupp.org/), Matt Simerson's megatoaster (http://www.tnpi.biz/internet/mail/qmail/qmail.toaster1.2.shtml), and many others.
It is very tempting, particularly when new to qmail, to simply grab a bunch of (neat-sounding) patches and apply them all. This can be a dangerous thing to do unless you know C and SMTP well and can resolve patch conflicts. Even if the patches apply cleanly, the new features may be unnecessary and/or confusing (and may still conflict in terms of their effect). Keep in mind that qmail works just fine without them, and many of them provide features that can be obtained in other ways. Patching is an option, and one that should be used carefully. Every unused feature is memory (and CPU-time) wasted, and a potential source for an unexpected bug or security flaw—many patches have not been as rigorously designed or tested as qmail.
The approach encouraged in this book is one of being pragmatic and efficient (and, consequently, rather minimalist): use patches because the features they provide are necessary, and understand them before applying them. Thus, in this book patch URLs are presented alongside more lengthy explanations of the goal they accomplish and the alternatives and/or downsides.
The most widely recommended method for running qmail uses the daemontools and ucspi-tcp packages, both written by the author of qmail, Dr. Bernstein.
The ucspi-tcp package consists of a set of useful programs for connecting to the network and maintaining simple databases of environment-variable/connection rules. For example, tcpserver
is included as part of ucspi-tcp.
The daemontools package contains the svscan/supervise
programs for running, monitoring, and controlling long-running programs (daemons), and for connecting them to safe logging mechanisms (e.g. multilog
). The default installation of daemontools creates a /service
directory. To control a daemon with svscan
, add a directory for that daemon to the /service
directory. The svscan
program starts up an instance of the supervise
program for each subdirectory of the /service
directory. Each of these directories must contain a shell script named run
that contains all the necessary commands for starting the specific daemon. The run
script must not exit until the daemon it commands exits. When the run
script exits, the directory's supervise
process restarts it, unless the supervise
process has been told not to do so (for e.g. by placing a file named down
in the subdirectory).
The combination of these two packages is a powerful setup for controlling, monitoring, and maintaining a qmail server.
Installing these packages is very simple. The ucspi-tcp package can be installed by simply downloading it (http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz), decompressing it, and running make setup check
in the decompressed source directory.
The daemontools' installation is slightly more complicated.
1. You must create a
/package
directory:
mkdir -p /package
chmod 1755 /package
cd /package
2. Download the daemontools source into this
/package
directory, decompress it, and move into the resulting folders, as follows:
wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
tar xzvf daemontools-0.76.tar.gz
rm daemontools-0.76.tar.gz
cd admin/daemontools-0.76
csh -cf '/command/svscanboot &'
Basic use of the tcpserver
program from the ucspi-tcp package has been covered previously. However, the tcpserver
program has many options that are of importance to a well-maintained qmail installation. There are two main areas where tcpserver
shines and is often configured according to the system-administrator's personal preference. The first is in data collection; the second is in setting appropriate environment variables and asserting behaviors based on which remote system connects to tcpserver
.
The tcpserver
program can collect some basic information about the remote server, as described by the possible environment variables in the previous table. However, in many cases, such information is either irrelevant or unnecessary, and the collection of such data can be eliminated to improve connection latency. For example, looking up the remote host's IP address in DNS or attempting to make an ident
query to identify the remote user may not provide much benefit, but does slow down connection attempts. Turning off such queries may improve initial connection latency, if that is a concern.
For example, by default, tcpserver
looks up the remote host's hostname in DNS. If this is unnecessary, giving tcpserver
the -H
flag prevents this, and consequently prevents tcpserver
from providing the TCPREMOTEHOST
environment variable to whatever program it runs (e.g. qmail-smtpd
). Similarly, if ident information is unnecessary, giving tcpserver
the -R
flag will prevent it from performing that query.
The tcpserver
program can also be configured to use a small database (in CDB format) of rules defining when to allow or deny connections and which (if any) environment variables to set, based on the data it knows about the remote host.
The most common method of specifying these connection rules is to create a text file, /etc/tcp.smtp
, in a specific format that is compiled by the tcprules
program into the CDB database used by tcpserver
(e.g. /etc/tcp.smtp.cdb
). The format of a rule in a tcprules
file (such as /etc/tcp.smtp
) is:
matcher : decision , environment-variables (if any)
Connection rules are matched on a first-match-wins basis. For example:
192.168.1.2:deny 192.168.1.:allow,RELAYCLIENT="" =www.example.com:allow,RELAYCLIENT="" =:allow :deny
This rule file would deny all connections from the 192.168.1.2
IP address, but would allow anything else in the 192.168.1.x
IP range to connect and would set the RELAYCLIENT
environment variable for those connections. If the DNS hostname of the remote host is www.example.com
, this file allows that host to connect and sets the RELAYCLIENT
environment variable. Any other host that has a hostname (denoted by the =
sign) is allowed to connect, and finally any other connection attempt (i.e. from a host without a hostname) is rejected.
This rule file can be compiled into a CDB database file as follows:
tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
The tcpserver
program can then be told to use that CDB database by giving it the -x
flag with the name of the CDB
file, for example:
tcpserver -u `id -u qmaild` -g `id -g qmaild` \
-x /etc/tcp.smtp.cdb \
0 smtp /var/qmail/bin/qmail-smtpd
The basic format of a supervise-controlled
service is a folder containing a shell script named run
. This shell script eventually must run the service (daemon) that is to be controlled and must not exit until that daemon does. A good example of what might go into a run
file is the /var/qmail/rc
script built as part of the previously discussed basic qmail install. This script prepares qmail to run, and then runs it. As long as qmail-start
is still running, the script does not exit. Thus, a very simple service folder for the delivery side of qmail is a folder containing that rc
file, renamed run
.
An extension to the previously described basic service-directory format is possible. The extension is to add a folder named log
within the daemon's directory, which contains another shell script named run
. In this extension, the standard output of the first first-level run
file is piped as input to the log
directory's run
file. In this way, the daemon can be stopped and started independently of the logging mechanism, which can be any logging mechanism that accepts standard input, such as splogger
or something similar. An easy, powerful method of logging is the multilog
program (a part of the daemontools package), which saves log output in a crash-resistant, automatically rotating manner with high-precision timestamps.
Ordinarily, qmail-start
uses the logging mechanism specified in the rc
file, usually splogger
. However, if the rc
file (and thus, qmail-start)
is controlled by svscan
, it can be more useful to remove the logging argument from the rc
file. This change causes qmail-send's
log messages to be sent to standard output, which can then be used by svscan's
more flexible logging architecture. There's no benefit from this if you are using the splogger
utility, but more powerful logging tools, such as multilog
, do benefit from the change. The run
file for the qmail-send
service directory might look something like the following:
#!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start ./Mailbox
A log/run
file for the qmail-send
service directory might look similar to the following:
#!/bin/sh exec setuidgid qmaill multilog t /var/log/qmail/qmail-send/
The beginning of this command, setuidgid qmaill
uses the setuidgid
tool from the ucspi-tcp package. The previous command is essentially equivalent to the following:
exec su qmaill -c 'multilog t /var/log/qmail/qmail-send/'
This is because both switch to a different user (qmaill) before running the rest of the command, but the setuidgid
version is easier to read and type. The reason for using the qmaill user for logging is that it prevents the logs from being altered even if an attacker controls the process generating the logs (qmail-send, in this case).
This same structure can be used for running qmail-smtpd
in a controllable, monitorable fashion. Simply create a directory for it (e.g. /var/qmail/supervise/smtpd
) and create a run
file for it, such as:
#!/bin/sh QUID=`id -u qmaild` QGID=`id -g qmaild` LOCAL=`head -1 /var/qmail/control/me` if [ ! f /var/qmail/control/rcpthosts ]; then echo "Without a rcpthosts file, qmail is an open relay." echo "Open relays are spammer havens." echo "Please use a rcpthosts file." exit 1 fi exec tcpserver -R -l "$LOCAL" -H \ -x /etc/tcp.smtp.cdb \ -u "$QUID" -g "$QGID" \ 0 smtp \ /var/qmail/bin/qmail-smtpd 2>&1
Then create in that directory another directory named log
, and in the log
directory, a run
file such as:
#!/bin/sh exec setuidgid qmail multilog t /var/log/qmail/smtpd/
Once these files are created, telling svscan
to use them to control the service they specify is a two-step process. First, make sure that the run
files are executable:
chmod +x /var/qmail/supervise/smtpd/run
chmod +x /var/qmail/supervise/smtpd/log/run
Then link the daemon's directory into /service
, as follows:
ln -s /var/qmail/supervise/smtpd /service/qmail-smtpd
Wait a few moments, and then run the following to double-check that all is well.
svstat /service/qmail-smtpd
If it started as it should, the output of that command should indicate that the service in question (qmail-smtpd) has been running for a few seconds already. You can perform essentially the same procedure on the qmail-start
service directory, or any other daemon to be controlled by svscan
.
Once svscan
is controlling a folder and the associated daemon, you can command the daemon with the svc
command. For example:
svc -d /service/qmail-smtpd
This will order the qmail-smtpd
service to stop by sending it a TERM signal. Using the -h
flag instead of -d
will cause the service to receive a HUP signal; in the case of qmail-start
, this causes qmail to re-read many of its configuration files. This reread-config-on-HUP is a behavior shared by many UNIX daemons. The -u
flag will cause the service to start again after having been stopped by the -d
flag. The -t
flag, like the -d
flag, also sends a TERM signal. However, unlike the -d
flag, the service is restarted as soon as it exits.
It is important to note that the TERM signal sent by the -t
and -d
flags does not cause all daemons to exit immediately. For example, when qmail-send
receives a TERM signal, it finishes all deliveries currently in progress before exiting—which means that it may take several minutes to exit. To bring a daemon down immediately, use the -k
flag, which sends the un-ignorable KILL signal. Note, though, that while the KILL signal will immediately terminate any process not protected by the kernel, the signal is not propagated to any of the daemon's child processes. Also, the -k
flag alone allows the server to restart once it exits (similar to the -t
flag). Thus, it is often used after the -d
flag has been used first, to terminate a recalcitrant daemon.