10.1 How Qmail Delivers Local Mail

Every local message is delivered to the local part of its target address, the part of the address to the left of the at-sign. The local part may come directly from an incoming message, or it may be generated internally by qmail, particularly for mail to virtual domains (see Chapter 12), which construct the local part from a combination of the incoming address and information about the virtual domain.

If the local part of an address contains one or more hyphens, the part before the first hyphen is consider the user and the rest is the extension. If the local part doesn't contain a dash (hyphen), the local part is the user and there's no extension.

10.1.1 Identifying the User

The first step in a local delivery is to identify the user corresponding to the local part and retrieve several items about the user. The items are:

  • Username, that is, the login name that is usually but not necessarily the same as the qmail user.

  • The numeric user ID.

  • The numeric group ID.

  • The home directory.

  • The dash character, if the local part had an extension. This is almost always an actual dash, although for maximum sendmail compatibility some people use a plus sign instead.

  • The extension, usually the extension from the local part.

Qmail uses two techniques to retrieve the user information. First it checks the users database, which the qmail manager can and usually should create. (I discuss it in more detail Chapter 15.) If there is no users database or an address doesn't appear in the database, it runs qmail-getpw to get the information from the Unix password file. If both of those fail, it prepends alias- to the address and tries again, so that unknown addresses are treated as subaddresses of the alias user.

10.1.2 Locating the .qmail File

All local deliveries are controlled through a .qmail file. Once qmail has the user information corresponding to a local part, selecting the qmail file is straightforward. All .qmail files are located in the user's home directory.[1] If the local part has no extension, the .qmail file is called .qmail. If Fred's home directory is /home/fred, mail for the address fred is handled by /home/fred/.qmail. If there's an extension, it's .qmail-extension; for example, mail to fred-fishing would be handled by /home/fred/.qmail-fishing. If the .qmail file for an address with an extension doesn't exist, qmail also looks for a .qmail file, replacing the extension with -default, as in /home/fred/.qmail-default. If there are multiple levels of extension, qmail searches for defaults one level at a time, and mail for fred-fishing-lures is now handled by /home/fred/.qmail-fishing-lures, or /home/fred/.qmail-fishing-default, or /home/fred/.qmail-default. Notice that a single extension is not defaulted to the plain .qmail file, so the final default for any address with an extension is .qmail-default, not .qmail. To prevent funny business, any dots in the address are replaced by colons in the filename, so the .qmail file for fred-fishing.stories is /home/fred/.qmail-fishing:stories.

[1] Well, almost. If the extension contains slashes, the .qmail file will be in a subdirectory of the home directory.

If a .qmail file is empty, qmail uses the default delivery instructions passed to qmail-start at startup time. If there is no plain .qmail file, qmail also uses the default delivery instructions. On the other hand, if .qmail-default doesn't exist, mail to addresses with an extension bounces.

The alias user is handled the same as any other user. This means that mail to unmatched addresses is handled by ~alias/.qmail-address if it exists, otherwise ~alias/.qmail-default. That means you can handle arbitrary addresses by creating .qmail files in ~alias. You can also handle arbitrary addresses by running fastforward from ~alias/.qmail-default, to look up addresses in a sendmail-style /etc/aliases database. I cover that later in this chapter.

10.1.3 Processing the .qmail File

