2.1 Small Programs Work Together

Earlier MTAs were written as large monolithic programs. Sendmail, for example, is one large executable program that listens for incoming SMTP connections, accepts locally generated mail, queues mail, attempts outgoing SMTP deliveries, performs local deliveries, interprets .forward files, retries mail that for which earlier delivery attempts failed, and about 50 other functions. While this means that all of these functions can share utility routines and it's easy for one function to call on another or pass a message to another, it also means that sendmail is a large program (300 KB of code on my system, not including any libraries it uses) that is slow to start up and expensive to fork, and bugs anywhere in the code can potentially make any of the functions misbehave or fail. Other monolithic MTAs, such as smail and exim, share these problems.

Qmail, on the other hand, is about 10 small programs, none with as much as 30 KB of code, working together. This design approach offers many advantages.

2.1.1 Each Program Does One Thing

Each of qmail's programs performs a single function. For example, qmail-lspawn spawns (starts up) local deliveries, and qmail-clean deletes the queue files of messages that have been completely processed. The various programs use documented protocols to communicate, which makes it easier both to debug them and to substitute one version of a program for another.

For example, on a local area network (LAN) with several workstations, the most common mail setup is for one server to handle all of the incoming mail and deliveries. All the other workstations use that server as a "smarthost" and immediately forward locally generated mail to the smarthost. In this arrangement, each workstation traditionally has a complete implementation of the MTA, with configuration files set to forward mail to the smarthost. Note that about 90% of the MTA's function is present but not used, and strange bugs often surface when the configuration files on the workstations get out of sync with each other. The optional QMQP package makes it possible to install a tiny "mini-qmail" package on the workstations, with the only configuration being the address of the smarthost. In a regular qmail installation, the program qmail-queue takes a message and creates a queue entry so the message can be processed and delivered. Several other programs call qmail-queue, including qmail-smtpd, which receives incoming mail via SMTP, and qmail-inject, which receives locally generated mail. QMQP replaces qmail-queue with a small program that immediately forwards incoming mail to the smarthost. There's no need to install the queueing and delivery part of qmail on the workstations, but to the programs that call qmail-queue, mail works the same as it always did.

2.1.2 The Principle of Least Privilege

Most monolithic MTAs have to run as the super-user to open the "privileged" port 25 for SMTP service and deliver mail to user mailboxes that are not world-writable. Qmail uses the principle of least privilege, which means it runs only the program that starts local mail deliveries, qmail-lspawn, as root. All of the other programs run as nonprivileged user IDs. Different parts of qmail use different IDs for example, only the parts that change the mail queue run as the user that can write to the queue directories. This offers an extra level of resistance to accidental or deliberate errors.

Qmail also offers the very useful ability to delegate management of a virtual domain to a Unix user in a simple and secure way. The user can manage all the addresses in the domain by adjusting his own files as needed without ever having to bother the system manager or run super-user privileged programs.

2.1.3 Program Wrapping

Qmail makes extensive use of program wrapping to allow users and administrators to add and modify features.[1] A wrapper program runs a second program, modifying the second program's action in some way. The syntax for wrapper programs is:

[1] There's no standard name for this clever software design. Some people call it program chaining, and some people call it Bernstein chaining or a djb pipeline because Dan Bernstein is one of its best-known users.

wrapper wrapargs program progargs

That is, first come any arguments the wrapper takes, then the name of the program to run.

For example, when qmail runs a program for local delivery, it does not normally insert a mailbox separator line at the beginning of the message, but some programs, such as the procmail mail sorting package, require that line. The preline wrapper program provides the needed line:

| preline procmail arguments

That is, preline runs the program given as its argument, inserting a separator line ahead of the input.

In some cases, multiple wrappers can be cascaded, with several setup programs running each other in turn to create the environment for a main program. For example, the qmail POP3 daemon is implemented in three parts. The outermost, qmail-popup reads the username and password from the client. It then runs checkpassword, which validates the username and password, and changes to the directory that contains the mail. Finally, it then runs qmail-pop3d, which runs the rest of the POP3 session. By substituting different versions of checkpassword, it's easy to handle mail-only users, addresses in virtual domains, or any other local mailbox and password conventions.

2.1.4 No New Languages

Qmail tries very hard not to create new configuration or command languages, in reaction to the baffling complexity of the sendmail configuration-file language. Instead, qmail uses standard Unix features wherever possible. We saw program wrapping, previously, as one way to make programs configurable. The other way is to use the standard Unix shell. Rather than put a lot of options into the syntax of .qmail files, which control local deliveries, qmail builds in only the two most common options: delivery to a mailbox and forwarding to a fixed address. For anything else, you put shell commands in the .qmail file, generally using a few small helper programs such as forward, which sends a message to the address(es) given as arguments. This has proven in practice to be very flexible, and it's usually possible to express complex delivery rules in a few lines of shell script.

2.1.5 Configuration Files

Rather than put all of the configuration information into one huge file, qmail splits it up into multiple small files. The global configuration information goes into files in /var/qmail/control, while per-user delivery instructions go into files in each user's home directory.

Most of the files are simple lines of text, such as /var/qmail/localhosts, which lists the hostnames that should be treated as local to the system on which qmail is running, one per line. As a concession to efficiency, files that could potentially become large, such as the list of virtual domains, are compiled into CDB files that use a hashing technique to permit programs to look up any entry with one or two disk reads. Each file contains only one kind of information, so there's no need for a language to define file sections or subsections.



qmail
qmail
ISBN: 1565926285
EAN: 2147483647
Year: 2006
Pages: 152

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net