Setting up the transport agent is perhaps the most crucial mail-related job presented to the system administrator. There are a variety of transport agents available on Unix systems, but sendmail is by far the most widely used. According to current estimates, sendmail handles over 75% of all Internet mail traffic (Unix and non-Unix alike). Other transport agents used on Unix systems include Postfix, smail, qmail, and exim. We will consider sendmail and Postfix here. 9.4.1 sendmailEric Allman's sendmail package is a very powerful facility, capable of handling email from the moment a user submits a message from a mailer program, transporting it across a LAN or the Internet to the proper destination system, and then finally handing it off to the delivery agent, which actually places the message in the user's mailbox. In fact, because the package includes a delivery agent program, the facility as a whole can handle every aspect of electronic mail except composing and reading messages and retrieving them from message stores. sendmail is also a well-proven facility, and, at this point, is quite secure, provided that it is configured properly.
sendmail is available from http://www.sendmail.org; see also http://www.sendmail.net, which is Sendmail, Inc.'s site for the free version. For information about commercial sendmail products, see http://www.sendmail.com. The current sendmail version series is 8.12.3 (circa April, 2002). sendmail's major version number 8 refers to the extensive rewrite of sendmail done in 1993 by its author, Eric Allman. The other numbers are revisions within that series.[8] Unfortunately, vendor-included versions of sendmail tend to lag behind the current version to varying degrees, with free operating systems remaining closest to the current version and commercial operating systems quite a bit further behind. (At the moment, sendmail versions included with commercial operating systems range from 8.8 to 8.10 for the Unix flavors we are considering.)
You can identify which version of sendmail is running on a system by running the following command: $ echo | sendmail -bt -d0 Version 8.11.3 Compiled with: LDAPMAP MAP_REGEX LOG MATCHGECOS MIME7TO8 MIME8TO7 NAMED_BIND NETINET NETUNIX NEWDB NIS QUEUE SASL SCANF SMTP USERDB ============ SYSTEM IDENTITY (after readcf) ============ (short domain name) $w = poffice (canonical domain name) $j = poffice.ahania.com (subdomain name) $m = ahania.com (node name) $k = poffice.ahania.com ======================================================== ADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> This sendmail command runs the facility in its interactive address-testing mode, with some additional debugging output enabled; in this case, the input is taken from standard input, which is null, thereby terminating the session after the initial messages are displayed (/dev/null could also be used as the input source). The resulting output indicates the sendmail version information and the set of compilation options with which it was built. For example, this version includes support for interfacing with an LDAP database (indicated by the first keyword in the list). The second section of the output displays information about the local system and its DNS domain environment. The final lines pertain to email address translation and can thus be ignored here. If you want to find out the sendmail version running on a remote system, telnet to port 25 (specified as telnet's second parameter): $ telnet pauling 25 Trying 192.168.9.220... Connected to pauling. Escape character is `^]'. 220 pauling ESMTP Sendmail 8.11.0/8.11.0; Sun, 4 Mar 2001 ... ^] telnet> quit Taking the last couple of years as the norm, upgrades to sendmail appear very frequently every 2-3 months, barring major bugs or security holes. Ideally, hosts that relay mail into and out of your site should be kept up-to-date with the latest version of sendmail since these are your most vulnerable security points. Other hosts, which usually rely on a central mail server for mail transport, can probably make do with the version that came with the operating system (unless a major security problem is discovered). In any case, check security sites and mailing lists (as well as the sendmail home page) regularly for notices of newly discovered sendmail vulnerabilities and appropriate fixes. The sendmail facility consists of many components: the sendmail daemon, some related commands and programs, several configuration files and databases, and configuration-file building tools. These files will be located in standard locations only if you install sendmail yourself from source code. Table 9-3 lists sendmail's major components, along with their directory locations for the various Unix operating systems.
sendmail's functioning is controlled by the sendmail daemon, and all the other components work under its direction. The daemon is generally started at boot time with a command like the following: sendmail -bd -q30m This command runs sendmail as a background daemon and checks its work queue every 30 minutes. In boot scripts, starting the daemon is generally preceded by commands that remove lingering junk files from sendmail's queue directory. On systems with System V-style boot scripts, you can start or restart the sendmail daemon with a command like this one: # /sbin/init.d/sendmail restart See Table 9-3 to determine the configuration file location on your system. On AIX systems, you use these commands to direct the System Resource Controller to start or restart the daemon: # startsrc -s sendmail # refresh -s sendmail 9.4.1.1 Configuring sendmailPreviously, configuring sendmail was something of a black art; it took a long time to learn how, and even then the process remained at least somewhat mysterious to all but the true gurus. However, since the sendmail configuration process began using the m4 macro preprocessor facility to create sendmail.cf configuration files, the job has become much, much easier. The discussion that follows presents an introduction to sendmail configuration; of necessity, some of sendmail's complexity is glossed over at times. When you create a sendmail configuration file, you tell sendmail about the specifics of mail submission and delivery on the local computer system. sendmail is highly configurable, allowing you to specify desired behavior in detail and to modify almost any of its default settings. Fortunately, however, these defaults are well-chosen, and configuring sendmail is quite simple for the most commonly used mail scenarios. sendmail's main configuration file, sendmail.cf , is created by running a much simpler source file through the m4 macro processor. To build a custom configuration, you must create this second file, process it, install the resulting file into the proper directory, and notify the daemon to reread it. The configuration file build directory varies for differentLinux distributions (see Table 9-3). The main directory contains a variety of sample configuration source files (their extension is .mc), and you can usually begin a new configuration by copying and then modifying one of them. In their simplest form, these files contain three main types of entries:
As the examples illustrated, character strings specified as macro arguments are enclosed with an initial backquote and a closing single quote: `string' Note the odd quotes. You can find information about all of sendmail 's m4-based configuration options in the README file in top-level sendmail.cf build directory (i.e., ../ relative to the directory listed in Table 9-3); this document is titled "Sendmail Configuration Files" and is also available on the sendmail websites. For the goriest of details, consult the book sendmail by Brian Costales with Eric Allman (O'Reilly & Associates). 9.4.1.2 Getting started: A sample mail client configurationThe listing below illustrates the use of these various items within a sendmail source file. This file is used on the client systems of a site that uses a designated mail hub for all nonlocal outgoing mail; in other words, mail submitted on a client system destined for any local system is delivered directly, but all mail destined for systems outside the local domain gets forwarded to the mail hub. This configuration assumes that the aliases file on each system defines the ultimate email destination for all users in the domain. divert(-1) ##################################################### If you modify this file, you will have to regenerate /etc/sendmail.cf (run ./Build) ##################################################### divert(0) VERSIONID(`Config file for Red Hat Linux') OSTYPE(`linux') FEATURE(`smrsh') define(`PROCMAIL_MAILER_PATH',`/usr/bin/procmail') FEATURE(`local_procmail') define(`SMART_HOST',`poffice.ahania.com. ') define(`STATUS_FILE',`/var/log/mail.stats') MAILER(`smtp') MAILER(`procmail') As usual, the source file begins with comments. The first macro in the file, VERSIONID, specifies a version string identifying this particular version of the source file; often, the value of this macro is a source control system ID string,[14] although in our case it is simply a few words of description.
The next macro, OSTYPE , specifies the operating system type of the target system; in this case, Linux is selected. This macro causes another, OS-specific source file to be included within this source file. The various defined ostypes and their associated source files are located in the ../ostype subdirectory (relative to the build directory). You should select and examine the one corresponding to your operating system. Looking at the file is important so that you are aware of predefined defaults set there. The next three macros select two sendmail features: the first FEATURE macro, smrsh, says that sendmail's smrsh program should be used as the shell through which mail is sent to files and programs. The second feature, local_procmail, says to make procmail the default local delivery agent. The intervening line defines the path to the procmail program (the default is /usr/local/bin/procmail). The next two lines use the define macro to indicate the system that is the outgoing mail hub for mail outside the local domain (poffice) and to specify an alternate location for the sendmail status/statistics file (usually /etc/mail/statistics). The final two lines of the file use the MAILER macro to specify that SMTP and procmail local mailers (delivery agents) are in use on this system. Note that the order of items within this file is important. This is the general structure of an .mc source file: VERSIONID OSTYPE DOMAIN Domain-wide configuration file FEATURE define MAILER First "smtp", then "local", then others LOCAL_RULE_* Local rewriting rules (advanced feature) LOCAL_RULESET Thus, FEATUREs generally precede defines. However, if a setting related to a feature is specified in a define macro, that define should precede the corresponding FEATURE. We saw an example of the latter with the local_procmail feature in our example. The DOMAIN macro may be used to specify a domain-wide configuration file holding settings desired on every host (or across a group of hosts), as in this example which selects the generic domain: DOMAIN(`generic') The name specified as its argument is taken as the name of an .m4 file in ../domain relative to the build directory (i.e., ../domain/generic.m4 in this example). Occasionally, you may want to ensure that some feature is disabled. The undefine macro is used in these cases, as in this example, which disables alias expansion: undefine(`ALIAS_FILE') 9.4.1.3 Building sendmail.cfThe Build script in the build subdirectory is used to create a configuration file from a .mc source file. I also tend to be a bit cautious in installing the new file, so I use a process like this: # cd build-dir # emacs test.mc # ./Build test.cf # cp /etc/mail/sendmail.cf /etc/mail/sendmail.cf.save # cp test.cf /etc/mail/sendmail.cf # chmod 444 /etc/mail/sendmail.cf Whenever you change your sendmail configuration, you must send the running daemon a HUP signal: # kill -HUP `head -1 /location /sendmail.pid` The sendmail.pid file stores the process ID of the sendmail daemon (on its first line), along with the command used to initiate it (line two). Some systems do not provide a Build script. In these cases, use one of the following commands (executed in the build directory): # make test.cf # m4 ../m4/cf.m4 test.mc > test.cf The first command is used when there is a Makefile present in the build directory, and the second is the vanilla invocation of the m4 macro processor. In the latter case, the command explicitly prepends the standard sendmail m4 include file to the source file; this step is taken care of for you by the Build script or Makefile. 9.4.1.4 Configuring the mail hubHere is a source file that might be used to build the sendmail.cf file for the mail hub computer system (the initial comment block and VERSIONID and OSTYPE macros have been omitted): FEATURE(`use_cw_file') dnl Send out all mail as user@ahania.com MASQUERADE_AS(`ahania.com') FEATURE(`masquerade_envelope') FEATURE(`allmasquerade') MAILER(`smtp') MAILER(`local') The first feature specifies that an external configuration file will be used to specify a list of hosts and domains for which this system will accept and deliver mail locally (traditionally known as the cw file, after sendmail's internal "class w"). The default file for this purpose is /etc/mail/local-host-names, an ordinary text file containing one name per line. At a minimum, this should contain all the aliases for the local hostname. You will also need to include the local domain within the file in order to support local delivery of addresses of the form user@local-domain (i.e., user@ahania.com, in our example).
The three lines following the comment enablemasquerading on this host. Masquerading presents a single, common source location for all outgoing mail. For example, it can be used to make all email appear to be coming from a single system, regardless of where it was actually submitted. It can also be used to make all local sender addresses conform to a particular form (often user@site), In this case, the MASQUERADE_AS macro causes all mail leaving the site to appear to be coming from the user at ahania.com, and all references to any local computer are removed. The masquerade_envelope feature causes masquerading to occur within the message's envelope[15] as well as the standard mail headers, and allmasquerade says to masquerade recipient names as well as sender names (the latter is useful when the recipient list includes both local and nonlocal people).
A related feature is always_add_domain, which appends the local domain to unqualified usernames (although many mailers also do this). It also respects the setting of MASQUERADE_AS. Including this feature is virtually always safe. If you decide to use masquerading, you may want to exclude some usernames from the translation process. This is the purpose of the EXPOSED_USER macro. For example, the following macro excludes root from masquerading: EXPOSED_USER(`root') Other system-related mail addresses should also be so excluded, including Mailer-Daemon, postmaster, and so on. We will consider additional masquerading-related features in Section 9.4.1.8 later in this chapter. 9.4.1.5 Selecting mailersThe final two lines of the example mail hub configuration file the MAILER macros activate various delivery agents: in this case, SMTP and the default local delivery agent. sendmail has many defined mailers, including the following:
Once again, order matters among the selected mailers. You will be safe if you place smtp first, follow it with local, and then list any other mailers. Note that the mailers local and procmail are made equivalent when you include FEATURE(`local_procmail').
Each of these defined mailers has some associated parameters that can be defined, including mailer_MAILER_PATH and mailer_MAILER_ARGS, which specify the executable path and desired command arguments, respectively (where mailer is replaced by the uppercase mailer name). We'll look at an example in a bit. The program used for local mail delivery MAILER(local) varies quite a bit from Unix version to version:
In general, you can determine the default local mailer by running a command like the following (the location of the configuration file will vary): $ grep Mlocal /etc/sendmail.cf Mlocal, P=/usr/bin/procmail, ... The path following "P=" indicates the local delivery agent. There are many delivery agents in use on Unix systems: mail, rmail, deliver, mail.local (part of the sendmail package), procmail, and uux with rmail (for UUCP-transported mail). The default local delivery agent is /bin/mail for mail messages and /bin/sh for mail messages piped to files or programs. You can override these programs and/or locations with define macros such as these: define(`LOCAL_MAILER_PATH', `/usr/bin/rmail') define(`LOCAL_MAILER_ARGS', `rmail -d $u') define(`LOCAL_SHELL_PATH', `/usr/bin/sh') define(`LOCAL_SHELL_ARGS',`sh -c $u') These entries define the local delivery agent to be /usr/bin/rmail and specify an alternate location for the shell. The _ARGS parameters specify the command to run in each case: rmail will use the -d option followed by the delivery address ($u, which resolves to the appropriate username), and piped email will be processed with sh -c address (where $u will again expand to the delivery address in this case, the command specified as the alias translation). If you want to use sendmail's mail.local program as the local delivery agent, you can simply include this macro in your configuration source file: FEATURE(`local_lmtp',`path-to-mail.local') The second argument is optional and defaults to /usr/libexec/mail.local.[16]
As with the local delivery agent, you can determine which program is used for piped mail messages using a command such as grep Mprog /etc/sendmail.cf. Since piped email is a traditional security hole, many administrators choose to replace sh with a more restricted shell. The smrsh shell included with sendmail fits the bill nicely (it's pronounced "smursh," but it stands for "sendmail restricted shell"). As we've seen, smrsh may be selected using the following FEATURE macro: FEATURE(`smrsh',`path') The second argument is again optional and defaults to /usr/libexec/smrsh. Like other restricted shells (see Chapter 7), smrsh ignores all I/O redirection within commands, strips all initial paths from command names, and restricts allowable commands to those stored in its executables directory, usually /usr/lib/sendmail.d/bin. The administrator then places permitted (safe) commands (e.g., vacation) in that directory, usually via symbolic links, taking care to exclude unsafe commands, such as shells (other than smrsh itself), command interpreters (e.g., Perl, Python), and programs offering shell escapes. Neither the directory nor the files within it should be group- or world-writable.
9.4.1.5.1 More about pipes to files and programsNormally, pipes to files can be made to ordinary files, devices, and other filesystem entities. You may want to limit them to ordinary files (to prohibit device access and prevent inadvertent errors, such as overwriting directories) by defining confSAFE_FILE_ENV : define(`confSAFE_FILE_ENV',`/') If you further want to limit the allowed locations for writes to files, specify the root of the desired directory as the second parameter. For example, the following entry restricts such writes to files under /home: define(`confSAFE_FILE_ENV',`/home') Finally, you can disable mail message relaying to files and programs by removing the / and | characters from the list of flags given to the local mailer: MODIFY_MAILER_FLAGS(`LOCAL',`-|/') 9.4.1.6 Some client and mail hub variationsIn this section, we look briefly at a potpourri of additional features related to general client or hub configuration. 9.4.1.6.1 An isolated internal networkA non-Internet-connected LAN can easily rely on a single host to serve as its conduit to the outside world. The client systems in such a network use an additional feature: nocanonify . This feature tells sendmail not to expand email addresses to their fully qualified form on the local system. Instead, it will be done on the mail hub. Delaying it until then saves some unnecessary or redundant DNS lookups locally even for hosts with connections to the Internet. Moreover, it is essential to include this feature when clients with limited or no DNS access will be sending messages to arbitrary Internet destinations that they may not be able to resolve. On the mail hub, the relay_entire_domain feature allows that system to accept mail for forwarding from any host in the local domain. Relaying is discussed in more detail when we consider sendmail's anti-spam features later in this section. 9.4.1.6.2 A null clientIt is possible to define an even more minimalclient system than the one we examined earlier. sendmail offers the option of a "null client" system in which all mail is sent to another host for processing. It uses a minimal configuration file, consisting of merely the OSTYPE macro and one FEATURE macro: FEATURE(`nullclient',`poffice') This example specifies the target host the system to which to forward outgoing mail as poffice. This feature also automatically turns off all address aliasing and forwarding features.[17]
If you decide to set up a null client system, you should examine the corresponding operating system-specific include file (in ../ostype) to ensure that no unwanted features are enabled there. In addition, there is no need to run the sendmail daemon on such a client system (user agents will invoke it themselves when necessary). 9.4.1.6.3 Mailer-specific and other local relaysMore complex mail transport schemes can also be implemented in addition to what is provided by the SMART_HOST feature (which specifies a host to handle mail addressed to hosts outside the local domain). For example, different mailers can each have a specified relay host for forwarding mail traffic using the corresponding protocol. For example, the following macro defines oldmail as the relay host for UUCP-based mail: define(`UUCP_RELAY',`oldmail') Mailer-specific relay settings take precedence over SMART_HOST. The MAIL_HUB feature routes all outgoing mail to a specified host, as in this example: define(`MAIL_HUB',`poffice') Alternatively, LOCAL_RELAY can be defined to route unqualified mail addresses to a specific host: define(`LOCAL_RELAY',`poste') LOCAL_USER(`root admin') These macros cause all mail addressed to just a username to be routed to poste for processing, although mail to root and to admin is excepted. The entries in the aliases file are not used for such rerouted addresses.[18]
Here is a summary of the various mail hub specification macros:
9.4.1.7 More addressing optionssendmail supports several ways of implementing aliasing of various sorts, including NIS/NIS+, LDAP, and lookup tables (databases, actually), in addition to the aliases file and forwarding mechanisms. In this section, we consider some of these aliasing methods, along with some related issues. 9.4.1.7.1 Sender aliasingsendmail supports lookup table-based aliasing in addition to the standard mechanisms; the databases used for these lookups are generically known as "maps." The genericstable feature selects map lookup for outgoing sender addresses. You enable it with configuration source file entries like the following: FEATURE(`genericstable',`hash /etc/mail/senders') GENERICS_DOMAIN_FILE(`/etc/mail/local-host-names') The first entry selects the generics table feature and specifies the database as the hash-type Berkeley DB file /etc/mail/senders.db (the argument's syntax is thus db-type path). The default is hash /etc/mail/genericstable. The second macro specifies that the file listing the domains to which the map should be applied is /etc/mail/local-host-names (the same file listing hosts and domains to be considered as local). Alternatively, a different file could be specified, or the GENERICS_DOMAIN macro could be used to list the local domains explicitly. Obviously, the associated database file must also be created. The process for doing so is simple:
So what happens when someone replies to one of these genericized email addresses? The aliasing mechanisms in the local domain need to recognize and translate the address accordingly (e.g., via an aliases file entry) for the mail to be delivered to the proper recipient. You can also use the virtual user table feature for the reverse translations (discussed under Section 9.4.1.8, a little later in this section). A few more points: first, it is often a good idea to include the always_add_domain feature when using a generics table to ensure that all names are fully qualified. Second, the generics_entire_domain feature can be used to apply generics table translation to senders from subdomains of the domains using the feature. Finally, be aware that map translations are not recursive; only a single lookup operation is performed. 9.4.1.7.2 Using LDAP for incoming mail addressesAnother option for address aliasing is to use an LDAP database to store the associated information. Recent versions of sendmail include the capability to issue LDAP queries (provided it is selected at compile-time; check the options for LDAPMAP ). The following configuration source file macros enableLDAP support for our example domain: FEATURE(`ldap_routing')LDAP_ROUTE_DOMAIN(`ahania.com') define(`confLDAP_DEFAULT_SPEC', `-h orwell.ahania.com -b ou=People,dc=ahania,dc=com') The first feature enables LDAP support, and the second macro specifies the domain to which it applies. The final macro specifies the LDAP server and the base distinguished name at which to begin the search (see Chapter 6 for a detailed discussion of LDAP). Once enabled, sendmail uses the following LDAP attributes of the inetLocalMailRecipient object class:[20]
Here are some exampleLDAP records: dn: uid=chavez,ou=People,dc=ahania,dc=com uid: chavez objectClass: posixAccount objectClass: inetLocalMailRecipient mailLocalAddress: rachel_chavez@ahania.com mailRoutingAddress: chavez@dalton.ahania.com dn: uid=nadia,ou=People,dc=ahania,dc=com uid: nadia objectClass: posixAccount objectClass: inetLocalMailRecipient mailLocalAddress: nadia_rega@ahania.com mailRoutingAddress: nrega dn: uid=scarr,ou=People,dc=ahania,dc=com uid: scarr objectClass: posixAccount objectClass: inetLocalMailRecipient mailLocalAddress: steve_carr@ahania.com mailRoutingAddress: scarr@zoas.org mailHost: oldmail.ahania.com (Note that only the relevant attributes are shown; in actual practice, these entries would probably contain additional object classes and their associated attributes.) The first two examples translate generic incoming addresses: a fully qualified address and a (local) alias, respectively. The final example performs a similar translation, this time introducing a different domain in the target address. In addition, the mail will be routed to the host oldmail (as specified in the mailHost attribute). In other words, incoming messages addressed to steve_carr@ahania.com will be routed to host oldmail, which will deliver them to scarr@zoas.org. 9.4.1.7.3 The redirect featuresendmail offers a very convenient way to deal with email that comes to people who have left an organization: its redirect feature. When this is included in the configuration source file, mail addressed to any recipient of the form someone@anywhere.REDIRECT is returned to the sender with the message: 551 User has moved; please try someone@anywhere To use the feature, you must define aliases of the proper form for users who have left. For example, this alias will notify anyone who sends a message to erika that her mail should now go to eps@essadm.com: erika: eps@essadm.com.REDIRECT 9.4.1.8 Virtual hostingWe saw a simple example of address masquerading when we considered the example mail hub configuration earlier. Many times, however, a mail host needs to provide mail services for several distinct domains (often in the context of website hosting). This process is known as virtual hosting, and sendmail provides several features to support it. The most important of these is the virtual user table, which translates incoming addresses according to a map that you set up. Here are some sample configuration file entries using this feature: FEATURE(`virtusertable',`hash /etc/mail/vuser') VIRTUSER_DOMAIN_FILE(`/etc/mail/local-host-names') As you can see, the virtual user table entries are quite similar to those used with the generics table feature. The format of the source file for the virtual user map is: incoming-address desired-local-recipient The entries in this file typically include not only individual user address translations but also blanket transformations of the addresses for entire domains. Here are some examples (assume ahania.com is the local domain): rachel_chavez@ahania.com chavez@dalton.ahania.com erika@ahania.com erikap@mango.essadm.com help@ahania.com error:No such user @essadm.com czarina@essadm.com @zoas.org %1@ahania.com The first two entries translate addresses to different users within the same and a different domain, respectively. The third entry returns an error to the sender for any message addressed to help in the local domain. The final two entries match any address in the specified domain. The entry for essadm.com sends all messages to any user at that domain to the user czarina. The final line maps all addresses of the form user@zoas.com to the same username in the local domain. Note that more complex constructs are possible; see the sendmail documentation for details about the entry syntax. Once again, the makemap command is used to create the database file. For example: # cd /etc/mail; makemap hash vuser < vuser.txt By default, the map is used only for fully qualified addresses in the local domain. The virtuser_entire_domain feature can be used to apply virtual user table translation to addresses referring to subdomains of the associated domain(s).
9.4.1.9 The services switch fileThe order of various name-lookup services is controlled, as usual, by the network services switch file, which is /etc/nsswitch.conf on Linux and Solaris systems (more specifically, it is controlled by the aliases entry). For example, the following entry specifies that the standard aliases file should be used for aliases, followed by any NIS, and then the NIS+ maps: aliases: files nis nisplus For systems not supporting the services switch file, sendmail provides similar functionality via the confSERVICE_SWITCH_FILE setting: define(`confSERVICE_SWITCH_FILE',`/etc/mail/service.switch') The file above selects the usual name and location for this file (although the setting isn't configured at all on many systems). The file has a slightly different format, omitting the colon following the initial keyword: aliases files nis nisplus hosts files dns nis nisplus As this example indicates, the sendmail services switch file can contain entries for both aliases and hosts, providing search orders for mail addresses and hostnames, respectively. See Section 5.2 for more information about the network services switch file. 9.4.1.10 Spam suppressionsendmail offers several features designed for dealing with spam, the electronic equivalent of junk mail.[21] These features can be grouped into four areas:
We will consider the first and third items in more detail in the remainder of this section. For a different approach to detecting and processing spam, see Section 9.6 later in this chapter. 9.4.1.10.1 Message relayingPrior to sendmail Version 8.9, the transport agent operated in a friendly mode, relaying any mail that was presented to it. This is known as "promiscuous relaying." Unfortunately, systems that allow such relaying referred to as "open relays" have been misused by spammers, who send messages through systems that allow relaying, thus disguising or erasing the true origin of the messages. This is a problem for the relay system because the spammers are consuming bandwidth and system resources on the relay host. For example, all of the DNS lookups needed to deliver, say, 10,000 spam email messages are happening on your system rather than theirs. As a result, all relaying is turned off by default in recent sendmail versions. However, sendmail does include options to turn on relaying only as needed, in limited and controlled ways. We've already seen one example of this in the relay_entire_domain feature. Also, when you use the cw file for the domain lists for the generics and/or virtual user tables, you effectively turn on relaying for the included domains. The RELAY_DOMAIN and RELAY_DOMAIN_FILE macros can be used to specify additional domains for relaying. These macros take a domain list and filename (containing the domain list) as arguments, respectively. You can also use the access database to specify allowed relay domains and hosts (see the next section). You may also want to reject mail addressed to nonexistent local addresses. The LUSER_RELAY macro specifies how such messages should be handled. For example: define(`LUSER_RELAY',`tundra.ahania.com') define(`LUSER_RELAY',`local:trashman') define(`LUSER_RELAY',`error:wrong number bozo') The first example reroutes such messages to the host tundra. The second sends them to a local address (via the LOCAL mailer); this address can be an alias pointing anywhere you want. Finally, the third example returns such messages with the indicated error message (which may not be appropriate for use at your site). If you are using limited relaying, the best practice is to undefine the relay settings for mailers you are not using in order to minimize your site's vulnerability to misuse by spammers. For example: undefine(`UUCP_RELAY') and similarly for other unused mailers (e.g., DECNET, BITNET and so on). Some people advise rejecting all mail with any variation of UUCP-style addresses using this macro: FEATURE(`nouucp',`reject') This advice arose from the fact that spammers used to occasionally use such addresses in an attempt to trick sendmail. However, doing this will reject all legitimate email from sites that happen to still use UUCP (and there are more of them than you think). All in all, this feature has no appreciable effect on spam and can block real electronic mail. For this reason, I strongly discourage you from using it. 9.4.1.11 Public blacklists and the access databaseWe now turn to two features related to stopping spam at the incoming mail host, preventing it from ever reaching user mailboxes. The first of these is the ability to reject mail from any site included in one of the public lists of known spammers and open relays: FEATURE(`dnsbl') This feature tells sendmail to check senders against such a list. Such facilities use standard DNS facilities to take advantage of the normally unused IP address 127.0.0.2; the facilities set up an otherwise normal DNS server that returns this address for all sites (IP addresses) in their list. Transport agents can choose to interpret the address as marking a bad site, and sendmail rejects mail from these sites when this feature is enabled.[22]
The default list to check is the Realtime Blackhole List run by the Paul Vixie and coworkers' Mail Abuse Prevention System (MAPS) project (see http://maps.vix.com for more information; the actual server is rbl.maps.vix.com). You can specify a different server to query via the second argument to the macro, and you may include the feature multiple times. MAPS provides other lists as well, as do several other organizations (e.g., theOpen Relay Behaviour-modification System (ORBS); see http://www.orbs.org). There is always a small possibility of rejecting legitimate mail messages using this feature. If this occurs, you can use the access database to make exceptions without disabling the entire feature. You enable use of an access database (map) using the following features: FEATURE(`access_db', `hash /etc/mail/access') FEATURE(`blacklist_recipients') The access_db feature's arguments specify the type and pathname for the database file (as for the generics and virtual user tables); the default file type and location are given in the example. The second feature is optional. The blacklist_recipients feature allows you to include access database entries blocking incoming messages for local mail recipients and hosts. You create the access database file using the makemap command: # cd /etc/mail; makemap hash access < access.txt The entry format for access database entries is the following: item action where item is a username, host, domain, or network, and action is a keyword indicating how to treat email from that source. The available keywords include:
In addition, if a site's entry in the access database specifies mail rejection in any of its variations, outbound mail directed there will also be prohibited. Here are some examples: bad-guys.org REJECT evil-ones.net ERROR:"550 No spam accepted" mole.bad-guys.org OK zoas.org RELAY 10.0.22 RELAY something4nothing@notaol.org DISCARD mybadguy@ REJECT fortress.ahania.com ERROR:"550 No mail allowed" The first two entries reject mail from the specified domains, using the default and specified error message, respectively. Note that error messages that you specify must begin with the 550 error code. The third entry defines an exception to the preceding rejection of mail from the bad-guys.org domain, allowing mail from host mole to get through. The fourth and fifth entries allow relaying of mail originating from the zoas.org domain and any host on the 10.0.22 subnet. The following two entries apply to specific mail accounts, discarding any mail received from sender something4nothing in the notaol.org domain and rejecting incoming mail addressed to mybadguy in the local domain. The final entry rejects mail addressed to anyone on host fortress in the local domain. Note that the last two entries, which apply to local recipients rather than remote senders, require the blacklist_recipients feature in order to be valid. If finer-grained access control is desired, the access database also supports a slightly modified syntax variation allowing separate entries for senders, recipients, and connections at a site. It consists of prepending one of From:, Connect:, and To: to the simpler entry. For example, the following entry rejects mail from the specified address but allows outgoing messages addressed to it: From:spammer@notaol.org REJECT Similarly, the following entries reject mail to and from evil-ones.org but define an exception for one sender and another recipient: From:evil-ones.org REJECT To:evil-ones.org REJECT From:myguy@evil-ones.org OK To:mygal@evil-ones.org OK You can also use the access database to implement unidirectional relaying. For example, this entry relays messages from zoas.org but does not relay messages from other sources to it: Connect:zoas.org RELAY Note that Connect: is used, not From:. Use To: to allow relaying to a specified destination.
The entries in the access database are used by three distinct sendmail message examination phases.[23] Messages are checked first for allowed relaying (based on the client hostname and address), then for an allowed sender, and finally for an allowed recipient. If a message is rejected in one phase, it cannot be restored later. This means that the preceding syntax does not allow for certain kinds of exceptions to be defined. For example, you cannot allow email to a specific user always to get through regardless of its origin, because the local addresses checks are downstream from the message source checks.
However, you can use the delay_checks feature to reverse the order of the three test phases. In this mode, recipient-level access controls have the highest precedence, rather than the lowest. In addition, if you add the friend argument when you invoke the delay_checks feature, you can define local addresses that are exceptions to all access checks, using the following syntax: To:rubbish@ahania.com SPAMFRIEND This entry exempts all mail addressed to rubbish in the local domain from access control tests, causing it to be accepted regardless of its origin. (Thus, "spamfriend" is used to mark recipients who don't mind getting spam.) 9.4.1.12 sendmail securityIn this section, we take up several topics related to sendmail security. We'll begin by considering the ownerships and permissions of the various sendmail-related files and directories, to which I've already alluded several times in the course of this discussion. There are several points to keep in mind:
9.4.1.12.1 The sendmail default userAlthough it is a SETUID root program, the sendmail process always tries to reduce its privilege to the minimum required to perform a task by giving up its root privilege for some other user context appropriate to the task at hand. For example, it takes on the identity of the recipient user when performing certain mail forwarding tasks. The confDEF_USER_ID parameter specifies the user/group combination to use when sendmail wants to reduce its privilege but there is no specific user identity to take on. Here is an example: define(`confDEF_USER_ID',`mailnull:mailngrp') The macro sets the user and group identities that sendmail assumes to the user and group named mailnull and mailngrp, respectively. The mailnull user should be defined with a password file entry like this one: mailnull:***:9947:9947:sendmail default:/not/real:/dev/null The user's home directory should not exist, and no valid login shell should be specified. The password for this account should also be set to an asterisk or other invalid character (either here or in the shadow password file when in use). The group is set up similarly, for example: mailngrp:*:9947: The actual UID and GID do not matter, but this user and group should not own any files or be used for any other purpose. As a result, the nobody user should not be used as the default user. 9.4.1.12.2 Privacy optionssendmail provides a number of options for restricting or eliminating various sensitive tasks via the confPRIVACY_FLAGS parameter: define(`confPRIVACY_FLAGS',`flag-list') The second argument is a comma-separated list of flags that you want to enable. There are several flags you should consider including:
9.4.1.12.3 SASL authenticationThe Simple Authentication and Security Layer ( SASL) provides authentication capabilities to connection-based network communications (for more information, see http://asg.web.cmu.edu/sasl/). SASL authentication can be performed using a variety of mechanisms, and the communications partners can also negotiate a protection method (e.g., encryption) for future messages. A variety of network facilities use SASL, including OpenLDAP and sendmail. Authentication for SMTP connections via SASL is supported starting in sendmail Version 8.10 using the Cyrus SASL facility (http://asg.web.cmu.edu/cyrus/), and Version 8.11 adds support for encryption via TLS (the Transport Layer Security protocol, designed to replace SSL; see http://www.openssl.org). SASL support must be enabled at compile time (check for the SASL option). sendmail provides macros that allow you to specify:
To use these features, you must install the Cyrus SASL library (see http://asg.web.cmu.edu/cyrus/), compile sendmail with SASL support, and then configure it appropriately. For more information, consult the following:
9.4.1.12.4 Reducing the sendmail daemon's privilegesIn the past, the fact that sendmail runs setuid root has been one of the factors allowing for security breaches. As a result, suggestions for reducing thedaemon's privilege level appear frequently. One method for doing so is to use the chroot facility (see Chapter 3). This approach retains the setuid status but limits the daemon's functioning to a minimal, isolated filesystem. Version 8.12 provides a different technique for addressing this issue. It separates sendmail into two daemons, one operating as the transport agent and another operating a mail submission agent that handles mail from mailer programs that require message submission services. Their characteristics are described in Table 9-4.
The binaries for the two files are copies of the same executable with different ownerships and permissions. The sm-mta program is a drop-in replacement for the current sendmail daemon. It requires changing the name of the program in the system startup files and adding the -L sm-mta option to the startup command. For example: /usr/sbin/sm-mta -L sm-mta -bd -q30m The other program is owned by a new user and group and is setgid to that group. Its work queue must be also be owned by this user and group and have the mode 660. It is not run as a daemon and has a separate configuration file, called submit.cf above. The latter includes the msp feature: FEATURE(`msp') The feature enables and sets the various mail submission program-related parameters (e.g., the work queue directory). Check the documentation for the latest version of sendmail for current information about these features. 9.4.1.13 Monitoring ongoing operationsendmail provides several utilities for monitoring its ongoing operation. The most important of these is mailq (equivalent to sendmail -bp), which lists the contents of sendmail's work queue (/var/spool/mqueue): # mailq f3FHZeI08989 1240 Sun Apr 15 13:35 chavez (Deferred: Connection refused by dalton.ahania.com.) jones@dalton.ahania.com This display lists only a single entry. The first line indicates the name of the message file in the work queue directory along with its submission time and sender. The second line in this entry indicates the message status; in this case, the remote host to which the message is addressed is not answering. The final line lists the recipient address. Several different types of files may be present in the work queue directory; all have names consisting of a prefix plus the message ID. The prefix indicates the file content type:
There are a couple of situations in which you may have to deal with the contents of the mail work queue:
You can also examine sendmail operations by looking at the statistics file contents with the mailstats command, a separate utility included in the sendmail package (the statistics file location is set by defining STATUS_FILE and defaults to /etc/mail/statistics). Here is an example of running mailstats: # mailstats Statistics from Sun Apr 8 14:38:37 2001 msgsfr bytes_from msgsto bytes_to msgsrej msgsdis Mailer 53 378K 5 12K 0 0 local 1231 7425K 0 0K 0 0 relay --------------------------------------------------------------- T 1284 7803K 5 12K 0 0 C 1284 5 0 (The first column, which shows mailer numbers, is omitted to save space.) The columns show the number of messages received (msgsfr), sent (msgsto), rejected (msgsrej), and discarded (msgsdis), as well as the number of bytes received (bytes_from) and sent (bytes_to), broken down by mailer. This output is from a system that holds very few user mailboxes, so the local traffic is quite limited. Most messages are relayed to a mail hub for processing. The final two lines in the output show the totals for the each column and the connection totals. Much larger numbers and additional mailers will probably appear in the output from typical systems at your site. sendmail includes the ability to keep track of hosts to which delivery has failed and to use that data to prioritize future work. The following macro enables this feature using the conventional directory location: define(`confHOST_STATUS_DIRECTORY',`/var/spool/mqueue/.hoststat') You can view the current status data using the hoststat command (equivalent to sendmail -bh): # hoststat ---Hostname--------------How long ago----------Results--------- dalton.ahania.com 00:00:30 Deferred: Connection refu newton.ahania.com 01:47:03 250 2.0.0 f32Hl3720131 Me The entries indicate the time and results of the last connection attempt for each host. You can reset all host connection data by issuing the purgestat command (equivalent to sendmail -bH). 9.4.1.14 PerformanceIn this section, we look at some of the parameters that sendmail provides foroptimizing its performance. Mail queues can get very large when a great deal of mail arrives at the same time. The mail queue can get large at other times as well. For example, as we've seen, mail messages are held in the work queue when the first attempt to deliver them fails. This can cause two types of performance bottlenecks. First, disk I/O itself can simply overwhelm its I/O capacity. In addition, very large queue directories suffer from the Unix operating systems' degrading directory-lookup performance (which becomes prohibitive at about 2000 files for typical nonlogged Unix filesystems). One solution to both types of I/O bottlenecks is to use multiple queue directories, ideally each placed on a different physical disk. The following macro configures sendmail to use multiple work queues: define(`QUEUE_DIR',`/var/spool/mqueue/q*') The macro tells sendmail to use all subdirectories with names starting with "q" under the usual directory as its work queues (sendmail picks the queue for each message at random). The directories can be local subdirectories or (better) symbolic links to actual directories on different disks. Multiple queue directories can also allow mail message processing to proceed in parallel across each work location. Files can be moved between queue directories on the same system, because the algorithm used to generate their names is guaranteed not to repeat for 60 years. Here are some additional settings that may be useful in some situations. Most of them define parameters that serve to throttle back the workload when things get overloaded:
9.4.1.15 Debugging techniquesThere are several distinct sources of information that can be useful fordebugging sendmail configurations and operations. See the book sendmail , by Brian Costales with Eric Allman (O'Reilly & Associates), for full information about all of the debugging features discussed in this section. The first of these is the facility'slog file. Here are some sample entries (which we have wrapped to fit the page): Apr 15 12:44:12 kevin sendmail[25907]: f3FGhti25833: to=chavez@newton.ahania.com, ctladdr=jones (133/78), delay=00:00:17, xdelay=00:00:00, mailer= esmtp, pri=210301, relay=newton.ahania.com., dsn=4.0.0, stat=Deferred: Connection refused by newton.ahania.com. Apr 15 12:49:49 kevin sendmail[25927]: f3FGnmd25925: to=ahania@newton.ahania.com, ctladdr=root (0/0), delay=00:00:01, xdelay=00:00:01, mailer=esmtp, pri=30056, relay=newton.ahania.com. [192.168.9.216], dsn=5.1.1, stat=User unknown Apr 15 16:22:35 kevin sendmail[20388]: f36KK5h20388: ruleset=check_mail, arg1=<someone@zoas.org>, relay=IDENT:root@[10.0.19.223], reject=451 4.1.8 <someone@zoas.org>... Domain of sender address someone@zoas.org does not resolve All three of these entries clearly indicate specific mail delivery problems. The first entry indicates that host newton is not currently answering SMTP queries, and so this message from local user jones (UID 133, GID 78) has been sent to the work queue. The second entry indicates that the user ahania is unknown on host newton. Finally, the third entry indicates that the domain name in the sender address cannot be resolved via DNS. You can also use the telnet command to see the results for various senders and recipients by connecting to port 25. In these example, system kevin plays postman for the local domain. In this mode, you enter actualSMTP commands manually. Here is the initial connection command: # telnet kevin 25 Trying 10.0.19.223... Connected to kevin. Escape character is `^]'. 220 kevin.ahania.com ESMTP Sendmail 8.11.0/8.11.0; Mon, 16 Apr 2001 11:22:54 -0400 HELO zebra 250 kevin.ahania.com Hello zebra [10.0.19.184], pleased to meet you (Throughout this output, we've wrapped lines as necessary.) The test session begins by issuing a HELO[25] command, which begins an SMTP session and gives the connecting hostname as its argument. Next, we set up a test mail message by specifying the sender:
MAIL From: luc@bad-guys.org 550 5.7.1 luc@bad-guys.org... Access denied Access from this sender is denied, as specified by the access map. We clear the message state and try another test message: RSET 250 2.0.0 Reset state MAIL From: bill@zoas.org 250 2.1.0 bill@zoas.org... Sender ok RCPT To: mybadguy 550 5.7.1 mybadguy... Access denied The failure this time occurs because the recipient is prohibited by the access map from receiving mail. Here is our next attempt: RSET 250 2.0.0 Reset state MAIL From: bond@mole.bad-guys.org 250 2.1.0 bond@mole.bad-guys.org... Sender ok RCPT To: chavez 250 2.1.5 chavez... Recipient ok DATA 354 Enter mail, end with "." on a line by itself This is a test message. . 250 2.0.0 f3GFOD728166 Message accepted for delivery QUIT 221 2.0.0 kevin.ahania.com closing connection Connection closed by foreign host. The message succeeds, and we enter the message text with the SMTP DATA command (although there is no need to do so if testing the addressing is what we are after). After the message is sent, we end the telnet session. Properly interpreting the output from such test sessions requires a knowledge of the local sendmail configuration. For example, if the local configuration uses the delay_checks feature, then the output of the first attempt would be different: MAIL From: luc@bad-guys.org 250 2.1.0 luc@bad-guys.org... Sender ok RCPT To: chavez 550 5.7.1 chavez... Access denied In this case, the prohibited address seems to pass, and recipient chavez seems to be the problem, but this is simply the result of delaying the sender check until after the recipient check; the "Access denied" message appears after the recipient but applies to the sender. Another useful SMTP command is ETRN, which tells the sendmail daemon to process the queue for the host given as its argument: ETRN zebra.ahania.com 250 2.0.0 Queuing for node zebra.ahania.com started Such commands can be used to retrieve messages manually from a remote source such as an ISP. You can see sendmail perform the SMTP transactions for a message by using its verbose option, -v, as in this example: # sendmail -v chavez@ahania.com < /dev/null sendmail's verify mode (-bv) can be used to verify a recipient address, as in this example, which checks the address chavez: # sendmail -bv chavez chavez@newton.ahania.com... deliverable: mailer relay, host kevin, user chavez@newton.ahania.com The output indicates that the address is deliverable: it will be relayed to user chavez on host newton in the local domain via relay system kevin. Another useful sendmail feature is itsaddress translation mode (-bt). Traditionally, this mode was used to verify and debug the complex address rewriting rules needed in earlier versions of sendmail, and it can still be used for this task. Over the years, however, many other useful internal commands have been added. Several useful ones are illustrated in the following annotated session: # sendmail -bt ADDRESS TEST MODE (ruleset 3 NOT automatically invoked) Enter <ruleset> <address> > /mx zebra List MX records for host. getmxrr(zebra) returns 2 value(s): zebra.ahania.com. bella.ahania.com.ahania.com. > $m Display value of internal variable. ahania.com > $=w Display member of a class (here, local hosts). [192.168.9.220] kevin localhost [127.0.0.1] ahania.com > .Cwsalk Add a member to class w (local hosts): salk. > /map virtuser rachel_chavez@ahania.com map_lookup: Translate an address using the virtual user map. virtuser (rachel_chavez@ahania.com) returns chavez@ahania.com This is the translation (local address). > /try smtp chavez Show address translation for mailer/recipient. Trying envelope recipient address chavez for mailer smtp canonify returns: chavez Output shortened! PseudoToReal returns: chavez MasqSMTP returns: chavez < @ LOCAL > EnvToSMTP returns: chavez < @ kevin . ahania . com . > final returns: chavez @ kevin . ahania . com Rcode = 0, addr = chavez@kevin.ahania.com > /tryflags S The /try command now applies to senders. > /try smtp chavez Show address translation for mailer/sender. Trying envelope sender address chavez for mailer smtp ... Rcode = 0, addr = rachel_chavez@ahania.com > ^D The two /try subcommands indicate that incoming SMTP-transported mail to recipient chavez goes to chavez on host kevin (where is it relayed to its final destination, as we've seen), and that outgoing SMTP-transported messages from user chavez will have rachel_chavez@ahania.com as the sender (the same information was also given by the earlier /map subcommand). Other useful subcommands include =M, which lists defined mailers, and -dn.m, which turns on the specified debugging level , a topic to which we now turn. sendmail also offers an exhaustive debugging mode, selected with the command's -d option. The option takes a debugging level and optional sublevel as its argument the syntax is -dlevel.sublevel where the level indicates the general area of output information and the sublevel indicates the verbosity level (the default for the latter is 1, the least detailed level). Multiple level specifications can be given, separated by commas. Table 9-5 lists the most useful debugging options. Note that these options appear on normal sendmail commands: most often, sending a test message, but sometimes using -q to process the work queue. In some cases, you need to include -v to make the debugging output appear.
Here is an example displaying the delivery process for local recipient trucks: # sendmail -v -d11.2 trucks < /dev/null trucks... aliased to trucks@zebra.ahania.com openmailer: procmail -Y -a -d trucks trucks... Connecting to local... openmailer: openmailer: running as r/euid=371/0, r/egid=0/0 MCI@80efaf0: flags=2<TEMP>, errno=0, herrno=0, exitstat=0, state=2, pid=13143, maxsize=0, phase=NULL, mailer=local, status=NULL, rstatus=NULL, host=NULL, lastuse=Wed Dec 31 19:00:00 1969 trucks... Sent giveresponse: status=0, dsn=2.0.0, e->e_message=<NULL> Here we see that the local mailer is procmail, as well as a great deal of information about the process that delivers the mail. Similarly, the following command shows the alias translation process for user lilith on host dalton (output is shortened): # /usr/sbin/sendmail -d27 lilith < /dev/null alias(lilith) lilith (, lilith) aliased to ldonna alias(ldonna) ldonna (, ldonna) aliased to lcapri alias(lcapri) lcapri (, lcapri) aliased to lmc2499@dalton.ahania.com forward(lmc2499) alias(lil) lil (, lil) aliased to lil@garden.ahania.com This output traces a somewhat lengthy chain of aliases that ultimately translates lilith to lil@garden.ahania.com. 9.4.1.16 Macro summaryWe will end our consideration of sendmail with Table 9-6, which lists all the macros we have discussed in this section (ordered alphabetically by the name of the most significant component).
9.4.2 PostfixPostfix is an alternative mail transport agent that has received quite a bit of attention in the past couple of years. It is the work of WietseVenema; he wrote the initial version while spending a sabbatical year atIBM's Thomas J. Watson Research Center (where the program was named VMailer). The first production-quality version of Postfix was released in 1999, and it is still a work in progress. The package's home page is http://www.postfix.org.
Postfix was designed as a sendmail replacement with several goals in mind:
Figure 9-6 illustrates the basic Postfix mail transport process. As it indicates, the package's design is modular, separating the various processes from each other and allowing you to easily disable features you don't need to use. In the diagram, each of the rounded rectangles represents a daemon. The shaded rectangles indicate the message-flow path through the facility, and the white rectangles provide specific auxiliary services. Figure 9-6. Postfix mail processingThe left part of the diagram depicts howPostfix receives incoming mail. Mail created on the local system is handled by a component named sendmail, which sends it to the maildrop queue to await processing. This queue is processed by the pickup daemon, which feeds messages to the cleanup daemon. Incoming mail from outside sources is handled by the smtpd daemon, which similarly sends it to the cleanup daemon. The cleanup daemon prepares messages for delivery, adding any required headers, optionally transforming addresses, bouncing invalid and acceptable messages, and so on. The rewrite (address rewriting) and bounce daemons aid in these processes. When finished, cleanup sends the message to the incoming queue to await delivery (packaged as a single file). With the incoming queue, the Postfix delivery process begins. The queue manager process (qmgr) oversees and controls the delivery process. Jobs from the incoming queue are moved to the active queue and then either delivered or sent to the deferred queue. Whenever space opens up in the active queue, one job each is moved from incoming and deferred. Jobs waiting in the deferred queue are scheduled via an "exponential backup" algorithm: each delivery failure results in a longer wait period before the next attempt. Within the active queue, jobs are selected using a round-robin selection method based on their final destination (to prevent any one site from consuming a disproportionate share of resources). An unreachable destination list is maintained and used to optimize the selection process. The bounce and resolve daemons aid the queue manager in its work. Ultimately, qmgr hands messages off to a delivery agent. Two of these are illustrated in the figure: local, which places messages in local user mailboxes, and smtp, which typically routes outgoing messages to the Internet. A few pieces of the package are not shown in the diagram. The most important of these is the masterdaemon, which serves as the supervisor for the entire facility and is the only daemon that is always running. In addition, there are two other mailers: the error mailer for creating and handling mail resulting from errors, and the pipe mailer, which handles mail destined for other transport protocols (currentlyUUCP). Table 9-7 lists the standard locations for the various Postfixcomponents.
In addition to the daemons, the Postfix facility includes several administrative utilities. The most important of these are postfix (used to start and stop the facility and similar actions) and postmap (createsPostfix lookup maps). We will see examples of their use later in this section. Other commands include:
Finally, Postfix configuration files reside in /etc/postfix. The only exception to this is the aliases file, which is typically located in /etc. 9.4.2.1 Installing PostfixInstalling Postfix is not difficult, but it does require some care. It is possible to use both Postfix and sendmail on the same system, and the procedures for doing so are discussed in the INSTALL file in the Postfix source distribution. In this discussion, we will assume that Postfix is replacing sendmail. These are the steps required to installPostfix:
I recommend trying this process for the first time on a test system, rather than your central mail hub! 9.4.2.2 Configuring PostfixPostfix configuration files reside in the /etc/postfix directory. This location is assumed in the discussion that follows. Postfix's primary configuration file is main.cf. The Postfix package includes a sample version of main.cf, which describes most of its possible entries. The package also provides a number of smaller sample files illustrating features related to a single purpose (named sample-*.cf). The main.cf file often begins with entries specifying the package's file and directory locations. These sample entries list the default settings:[28]
config_directory = /etc/postfix queue_directory = /var/spool/postfix daemon_directory = /usr/libexec/postfix command_directory = /usr/sbin These entries also illustrate the general entry format: setting = value. When value is a list, the individual items are separated with spaces and optional commas. Entries in the configuration file may continue onto as many lines as needed by beginning the second and subsequent lines with whitespace. There are several related settings you should be aware of (but for which the default values are often correct): myhostname = garden.ahania.com mydomain = ahania.com mydestination = $myhostname, localhost.$mydomain These entries specify the local hostname, the local domain (defaults to the domain part of myhostname), and a list of destinations that should be considered local (the local host), respectively. Note that parameter settings may be used in other entries by preceding the parameter name with a dollar sign.
9.4.2.2.1 Notifying the daemonWhenever you modify the Postfix configuration, you will need to notify the master daemon with this command: # postfix reload This command tells the process to reread its configuration files. 9.4.2.2.2 Client systemsNext, we consider some settings relevant to mailclient systems. For a minimal client configuration, only two additional entries are needed: relayhost = poffice.ahania.com mynetworks_class = host The first entry specifies a destination for all nonlocal mail, and the second prevents Postfix from relaying mail for any computer except the local host. You can also specify a host to handle all unknown local users. This example redirects mail for unknown local users to the same user on system poffice: luser_relay = $user@poffice.ahania.com Finally, if you want to define a null client system, which forwards even seemingly local mail to a mail server, define a relayhost and comment out the entries for smtp unix and local unix in the master.cf configuration file. 9.4.2.2.3 The mail hubThe configuration file on the mail hub typically has some additional entries. Here are some annotated examples: # add the domain to list of local destinations mydestination = $myhostname, localhost.$mydomain, $mydomain # relay mail from these origins: any host in the domain relay_domains = $mydestination, $mydomain In both cases, mydomain is added to the parameter's default list. In agreement with current security recommendations, relaying is disabled by default in Postfix. By default, Postfixrelays mail for all hosts in the domains listed in relay_domains. It also relays for hosts from any subnet the local host trusts, as defined by the mynetworks parameter: mynetworks = 10.0.19.0/24, 10.0.13.0/24, 127.0.0.0/8 In this case, Postfix will trust any host on the 10.0.19 and 10.0.13 subnets, as well as the local host. It is important to specify the setting for mynetworks correctly. It should consist of only trusted local subnets (and not the entire class A, B, or C address).[29] If this parameter is not explicitly defined, the list defaults to the local subnet and 127.0.0.0.
Postfix can also automatically rewrite all local sender addresses on outgoing mail to the user@domain form by including these entries: masquerade_domains = $mydomain masquerade_exceptions = root, postmaster The first entry sets the domain used for addressmasquerading, and the second entry lists users whose addresses should be excluded from the operation 9.4.2.2.4 The local delivery agentBy default, Postfix uses its own local daemon for local mail delivery. You can specify a different program with the mailbox_command parameter. For example, this entry makes procmail the local delivery agent: mailbox_command = /usr/bin/procmail If you choose to use procmail this way, you must define an alias for root, or mail for the superuser will be lost. The mail_spool_directory parameter may be used to specify an alternate directory for user mailboxes, as in this example: mail_spool_directory = /var/newmail 9.4.2.2.5 Systems with intermittent Internet connectionsOn mail hubs having only intermittent Internet connections (for example, via a dialup ISP), you can use these entries to accumulate messages between connections: relayhost = ISP-host Relay external mail to this host. defer_transports = smtp Hold outgoing mail transported via SMTP. disable_dns_lookups = yes Don't perform DNS name resolution tests. The final entry is necessary to avoid mail being rejected because of name resolution failures. It may be used on any system that lacks external DNS lookup capabilities. Postfix also includes a feature designed to optimize the process of delivering mail to an intermittently connected site; the daemon that provides this functionality is known as the flush daemon. It is configured via the fast_flush_domains parameter: fast_flush_domains = $relay_domains This entry causes fast flush service to be used for all domains for which this server relays mail. When the connection to one of these locations is made,[30] this service causes Postfix to attempt to deliver only the mail destined for that specified destination rather than flushing the entire queue. Obviously, this is much more efficient for both the client and the mail server.
9.4.2.2.6 Address transformationsPostfix can perform a variety ofaddress-transformation operations on sender and recipient addresses. The simplest of these is to append the local domain to nonqualified outgoing sender addresses, using the myorigin parameter: myorigin = $mydomain This entry is often included on both the mail hub and client systems. Like sendmail, Postfix can use binary lookup tables called maps to perform various sorts of address translations and for other purposes, such as access control. Maps are created from a text source file with the postmap command. Outgoing mail address mapping e.g., to a standard form like first.last@domain is done via the canonical map, which is specified via this configuration file entry: canonical_maps = hash:/etc/postfix/canonical.db This example specifies that the file canonical.db in the Postfix configuration directory should be used as the canonical address map, and that the file is a hash-type database. Here are some example entries from the map's source file: chavez rachel_chavez@ahania.com carr steve_carr@zoas.org ewood eve_wood@ahania.com When this map is used, the sender name in the left column is translated to the form given in the right column. The following command may be used to create the canonical.db map from a source file named canonical: # postmap hash:canonical The hash: prefix specifies the database type (a hash is the default, so the prefix is actually optional here). Use the postconf -m command to list the database types supported on your system; the list of possibilities includes hash, dbm, and btree. The default canonical map is applied to both senders and recipients within the message and the envelope. Alternatively, you can specify a map used only for sender addresses or recipient addresses via these configuration file parameters: sender_canonical_maps = hash:/etc/postfix/sender_canonical recipient_canonical_maps = hash:/etc/postfix/recipient_canonical These maps are applied before the general canonical map when it is also enabled. NOTE
Postfix can similarly perform map lookup-based transformations on incoming recipient addresses using its virtual map (discussed later in this section). Postfix also offers a map for generating mail messages indicating the new address for departed users. This is called the relocated map. Here are the associated configuration file entries: relocated_maps = hash:/etc/postfix/relocated local_recipient_maps = $relocated_maps, $alias_maps, unix:passwd.byname The first entry specifies the type and file location for the map file, as usual. The second entry adds the relocated map to the front of the list of items to use for looking up incoming mail recipients. In this case, the relocated map is checked first, followed by the aliases database and the password file. Entries in the relocated map consist of the local username and the new email address. Here is an example: erika eps@essadm.com 9.4.2.2.7 Virtual domainsPostfix can be configured to support virtual domains, using its virtual map facility. Here is an exampleconfiguration file entry enabling this feature using the virtual.db map file: virtual_maps = hash:/etc/postfix/virtual The map file performs two functions: enabling virtual domain support for listed domains and specifying incoming recipient address translations. Here are some example entries from the virtual map source file (assume the local domain is ahania.com): zoas.org whatever essadm.com whatever webmaster@essadm.com czarina@lecarre.ahania.com smith@zoas.org hayes@oldwest.ahania.com jones@zoas.org kidcurry@oldwest.ahania.com @zoas.org @ahania.com rachel_chavez@ahania.com chavez@dalton.ahania.com The first two entries enable virtual hosting for the zoas.org and essadm.com domains; the text in the second column for such entries is ignored. The third entry redirects mail for webmaster@essadm.com to a specific local user. The fourth and fifth entries specify local recipients for users smith and jones at zoas.org. The sixth entry, for @zoas.org, will be used for any other recipient in that domain; in this case, mail will be redirected to the same user in ahania.com, the local domain. The final entry illustrates that this map may also be used for general incoming recipient address translation unrelated to virtual hosting, in this case translating the address rachel_chavez@ahania.com to the appropriate, fully qualified recipient address. As usual, the virtual map database is created with postmap. For example, this command would create the hash-type database virtual.db from the source file virtual: # postmap virtual Postfix handles virtual domains somewhat differently than sendmail users may be used to. In particular, usernames that exist in the local domain are not recognized in virtual domains by default. In other words, if chavez is a user in ahania.com, essadm.com is a hosted virtual domain, and there is no virtual map entry for chavez@essadm.com, mail to that address will bounce. In contrast, sendmail-style virtual domains attempt to deliver such mail to chavez@ahania.com (bouncing it when no identically named user exists). You can implement sendmail-stylevirtual domains by making two modifications to the Postfix configuration:
9.4.2.2.8 LDAP lookupsPostfix can also be configured to useLDAP for local recipient address translations. This capability must be selected at compile time. You can determine whether your installation supports it via the postconf -m command. Here are some example configuration file entries: alias_maps = hash:/etc/aliases, ldap:ldapsource ldapaliases_server_host = orwell.ahania.com ldapaliases_search_base = dc=ahania,dc=com ldapaliases_query_filter = (mailacceptinggeneralid=%s) ldapaliases_result_attribute = maildrop The first entry adds LDAP the list of items to use for address translation, checking it after the aliases file. The remaining entries specify the LDAP server to connect to, the root of the tree to search, the query that should be run, and the record field to return to Postfix (respectively). In this case, the LDAP database is queried by searching the mailacceptinggeneralid field for the address; the contents of the maildrop field from matching record(s) are used as the new address. Here is a sample LDAP entry using these default attributes: dn: cn=some-object, dc=ahania, dc=com ... mailacceptinggeneralid: help@zoas.org mailacceptinggeneralid: oliviav@essadm.com maildrop: vargas@dalton.ahania.com This example illustrates the use of multiple key fields, any of which will translate to the local mail address vargas@dalton.ahania.com. Of course, you can use any object type, key field, and return field that makes sense in the context of the local LDAP schema. 9.4.2.3 Access control and spam suppressionPostfix includes an access control facility that can be used for both security-related and spam-suppression purposes. Postfix allows you to specify incoming mail restrictions based on the connecting system (the "client"), the sender, and/or the recipient, via the smtpd_client_restrictions, smtpd_sender_restrictions, and smtpd_recipient_restrictions configuration file entries, respectively. It also provides the smtpd_helo_restrictions and smtpd_etrn_restrictions parameters for specifying restrictions for hosts attempting to use the SMTP HELO/EHLO commands (to initiate an SMTP session) and the SMTP ETRN command (to request that pending mail be transferred). The setting for any of these parameters is a list of items, which can include Postfix keywords and/or a type:file specification for an external map. The most important keywords are listed in Table 9-8.
Here are some examples, which also introduce a couple more related parameters: smtpd_sender_restrictions: hash:/etc/postfix/senders, reject_non_fqdn_sender, reject_unknown_client reject_unknown_sender_domain, reject_unauth_destination, reject_unauth_pipelining, reject_maps_rbl maps_rbl_domains = blackholes.mail-abuse.org, rbl.maps.vix.com smtpd_recipient_restrictions: hash:/etc/postfix/no-mail, permit smtpd_helo_restrictions = reject_maps_rbl, reject_invalid_hostname smtpd_helo_required = yes smtpd_etrn_restrictions = permit_mynetworks This configuration is fairly restrictive. Messages from unknown clients and unknown senders are rejected, as are ones from or sent by blacklisted domains (lines 1-3), defined as the two sites in the second entry (line 4). Likewise, messages to nonlocal destinations are also rejected (line 2). Senders (line 1) and recipients (line 6) are checked against access maps. Recipients are accepted provided they pass all the restrictions in the access map (line 5). Blacklisted sites are not allowed to connect to this server, and connections using malformed SMTP HELO/EHLO commands are also rejected (line 6), although this command is required for a successful connection (line 7). Finally, only systems in the local networks may use the SMTP ETRN command to retrieve their mail (line 8). The recipients entry illustrates the use of the generic permit keyword, which simply makes the entry's effect evident; in other words, all lines end with an implicit permit unless you include an explicit reject. When access is determined, list items are applied in order. Access map source files consist of user and/or domain names, followed by the desired action. At the moment, actions consist of rejection, specifiable in two forms (as illustrated in the examples below), acceptance, and any of the restriction keywords. Here is an example that might be part of a sender access map: bad-guys.org REJECT evil-ones.net 550 No spam allowed. zoas.org OK mybadguy@ permit_mynetworks These entries reject all mail from anyone at bad-guys.org and evil-ones.net (using the indicated error code and message in the latter case). Mail from zoas.org is accepted. When a user named mybadguy sends a message, it is rejected unless the client system is a member of one of the local networks. You create the binary form of the map using the postmap command as usual: # cd /etc/postfix; postmap senders
Postfix also allows you to define "restriction classes": named groups of keywords that can be used within access maps. In fact, if you want to use a reference to an access map within an access map entry, you must do so via a restriction class,[32] as in this example:
main.cf: smtpd_restriction_classes = no_unknown, check_sender, accept_iffy no_unknown = reject_unknown_sender_domain, reject_unknown_client, reject_non_fqdn_sender, reject_non_fqdn_hostname check_sender = check_sender_access hash:/etc/postfix/senders accept_iffy = check_sender_access hash:/etc/postfix/iffy smtpd_recipient_restrictions = /etc/postfix/our-mail /etc/postfix/senders: bad-guys.org REJECT /etc/postfix/iffy: mole@bad-guys.org OK weasel@bad-guys.org OK ferret@bad-guys.org OK bad-guys.org REJECT /etc/postfix/our-mail: chavez@ahania.com OK ahania.com no_unknown essadm.org check_sender zoas.org accept_iffy This configuration defines three restriction classes: non_unknown, which rejects mail from unknown sources; check_sender, which looks up the sender in an access map named senders; and accept_iffy, which looks up the sender in a different access map, iffy. In addition, recipients are checked against the our-mail access map. This setup allows recipients in different local domains to have different checks applied to their incoming mail. These restriction classes are actually applied in the recipients map, our-mail. Messages to chavez are accepted without further checking. Messages to other users in the ahania.com domain are checked for unknown client and sender addresses before being accepted for delivery. Messages to users in the essadm.org domain are rejected if they come from a sender at bad-guys.org (via the sole entry in the senders map). Finally, messages to users in zoas.org are usually rejected if they come from someone at bad-guys.org, but they are accepted from the three bad-guy.org users listed in the iffy map. Postfix can also accept or reject mail based on the contents of either the message headers or body contents, using these configuration file entries: header_checks = regexp:/etc/postfix/header_checks body_checks = regexp:/etc/postfix/body_checks These examples define the pathname for the map used to specify the desired header/body checks. They use a map type of regexp, indicating that the specified file is a regular expression map, another of the supported map types (which may be used for any map file throughout the Postfix facility). The map source file looks like this: /viagra/ REJECT /^Subject: [-A-Z0-9! ]*$/ REJECT /^To: .*@bad-guys.org/ REJECT /[%!@].*[%!@]/ 550 Sender-specified routing rejected This map, designed to be used to check mail message headers, rejects mail that contains "viagra" anywhere in the mail headers, has a subject that contains only uppercase letters, numbers, dashes, exclamation points and spaces, is addressed to any user @garden.ahania.com, or contains explicit routing within the address. In the latter case, the message is restricted and results in the specified error code and message text. As usual, the binary map file must be created from this source file using the postmap command. In addition to this regular expression-based filtering, Postfix also includes full content-filtering hooks (à la procmail). See the FILTER_README file in the top-level directory of the Postfix source tree for details. 9.4.2.4 Postfix securityPostfix is designed to be very secure. In this section, we'll cover various odds and ends related to Postfix security, beginning with these two configuration file parameters: mail_owner = postfix default_privs = nobody These entries specify the owner of the Postfix processes and queue directory and the user identity that Postfix assumes when delivering messages to a file or program and there is no associated user context (respectively). The postfix user account should have a unique UID and group (typically also named postfix). As with any administrative facility, you will need to ensure that the Postfix files and directories have the proper ownerships and permissions. The postfix check command can be used to examine the installation for these problems, and it should be run periodically.
As I've noted before, Postfix gives you two configuration options with respect to the maildrop queue: the queue directory can be world-writable (via chmod o+t), or it can be only group-writable. In the latter case, Postfix uses a SETGID program for local mail submission (owned by the postfix user and group). The non-SETGID configuration is the default. To switch to the second option, you must:
Finally, many administrators choose to run Postfix in a chrooted environment (with /var/spool/postfix serving as the root directory). This is easy to configure, but it is not the default. The examples/chroot-setup subdirectory of the source tree contains example scripts showing the required steps for converting to such a setup for various operating systems. For example, here are the files for a FreeBSD and an AIX system: FreeBSD: umask 022 mkdir /var/spool/postfix/etc chmod 755 /var/spool/postfix/etc cd /etc cp host.conf localtime services resolv.conf /var/spool/postfix/etc AIX: umask 022 mkdir /var/spool/postfix/etc chmod 755 /var/spool/postfix/etc for file in /etc/environment /etc/netsvc.conf /etc/localtime do test -e $file && cp $file /var/spool/postfix/etc done cp /etc/services /etc/resolv.conf /var/spool/postfix/etc mkdir /var/spool/postfix/dev chmod 755 /var/spool/postfix/dev mknod /var/spool/postfix/dev/null c 2 2 chmod 666 /var/spool/postfix/dev/null FreeBSD requires only that a few files from /etc exist in the chroot jail. The script for AIX conditionally copies a list of files (i.e., if they exist), copies two files that it knows it will need, and creates a /dev/null device in the jail (using the mknod command). Note that both scripts are careful to set the umask appropriately and to set the ownership and permissions for any subdirectories they create. 9.4.2.5 Monitoring and performanceAs with any system facility, Postfix requires some amount of ongoingmonitoring and occasional maintenance. In this section, we look at some of the features related to monitoring and performance optimization. We've seen the postfix command several times already. Three of its most important options are start and stop, which start and stop the facility, and flush, which may be used to force processing of the mail queue. These commands may be used to take care of common facility-wide failures and backlogs. Postfix also allows you to configure what sorts of errors should be reported to postmaster: notify_classes = list The item list consists of one or more keywords: bounce (copies message), 2bounce (for double bounces), delay (sends headers only), policy (UCE restriction rejections), protocol (protocol errors), resource (shortages/problems), and software (problems causing failed deliveries). The default list is resource, software. Postfix also provides many resource usage and performance-related settings that can be used to optimize its configuration on your system. The most important of these are listed in Table 9-9.
9.4.2.6 DebuggingThere are three main sources oftroubleshooting information available with Postfix: syslog entries, verbose command modes, and system call tracing. We will consider each of these in turn. Normally, Postfix sends status and error messages to the syslog facility. You can configure the minimum severity level for which you want messages reported in the usual way, using the /etc/syslog.conf configuration file. You can enable verboselogging for the various Postfix daemons by adding the -v option to the command corresponding specifications in /etc/postfix/master.cf (in the final column). For example, this modification enables verbose mode for the smtpd daemon: smtp inet n - n - - smtpd -v The final source of debugging information comes from system call tracing. Be aware, however, that this data is extremely verbose and often obscure. You can enable tracing in this way:
Once the daemon is invoked, system call tracing output goes to the specified file in the /tmp directory. You can examine this file as it runs and use the same command to stop the trace operation when appropriate. It is also possible to run Postfix daemons under a symbolic debugger. See the documentation for details about how to accomplish this. |