Once qmail has selected a .qmail file, it reads and processes the file one line at a time. The first character on the line determines the type of line:

  • Lines that start with a sharp sign (#) are comments and are ignored.

  • Lines that start with a vertical bar (|) are commands. Qmail hands the command to the shell (/bin/sh, regardless of what your login shell might be) in a known approximation to the recipient's login environment. See Section 10.3 later for more detail on how qmail runs commands.

  • Lines that start with a slash or a dot are mailboxes. The line is the filename of the mailbox. If the line ends with a slash, it's the name of a Maildir mailbox, otherwise it's the name of an mbox mailbox. See Section 10.2 for more details.

  • Lines that start with an ampersand (&) are forwards. The entire line after the ampersand is taken to be an envelope-format address to which the message is to be forwarded, with no comments, decorations, or extra whitespace other than whitespace at the end of the line, which is ignored. That is, if you want to forward your message to sarah@example.com, this line is correct:

    &sarah@example.com

    and these are all wrong:

    &sarah@example.com (Sarah Bande) &Sarah Nade <sarah@example.com> &sarah (Sarah Pheem) @example.com &sarah @ example.com

    If you want to forward to more than one address, put each address on a separate line. If you want to forward to addresses computed on the fly, use the forward program in a command line.

  • Lines that start with a letter or digit are also taken to be forwarding addresses, as though they were preceded by an ampersand. Again, the entire line is taken to be an envelope-format address, with no comments or decorations.

  • Completely blank lines are ignored, except at the beginning of a .qmail file where a blank line is an error.

A .qmail file can have any combination of these kinds of lines. The lines are interpreted one at a time. Command and mailbox lines are interpreted in sequence. (Maildir and mbox deliveries are handled by internal routines in qmail-local that return exit codes like commands do to indicate whether the delivery was successful.) If a command exits with a failure code (anything other than 0 or 99), the delivery failed and qmail-local stops immediately. If a command exits with code 99, the command is considered to have succeeded, but the rest of the .qmail file is ignored. If a command exits with code 100, the failure is permanent and the message bounces. If with code 111, the failure is temporary and qmail will retry the delivery (the entire .qmail file, not just the command that failed) later. For historical reasons, exit codes 64, 65, 70, 76, 77, 78, and 112 are also considered permanent failures, any other nonzero exit code is temporary failure, but for compatibility with future versions of qmail, programs should only return 0 for success, 99 for success and skip the rest of the file, 100 for permanent failure, or 111 for temporary failure.

If you want qmail to continue interpreting a .qmail file if a command fails, the qmail documentation suggests putting each command in a separate .qmail-whatever file and having the main .qmail file forward the mail to the subaddresses corresponding to each of those files. A much easier approach is to just force the exit code of each command line to zero:

| somecommand ; exit 0

The cabalistically inclined can abbreviate to:

| somecommand ;:

Forward lines are noted but not acted on until all of the lines in the .qmail have been interpreted. At the end of the file, if there were any forward lines and no command or mailbox line has failed, qmail-local calls qmail-queue to requeue the message to the forwarding addresses. If a command or mailbox delivery fails, qmail-local does no forwards, even if the forward lines preceded the failing delivery line in the .qmail file.

10.1.4 Defensive Features in qmail-local

Mail deliveries can be fouled up in a remarkable number of ways. qmail-local has several features intended to prevent mail foul-ups, or to limit the damage when a foul-up occurs:

  • Every time qmail-local forwards a message or delivers it to a mailbox, it places a Delivered-To: line at the front of the message. (The Delivered-To: line is available to program deliveries as the DTLINE environment variable for programs that remail the message.) If a message already has a Delivered-To: line with the exact same address as the current delivery, qmail-local won't deliver the message and fails permanently. This prevents mail loops in which a circular chain of forwarding addresses keeps forwarding a message along forever.

  • If the home directory in which the .qmail file resides is world-writable or the .qmail file itself is world-writable, qmail-local won't deliver the message and fails permanently, on the theory that the .qmail file might have been tampered with by someone other than the intended user.

  • If the sticky bit is set on the home directory, qmail-local fails temporarily. Qmail uses that bit as a flag that the user is editing .qmail files. This allows a user to set the sticky bit, edit .qmail files, then turn off the sticky bit, to be sure that qmail won't attempt to interpret a partially edited or partially rewritten file before the edits are done.

  • If the first line of a .qmail file is blank, qmail-local fails temporarily. It's not clear to me what problem this solves. Blank lines elsewhere in the file are ignored.

  • If the execute bit is set on a .qmail file, the file should contain only forward lines, and mailbox or command lines will fail. This helps make mailing lists more secure, so even if a bad guy sneaks an address onto a list that looks like a mailbox or command, it won't do any damage. If a .qmail file contains a +list line, subsequent lines in the file must be forwards, which makes it possible to use mailing list files with a few commands at the front to validate the message or reset bounce counters. (The +list feature is undocumented.)



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