7.4 SendmailSendmail is one of the most venerable Internet software packages still in widespread use: it first appeared in 4.1c BSD Unix (April 1983), and to this day, it has remained the most relied-upon application of its kind. But Sendmail has both advantages and disadvantages. 7.4.1 Sendmail Pros and ConsOn the plus side, Sendmail has a huge user community; as a result, it's easy to find both free and commercial support for it, not to mention a wealth of electronic and print publications. It's also stable and predictable, being one of the most mature applications of all time. On the down side, Sendmail has acquired a certain amount of "cruft" (layers of old code) over its long history, resulting in a reputation of being insecure and bloated. Both charges are open to debate, however. While it's true that Sendmail has had a number of significant vulnerabilities over the years, these have been brought to light and fixed very rapidly. An argument can therefore be made that Sendmail security is a glass half-empty/half-full situation. Depending on your viewpoint, Sendmail's various vulnerability reports and subsequent patches may prove that Sendmail is inherently insecure; or perhaps the fact that they come to light and are fixed quickly prove that Sendmail's development team and user community are pretty much on top of things; or maybe you think the truth is somewhere in between. (I'm in this last camp.) A more useful criticism is that Sendmail is monolithic: a vulnerability in one portion of its functionality results in the compromise of the entire application. Since Sendmail must run as root when performing some of its duties, any Sendmail vulnerability has the potential to be used to gain root privileges. As for the "bloatware" charge, it's true that Sendmail has a much larger code base than other MTAs such as Qmail and Postfix, as well as a larger RAM footprint. This probably has at least as much to do with Sendmail's monolithic architecture (one executable provides the great majority of Sendmail's functionality) as it does with cruft. Indeed, Sendmail's code has been scrutinized so closely by so many programmers over the years that it's a little hard to believe that too much unnecessary or blatantly inefficient code has survived intact over the past 20 years. Sendmail is also criticized for its complexity. The syntax of its configuration file, sendmail.cf, is noninstinctive, to say the least. In my opinion, its difficulty ranks somewhere between C and regular expressions. Like them, this is due to Sendmail's power. Regardless, this point is now largely moot: recent versions of Sendmail can be configured via m4 macros, which provide a much less user-hostile experience than editing sendmail.cf directly.
Regardless of one's opinions on Sendmail's cruftiness, it's unquestionably a powerful and well-supported piece of software. If Sendmail's benefits are more compelling to you than the drawbacks, you're in good company. If you additionally take the time to configure and maintain Sendmail with security in mind, you're in better company still. 7.4.2 Sendmail ArchitectureAs I mentioned earlier, Sendmail is monolithic in that it does all its real work with one executable, sendmail. sendmail has two modes of operation: it can be invoked as needed, in which case it will process any queued mail and then quit; or it can be run as a persistent background daemon. " Daemon mode" is required only when Sendmail's role is to receive mail from external hosts; if you just use Sendmail to send mail, you shouldn't run sendmail as a daemon. In fact, you can probably stop reading now since sendmail doesn't really need any customization to do this, unless you wish to run it chrooted (see Section 7.4.6). The way sendmail works, then, depends on how it's being run. If it's running as a daemon (i.e., with the -bd flag), it listens for incoming SMTP connections on TCP port 25 and periodically tries to send out any outbound messages in its queue directory, /var/spool/mqueue. If it's being invoked on the fly, it attempts to deliver the outbound message it's been invoked to send, and/or checks /var/spool/mqueue for other pending outbound messages. Sendmail's configuration files are kept mainly in /etc/mail, with a few files (usually aliases, aliases.db and sendmail.cf) residing one level higher in /etc. /etc/sendmail.cf is its primary configuration file. /etc/mail contains sendmail.mc, which can be used to generate /etc/sendmail.cf. /etc/aliases.db, which is generated from the text file /etc/aliases, contains mappings of username aliases. There's one other main repository of Sendmail files, containing its static m4 scripts (as opposed to the dynamic configuration files in /etc/mail). On Red Hat systems, this repository is /usr/share/sendmail-cf; on SuSE systems, it's /usr/share/sendmail; on Debian GNU/Linux hosts, it's /usr/share/sendmail/sendmail.cf. You shouldn't need to edit these files. That's as much as most of us need to know about how Sendmail is structured. Which is not to discourage you from seeking greater understanding, for which I recommend Costales' and Allman's book sendmail (O'Reilly). 7.4.3 Obtaining and Installing SendmailI can state with absolute certainty that your Linux distribution of choice includes one or more packages for Sendmail. Whether it's presently installed on your system and is an appropriate version for you to use, however, is another matter. If you use an RPM-based distribution (Red Hat, Mandrake, SuSE, etc.), you can see whether Sendmail is installed and its version by issuing the command: rpm -qv sendmail If you use Debian GNU/Linux, you can do the same thing with dpkg: dpkg -s sendmail Note that Red Hat and its derivatives split Sendmail into three packages: sendmail, sendmail-cf, and sendmail-doc. SuSE and Debian, however, each use a single package named sendmail (in their respective package formats). For the remainder of this discussion, I'll assume that you're using Sendmail 8.10.0 or higher unless otherwise noted.
Once you've installed Sendmail, either in the form of a binary package from your distribution or a source-code tarball you've compiled yourself, you've still got a couple of tasks left before you can use sendmail as a daemon. 7.4.3.1 SuSE Sendmail preparationIf you're a SuSE user, become root. Next, open /etc/rc.config with your text editor of choice and set the variable SMTP to yes. This is necessary to activate Sendmail's startup script in /etc/init.d (i.e., for Sendmail to be started at boot time). As part of its SuSEconfig package, SuSE also refers to the file /etc/rc.config.d/sendmail.rc.config for Sendmail configuration. This file is normally adjusted by Yast2's Sendmail configuration applet, or it can be edited manually. If your host is to act only as a simple SMTP server for its local users and not as a relay or gateway for an entire network, sendmail.rc.config provides a fast and simple means for Linux beginners to get started with Sendmail. However, setting up an SMTP relay/gateway is a bit beyond the scope of sendmail.rc.config; furthermore, it doesn't set most of the security-specific Sendmail options we're about to discuss. For any Internet-connected SuSE server that runs Sendmail as a daemon, I instead recommend you configure Sendmail manually (as described later in this chapter). You should first disable the use of sendmail.rc.config by opening it with your editor of choice and setting the variable SENDMAIL_TYPE to no. You can find sendmail.rc.config's full documentation in /etc/mail/README. After editing rc.config and sendmail.rc.config, run SuSEconfig. This will propagate the changes you just made. To actually start the daemon, you can enter the command /etc/init.d/sendmail start, but I recommend you wait until Sendmail is fully configured before doing so. 7.4.3.2 Red Hat Sendmail preparationIf you're a Red Hat user, you need perform only one task prior to configuring Sendmail: edit the file /etc/sysconfig/sendmail so that the variable DAEMON is set to yes. This will tell the startup script /etc/init.d/sendmail to start sendmail as a daemon at boot time. 7.4.3.3 Debian Sendmail preparationIf you've decided to use Debian's official package of Sendmail, you'll get a head start on configuring Sendmail at installation time: the deb package's post-installation script includes an interactive question-and-answer session that leads to the automatic generation of sendmail.cf. Depending on how straightforward your needs are, this may suffice. Even if your configuration requires subsequent fine tuning, you'll probably find Debian's automatically generated configuration to be a convenient starting point. 7.4.4 Configuring Sendmail: OverviewThe easiest way to generate Sendmail configurations is to follow these steps:
Once set up properly, sendmail.mc, mailertable, access, and virtusers won't need to be changed very often, if at all. The most volatile configuration information on any email system is usually user information. Therefore, on Sendmail systems, /etc/aliases is the file that will probably need the most ongoing maintenance. 7.4.5 Configuring sendmail.mcThe first task in setting up an SMTP server is generating /etc/sendmail.cf, for which I strongly suggest you use /etc/mail/sendmail.mc (on SuSE systems, /etc/mail/linux.mc). That's the method I describe here.
The "mc" in sendmail.mc is short for "macro configuration." sendmail.mc isn't a complete macro itself; it consists mainly of parameters, or "directives" in Sendmail's parlance, some of which are passed to macros, while others themselves expand to complete macros. There are several types of macro directive to be aware of, all of which appear in the truncated sendmail.mc listing in Example 7-1. Example 7-1. Excerpt from an /etc/mail/sendmail.mc filedivert(-1) dnl This is a comment line include(`/usr/lib/sendmail-cf/m4/cf.m4') VERSIONID(`Mail server')dnl OSTYPE(`linux') define(`confDEF_USER_ID',``8:12'')dnl define(`confPRIVACY_FLAGS', `authwarnings,needmailhelo,noexpn,novrfy')dnl define(`confSMTP_LOGIN_MSG', ` Sendmail')dnl define(`confSAFE_FILE_ENV', `/var/mailjail')dnl define(`confUNSAFE_GROUP_WRITES')dnl undefine(`UUCP_RELAY')dnl undefine(`BITNET_RELAY')dnl FEATURE(`access_db',`hash -o /etc/mail/access.db')dnl FEATURE(`smrsh',`/usr/sbin/smrsh')dnl FEATURE(`dnsbl')dnl FEATURE(`blacklist_recipients')dnl FEATURE(`mailertable',`hash -o /etc/mail/mailertable.db')dnl FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable.db')dnl FEATURE(`use_cw_file')dnl FEATURE(`masquerade_entire_domain')dnl FEATURE(`masquerade_envelope')dnl FEATURE(`nouucp')dnl MASQUERADE_AS(`hackenbush.com')dnl MASQUERADE_DOMAIN(`.hackenbush.com')dnl EXPOSED_USER(`root')dnl MAILER(smtp)dnl MAILER(procmail)dnl Cwlocalhost.localdomain The first important type of sendmail.mc entry is the comment. Comment lines begin with the string dnl, which is short for "delete through newline." Besides appearing at the beginning of each comment line, dnl can also be used at the end of "real" lines, which prevents unnecessary blank lines from being inserted into /etc/sendmail.cf. The second line in Example 7-1 is a comment line. The next interesting type of sendmail.mc directive is m4 variable definitions, which always begin with the string define or undefine, followed by a variable name and, if applicable, a value to assign to it. The syntax for definitions should be obvious in Example 7-1. Note that the `' marks enclosing variable names and values prevent them from being prematurely expanded by m4. Some variables are Boolean (true or false), but most people don't bother specifying their values: if you cite a Boolean variable in a define directive but omit its value, it defaults to true; citing it in an undefine directive without a value causes it to default to false. Another important kind of directive is the FEATURE. These lines each begin with the string FEATURE, followed by one or more parameters enclosed in directed quotation marks (`'). Similar in syntax to FEATURE statements, MAILER directives are placed at or near the end of sendmail.mc and define which mailers are supported on the system. In Example 7-1, the second- and third-to-last lines tell Sendmail to support the exchange of mail with SMTP and procmail agents. Finally, there are some directives that invoke and configure macros directly by name. MASQUERADE_DOMAIN, MASQUERADE_AS, and EXPOSED_USER are a few such macros that are present in Example 7-1. 7.4.5.1 Some sendmail.mc m4 variable definitionsLet's look at specific sendmail.mc directives that affect security, beginning with some definitions:
There are other security-related definitions, but they're all pertinent to SMTP AUTH, which is covered later in the chapter. 7.4.6 Configuring Sendmail to Run SemichrootedAs mentioned earlier in the chapter, Sendmail doesn't lend itself very well to chrooting, partly as a symptom of its monolithic architecture (one executable does everything). However, the configuration directive confSAFE_FILE_ENV can be used to tell Sendmail to chroot itself when writing files. This occasional chroot approach makes sense for Sendmail. We're probably most worried about file writes, and creating a Safe File Environment is a lot simpler than building a chroot jail that contains copies of every directory, file, executable, and device needed for a complex application like Sendmail to be fully chrooted. Example 7-2 shows the commands (only three!) needed to create a Safe File Environment. Example 7-2. Creating a chroot jailbash$ mkdir -p /var/mailjail/var/spool/mqueue bash$ chown -R 8:12 /var/mailjail* bash$ chmod -R 1755 /var/mailjail/var/spool/mqueue 7.4.6.1 Feature directivesFeatures, as they pertain to sendmail.mc, are syntactically similar to definitions (although they impact sendmail.cf differently). One thing many of these features have in common is the specification of external database files to store various types of mail-handling information. These database files, stored in binary format, allow Sendmail to rapidly retrieve externally maintained data such as user aliases and mail-routing rules. Several Unix database file formats are supported by Sendmail. Most prepackaged versions of Sendmail support the newer hash or btree database formats. The older dbm format may or may not be an option too, depending on whether your version of Sendmail was compiled with it. You can find out which formats are supported on your system by invoking the makemap command with its -l flag (Example 7-3). Example 7-3. Determining supported database formatsbash-# makemap -l hash btree Unless, for some reason, you share databases with hosts running older versions of Sendmail, I recommend sticking to hash. Let's look at some features pertinent to security:
7.4.6.2 MasqueradingMasquerading is the rewriting of From: fields in SMTP headers to make mail originating from one host appear to originate from another. If multiple hosts on your network send mail but only one can receive it, you need masquerading so replies can be sent back to mail sent by nonreceiving hosts. It's also useful for aesthetic reasons — e.g., if you want all the mail from your domain to have From: fields that use the form user@domain rather than user@hostname.subdomain.domain. So far we've been working with only two macros, define and FEATURE, each of which accepts many possible arguments that affect various portions in sendmail.cf. Other macros are dedicated to single aspects of sendmail.cf construction. Here are a few that deal with masquerading (note the absence of the directed quotes ('') in many of these directives):
Those are the most important sendmail.mc settings for security purposes. There are many other nonsecurity settings, however. For more information see the README.cf or cf.README.gz file I alluded to earlier in this section. 7.4.6.3 Applying your new configurationTo compile your macro-configuration file into sendmail.cf, use this command: bash-# m4 /etc/mail/sendmail.mc > /etc/sendmail.cf If your macro-configuration file's name isn't sendmail.mc, substitute it with linux.mc or whatever yours is called. Sendmail expects its configuration file to be named sendmail.cf, however, and it looks for it in /etc, so that part of the command is the same, regardless of your distribution or even your version of Sendmail. After each time you change sendmail.mc/sendmail.cf, you need to restart sendmail. The easiest way to do this is with its startup script /etc/init.d/sendmail, e.g.: bash-# /etc/init.d/sendmail restart 7.4.7 Configuring Sendmail's Maps and Other FilesGenerating sendmail.cf was the complicated part, but you're not done yet. Now you need to tell Sendmail what the legitimate local hostnames are, what to do with incoming mail, which users, networks, and domains may use your SMTP Gateway to relay mail with nonlocal destinations, and what aliases refer to which users. These settings can be specified in the text files and maps in /etc/mail. 7.4.7.1 local-host-namesIf you've set the feature use_cw_file in sendmail.mc , Sendmail will use the file /etc/mail/local-host-names, a text file containing hostnames listed one per line. Sendmail refers to /etc/mail/local-host-names in determining whether messages should be delivered locally — i.e., to a user on the SMTP gateway system itself. If Sendmail incorrectly determines a given address to be nonlocal, it may forward the message back out, resulting in a loop. Suppose our sample SMTP gateway receives email not only for the domain polkatistas.org (the domain on which its own FQDN resides) but also for tubascoundrels.net. If our gateway's hostname is "mail," its local-host-names file might look like this (Example 7-4). Example 7-4. /etc/mail/local-host-nameslocalhost localhost.localdomain polkatistas.org mail.polkatistas.org tubascoundrels.net mail.tubascoundrels.net Note that local-host-names is a flat text file: unlike mailertable, aliases, access, and most other files to which Sendmail refers on an ongoing basis, local-host-names should not be converted to a map (database) format. 7.4.7.2 Configuring the mailertableIf you defined the feature mailertable , you now must edit it in order to define delivery rules. This is an important feature: the mailertable lets you define with considerable granularity which types of email may be relayed (based on destination address) and how. mailertable has a simple syntax that is described in the same file that documents sendmail.mc (README.cf or cf.README.gz, depending on your distribution). In a nutshell, each line in mailertable contains two parts: a destination identifier and an action. The destination identifier matches destination addresses or parts thereof; the action tells sendmail what to do with messages whose destinations match the identifier. If the identifier begins with a ".", all email destination addresses ending in the text following the dot will match. Otherwise, everything following the "@" sign in a destination address must be identical to the identifier. The email address bobo@weird-al.polkatistas.org won't match the identifier polkatistas.org but will match .polkatistas.org. The action takes the form agent:destination where agent is either a mailer (defined in sendmail.mc or linux.mc in MAILER( ) statements) or the built-in agents local or error. local, of course, means the mail should be delivered to a local user, specified after the colon. (If nothing follows the colon, the user specified in the message itself will be used.) destination is a hostname or a local user to whom messages should be relayed. Example 7-5 shows a sample /etc/mail/mailertable file on an SMTP gateway, with three typical actions. Example 7-5. A simple mailertablefake.polkatistas.org local:postmaster .polkatistas.org smtp:%2 polkatistas.org smtp:internalmail.polkatistas.org . smtp:internalmail.polkatistas.org In line 1 of Example 7-5, Sendmail is instructed to send mail addressed to any user on the host "fake" (which may not even exist) to the local user postmaster. In line 2, Sendmail is told to route mail addressed to all other hosts on the polkatistas.org domain directly to those respective hosts via SMTP ("%2" is parsed as "everything after the @ sign, verbatim," i.e., it tells Sendmail to act as a dumb relay for these destinations). This technique is useful if your network has multiple internal mail servers or if you want to send mail directly to certain internal servers from the outside. If, on the other hand, you wish to forward all inbound mail to a single internal mail hub (whose own mailertable may contain dumb-relay entries), you could substitute smtp:%2 with smtp:internalmail.polkatistas.org. Line three of Example 7-5 tells Sendmail to route all mail addressed to the destination polkatistas.org, e.g., someuser@polkatistas.org to the host internalmail.polkatistas.org (apparently the polkatistas' internal mail server) via the SMTP protocol. This is not redundant if it follows an entry for .polkatistas.org ("dot-polkatistas-dot-org"): the leading dot in line 2 matches destinations in which polkatistas.org is preceded by a host- and/or subdomain-name, e.g., frankie.milwaukeeans.polkatista.org or fileserver.polkatista.org. Without the leading period, only destinations containing the specified string, but nothing more, will match. Suppose Sendmail is evaluating the address mick@polkatistas.org against the mailertable in Example 7-5: this address won't match line 1 since its destination isn't fake.polkatistas.org, nor will it match .polkatistas.org because there's no host- or subdomain-name between the "@" sign and "polkatistas.org". It will, however, match line 3. Finally, line 4 of Example 7-5 has as its destination identifier a lone ".". This translates to "none of the above": it matches any nonlocal destination that matches none of the lines preceding it. In line 4, we're telling Sendmail that the default action for nonlocal destinations is to relay such messages to the internal mail server via SMTP. Any transport referred to in mailertable must be defined as a legitimate mailer via a corresponding MAILER( ) directive at or near the end of sendmail.mc. The transport "local" is a special case; by default, this refers to the local sendmail daemon, but it's more efficient to use a proper MDA such as procmail. Use the sendmail.mc feature local_procmail, described earlier in Section 7.4.6.1, to set this. (Don't forget to include a MAILER( ) directive for procmail!) MAILER directives are described in README.cf. Each time you create or edit mailertable, you must convert it into a map (database) file. The traditional way to make maps is with the command makemap. For example, if you're using hash databases (as defined in your FEATURE('mailertable'...) directive), you could convert mailertable to a map file like this: bash-# makemap hash /etc/mail/mailertable.db < /etc/mail/mailertable In recent versions of Sendmail, there are two ways to do this. The simplest method is facilitated by a Makefile automatically placed in /etc/mail when you installed Sendmail. To use it, simply change your working directory to /etc/mail (if it isn't already), and execute this command: bash-# make mailertable 7.4.7.3 Configuring the access databaseNext we need to define which hosts and networks (domains) may relay messages through our server. We can do this by editing /etc/mail/access. Its syntax is simple: each line contains a source name or address, paired with an action (again, see README.cf or its equivalent on your distribution for details). The action can be RELAY, REJECT, DISCARD, OK, or ERROR. In practice, the most useful of these is RELAY. Since by default relaying is rejected, REJECT and DISCARD are useful only when defining exceptions to other RELAY rules (the list is parsed top to bottom, so be sure to list any exceptions near the top). Example 7-6 shows a simple access file. Example 7-6. Simple access filelocalhost.localdomain RELAY localhost RELAY 127.0.0.1 RELAY 192.168 RELAY Notice the absence of real hostnames in Example 7-6. In this example, the SMTP Gateway performs only outbound relays: inbound mail must be addressed to a local email address, and outbound relays must originate from hosts whose IP addresses begin with the octets "192.168" (obviously a non-Internet-routable network). I like this technique of using IP addresses because I can prevent IP-address spoofing with my firewall rules, but I can't prevent forged From: addresses in email. Your needs may be different. As with mailertable, access must be converted to a map file before Sendmail will see your changes. You can do this by executing the command make mailertable from within /etc/mail, or with the following: bash-# makemap hash /etc/mail/mailertable.db < /etc/mail/mailertable The access database has been made somewhat obsolete by Sendmail's support for SMTP AUTH. If you decide to restrict relaying by requiring authentication, you can omit the access database or leave it empty; see Section 7.4.8 to learn how. 7.4.7.4 Configuring virtusersThe virtusers database is useful when multiple (virtual) domains are served by a single SMTP host. Its syntax is very similar to that of aliases: each line contains an address or address mask on the left and a corresponding destination address on the right. If the address on the left is in the format username@host.name, it will be interpreted literally; if no username is specified, e.g., @host.name, it will be interpreted as "any user at host.name." Any hostname or FQDN specified as part of an address/address mask must be listed in local-host-names. The destination address may be the name of a local mailbox (i.e., a local username) or it can be a complete email address on an external host. In Example 7-7 we have a sample virtusertable table for a Sendmail server responsible for three domains. Example 7-7. Sample virtusertablepostmaster@tubascoundrels.net root
@polkatistas.org polkawrangler
@lederhosendudes.net %1@anniefauxfanny.edu
Mail addressed to postmaster@tubascoundrels.net will be delivered to root, assuming tubascoundrels.net has a line in local-host-names. All mail addressed to users at polkatistas.org will be sent to a single user, polkawrangler. Mail addressed to a given mailbox at lederhosendudes.net will be forwarded to the same mailbox at anniefauxfanny.edu. ("%1" is interpreted as "the username in the address matched by this line's address mask.") Like mailertable and access, virtusertable must be converted to a map file before Sendmail can use it. You can execute the command make virtusertable from within /etc/mail, or if you prefer the long way, enter: bash-# makemap hash /etc/mail/virtusertable.db < /etc/mail/virtusertable 7.4.7.5 Defining aliasesThere's just one more file you may wish to tweak: aliases. While most systems store aliases and aliases.db in /etc/mail, some keep them in /etc for historical reasons (this is the case on Red Hat systems). aliases contains a map of email aliases. Example 7-8 lists part of a sample aliases list. Example 7-8. Excerpt from /etc/aliasespostmaster: root root: mick michael: mick@visi.com mailstooges: mick, larry, curly As you can see, aliases is fairly self-explanatory: each line starts with an alias (something we expect to see to the left of the "@" sign in an email address), followed by a colon, and ends with a local username (mailbox name), another alias, or an external email address. You can map multiple comma-delimited accounts to a single alias to create mailing lists: this is the case with the last entry in Example 7-8, mailstooges. Note that you can "cascade" aliases as in Example 7-8; just be sure not to create any loops, as in Example 7-9. Example 7-9. An alias looppostmaster: root root: postmaster On an SMTP gateway, you probably won't want to do very much with the aliases database other than to tweak its entries for postmaster, hostmaster, root, and other infrastructure-related entries. Rather than handling ordinary users' aliases, a gateway should route messages based on destination hostnames and domains (i.e., via mailertable and virtusers) and leave alias-username translations to the hosts to which it relays (i.e., the internal mail server, unless for some reason the internal mail server lacks the ability to do so). After each edit of aliases , you must convert it to a map file. Unlike with access, there's only one method to do so, and it involves neither makemap nor make. To generate a new aliases.db file, simply enter the command newaliases without any flags or arguments. 7.4.8 Sendmail and SMTP AUTHThe security controls I've covered so far are all important: they're things that should be enabled and configured on any publicly accessible Sendmail server. But Sendmail has two relatively new features that take Sendmail security even further: authentication and encryption. Let's start with authentication. SMTP AUTH, described in RFC 2554 (ftp://ftp.isi.edu/in-notes/rfc2554.txt), is a badly needed extension to the SMTP protocol: it describes a flexible authentication mechanism that can be used to authenticate relaying. SMTP AUTH allows a password shared by two hosts (or stored by one host for its local users) to be used to validate email senders. Naturally, it's both unfeasible and counterproductive to authenticate all SMTP transactions, i.e., those involving mail addressed to or sent by users who verifiably reside on your local system or name domain. But authentication is extremely useful in two different SMTP-relaying contexts, which I'll call "server-server" and " client-server." In server-server relaying, a user sends mail to Server A, Server A authenticates to Server B and relays the mail through it, and Server B delivers the mail to its remote destination (Figure 7-1). Typically, Server A is an internal mail server, and Server B is a DMZed SMTP gateway. Figure 7-1. Server-to-Server RelayingThe second context for SMTP AUTH, one which is probably more widely used, is client-server SMTP relaying, in which remote users authenticate back to their "home" SMTP gateway to send (relay) their outgoing mail (Figure 7-2). This is a handy way to let users move between your internal network and external sites without reconfiguring their email-client software. If you're running an SMTP server that receives mail relayed from other domains, you probably want to use SMTP AUTH: it's an important defense against Unsolicited Commercial Email, the perpetrators of which rely heavily on open SMTP relays. Figure 7-2. Client-server SMTP relayingDepending on which authentication mechanism you choose, it may make sense to encrypt your SMTP AUTH transactions via Sendmail's TLS features. TLS stands for Transport Layer Security, which is the IETF's standard for and successor to Netscape Communications' versatile and ubiquitous SSL (Secure Sockets Layer) v3 protocol. As with HTTP, SMTP sessions even between unauthenticated hosts can be transparently encrypted using this protocol. Also as with HTTP, it appears that SMTP users tend to use TLS/SSL in this way rather than leveraging the powerful digital-certificate-based authentication mechanisms supported by TLS and SSL. This isn't too surprising: one of the ugly realities of modern IS security is that Public Key Infrastructure (PKI) technologies are complicated, unwieldy, and difficult to maintain. By combining digital certificates (used as strong but unverified encryption keys) with other, simpler authentication mechanisms such as SASL, many people feel they get "the best of both worlds." We'll cover Sendmail's TLS features in more depth later in this chapter. 7.4.8.1 Versions of Sendmail that support SMTP AUTHSMTP AUTH support in Sendmail was introduced with Sendmail v.8.10. As mentioned earlier in the chapter, Red Hat 7 and SuSE 7 both ship with binary packages of Sendmail v.8.11. However, while Red Hat's standard sendmail package has SMTP AUTH support compiled in, SuSE's doesn't: if you want SMTP AUTH, you need the package sendmail-tls, which can be found in SuSE 7.x's sec2 package series. Debian 2.2's ("Potato's") Sendmail package is v.8.9, which predates Sendmail's adoption of SMTP AUTH. However, the current testing distribution (a.k.a "woody") has a deb package of Sendmail 8.12.1, which does have SMTP AUTH support compiled in. If you don't use one of these three distributions and yours lacks an SMTP AUTH-enabled Sendmail package, you may need to download the latest Sendmail source code from http://www.sendmail.org and compile it yourself. Before you build, however, be sure to read Claus Aßmann's article "SMTP AUTH in sendmail 8.10-8.12" (http://www.sendmail.org/~ca/email/auth.html), which contains instructions on how to compile SMTP AUTH support into Sendmail — by default, Sendmail builds without it. 7.4.8.2 Obtaining Cyrus SASLSendmail actually can't authenticate anything directly, even if it has SMTP AUTH support compiled in. Rather, it depends on Carnegie Mellon University's Simple Authentication and Security Layer (SASL) package, which authenticates against its own database or against an OS mechanism such as PAM. SASL can of course be obtained from CMU (at ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/). However, it makes more sense to use your Linux distribution's binary package since if you install a binary package of Sendmail that supports SMTP AUTH, then the SASL package must satisfy dependencies in Sendmail. In Red Hat 7 the RPM package is called cyrus-sasl; in SuSE 7 it's also called cyrus-sasl and is part of the sec1 group; under Debian testing ("Woody") the required deb package is libsasl7. (There's no such package in Debian 2.2, but remember: the older version of Sendmail in Debian 2.2 doesn't support SMTP AUTH anyhow; you need the Debian-Woody sendmail and libsasl7 packages if you want SMTP AUTH.) 7.4.8.3 Configuring SASL for server-server authenticationIf you want your Sendmail server to authenticate other servers, it's easiest to use SASL's own authentication database, /etc/sasldb. Sendmail can use this database in sophisticated challenge-response mechanisms such as CRAM-MD5 and DIGEST-MD5 in which no secret data (i.e., passwords) are exchanged over the network. It can also use /etc/sasldb in the much less secure PLAIN method in which the password is exchanged over the network — unencrypted! — but the PLAIN method isn't appropriate unless you're also using TLS, described later in this chapter. Besides its compatibility with Sendmail's CRAM-MD5 and DIGEST-MD5 mechanisms, the other advantage of /etc/sasldb is that it provides an alternative set of authentication credentials besides your system- and user-account passwords. It makes sense to avoid using actual login credentials for automated network transactions such as server-server SMTP relaying. Let's configure SASL for the server-server relay scenario, then. This takes only two steps. First, we create a small, one-line configuration file telling SASL how Sendmail authentication should be handled. This file, /usr/lib/sasl/Sendmail.conf, only needs to define the variable pwcheck_method. Possible methods include sasldb (authenticate using /etc/sasldb), pam (use the operating system's PAM logon mechanism), and kerberos_v4 (use the local Kerberos infrastructure, assuming there is one). Example 7-10 shows a SASL Sendmail.conf file for a Sendmail server that authenticates relays from other servers via /etc/sasldb. Example 7-10. /usr/lib/sasl/Sendmail.conf with sasldb authenticationpwcheck_method: sasldb The second step is to create and populate /etc/sasldb with at least one user account.Do this with the following command: saslpasswd username This account should not use any username or password in /etc/passwd. Since no one will have to type the password in our server-to-server transaction, there's no reason for it to be short or simple. Example 7-11 shows a sample password-creation session (with the password shown for illustrative purposes — it isn't echoed back to the screen in a real saslpasswd session). Example 7-11. An example sasldbpasswd sessionbash-# saslpasswd maildroid Password: Ch1mp? ,03fuzz fl0ppi Again (for verification): Ch1mp? ,03fuzz fl0ppi Remember that password (or write it down in a safe place): you'll use it to configure any Sendmail hosts that need to relay mail to the one on which you created the account on. (We'll discuss how to do so shortly.) Note that if this is the first time we've run saslpasswd, this command will automatically create /etc/sasldb. Subsequent invocations of saslpasswd will append to the database and not overwrite it. We can see the fruit of our saslpasswd labors by entering, without flags or arguments, the command sasldblistusers (Example 7-12). Example 7-12. Using sasldblistusersbash-# sasldblistusers user: maildroid realm: dmzmail.polkatistas.org mech: PLAIN user: maildroid realm: dmzmail.polkatistas.org mech: CRAM-MD5 user: maildroid realm: dmzmail.polkatistas.org mech: DIGEST-MD5 If for any reason you wish to delete an account you've created in /etc/sasldb, you can do so with saslpasswd's -d flag, i.e.: saslpasswd -d username Once /usr/lib/Sendmail.conf and /etc/sasldb are ready, we can configure Sendmail for authentication. If you're doing so as you read this (and it's a server-server relay scenario), skip to Section 7.4.8.5. 7.4.8.4 Configuring SASL for client-server authenticationIIf your Sendmail server needs to authenticate individual users instead of other servers (e.g., remote users), SASL configuration is much simpler. All we need to do is create a /usr/lib/sasl/Sendmail.conf file that sets pwcheck_method to pam (Example 7-13). Example 7-13. A /usr/lib/sasl/Sendmail.conf file for client-server authenticationpwcheck_method: pam And that's it! Since SASL will use the existing local PAM mechanism to authenticate prospective relays, there's no need to create /etc/sasldb. Once /usr/lib/Sendmail.conf and /etc/sasldb are ready, we must configure Sendmail for authentication. If you're doing so as you read this (and it's a client-server relay scenario), skip to Section 7.4.8.6. 7.4.8.5 Configuring Sendmail for server-server authenticationThere are two files to edit to prepare our Sendmail server to authenticate other servers for relaying. The first, predictably, is /etc/mail/sendmail.mc, in which we must configure the variable confAUTH_MECHANISMS and the macro TRUST_AUTH_MECH. Both of these accept as their definition any combination of CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, GSSAPI, or KERBEROS_V4.
confAUTH_MECHANISMS is used to define which of these authentication methods you want Sendmail to support as either a server or a client. TRUST_AUTH_MECH, on the other hand, defines which authentication methods your Sendmail server will accept from prospective relay clients (e.g., other servers). This is usually but not necessarily a subset of the methods listed in confAUTH_MECHANISMS. (If you list any mechanisms in TRUST_AUTH_MECH that are not listed in confAUTH_MECHANISMS, the extraneous mechanisms in TRUST_AUTH_MECH will fail when attempted by clients. For clarity and predictability's sake, I recommend that your TRUST_AUTH_MECH macro contain only mechanisms also listed in confAUTH_MECHANISMS.) Example 7-14 shows part of an SMTP AUTH-enabled sendmail.mc file. Example 7-14. SMTP AUTH settings in server's sendmail.mcTRUST_AUTH_MECH(`CRAM-MD5 DIGEST-MD5')dnl define(`confAUTH_MECHANISMS', `CRAM-MD5 DIGEST-MD5')dnl For sasldb-based server-server authentication, I recommend the CRAM-MD5 and DIGEST-MD5 methods since, as I mentioned earlier, both methods use challenge-response sessions in which the password is used as a hash key. These methods are vastly preferable over actually transmitting the password, as in the PLAIN and LOGIN mechanisms. As with any changes you make to sendmail.mc, you should afterwards regenerate sendmail.cf via the command m4 /etc/mail/sendmail.mc > /etc/sendmail.cf and then restart sendmail. Okay, that's the "server" side of our server-server transaction. This host is now ready to accept relays from other, authenticated, servers. Now we need to configure at least one "client" system that transfers mail through the first one. If a Sendmail host needs only to relay mail, and not to accept relays from other hosts, it doesn't need TRUST_AUTH_MECH set. It instead needs confAUTH_MECHANISMS and confDEF_AUTH_INFO. Be careful what you set in confAUTH_MECHANISMS: if none of the mechanisms you specify are supported in the other host's TRUST_AUTH_MECH and confAUTH_MECHANISMS directives, relaying will fail. Also, note that your system will attempt its supported mechanisms in the order in which they're listed. Example 7-15 shows a relaying Sendmail host's confAUTH_MECHANISMS directive. Example 7-15. SMTP AUTH settings in a relay's sendmail.mcdefine(`confAUTH_MECHANISMS', `CRAM-MD5 DIGEST-MD5 LOGIN PLAIN')dnl define(`confDEF_AUTH_INFO', `/etc/mail/default-auth-info')dnl confDEF_AUTH_INFO specifies the location of the authentication credentials you want your host to present to its mail servers. This file is usually /etc/mail/default-auth-info, and it's an ASCII text file with the following four-line format: authorization_identity # (i.e., username) authentication_identity # (usually identical to username) secret # (password created on other host with saslpasswd realm # (usually the FQDN of the other host) Example 7-16 shows the /etc/mail/default-auth-info file on dmzmail.polkatistas.org. Example 7-16. A sample /etc/mail/default-auth-info filemaildroid maildroid Ch1mp? ,03fuzz fl0ppi dmzmail.polkatistas.org Needless to say, since /etc/mail/default-auth-info contains your relay password in clear text, you must protect this file the best you can. Be sure to change its permissions mode to 600 and its owner to root. Again, regenerate sendmail.cf and restart sendmail. You're done! Now whenever this host needs to relay mail through the server we configured earlier, it will first attempt to authenticate itself as maildroid using the CRAM-MD5 method. 7.4.8.6 Configuring Sendmail for client-server authenticationIf you need to configure your Sendmail server to authenticate relays from remote users using MUA software (i.e., to handle those users' "outbound" mail), there's not much you need to do: simply set confAUTH_MECHANISMS and TRUST_AUTH_MECH, this time making sure that each includes the LOGIN and PLAIN methods. Example 7-17 shows part of such a server's sendmail.mc file. Example 7-17. Part of sendmail.mc on server authenticating remote users via PAMTRUST_AUTH_MECH(`CRAM-MD5 DIGEST-MD5 LOGIN PLAIN')dnl define(`confAUTH_MECHANISMS', `CRAM-MD5 DIGEST-MD5 LOGIN PLAIN')dnl
On the client side, each user will need to configure his MUA with his username and password from the Sendmail server; this is usually in a section entitled "SMTP server settings," "Sending," etc. But there's one small problem with this (besides the fact that your public SMTP server probably shouldn't have ordinary user accounts, but that's an architectural problem): the LOGIN and PLAIN methods send passwords over the network in clear text. That's bad, right? Right. For this reason TLS encryption really should be used any time you use these methods. Luckily, many popular POP3 and IMAP applications support TLS (SSL), among them, MS Outlook Express and GNOME balsa. 7.4.9 Sendmail and STARTTLSBeginning with Version 8.11, Sendmail supports the Extended SMTP command STARTTLS (per RFC 2487, ftp://ftp.isi.edu/in-notes/rfc2487.txt). When this command is issued at the beginning of an ESMTP session, it initiates an encrypted TLS tunnel that protects the rest of the session from eavesdropping. Due to the logistics of distributing and maintaining X.509 certificates, many people who use STARTTLS prefer using SASL to authenticate their TLS tunnels over TLS's own X.509 authentication scheme. While this TLS/SASL combination is my focus here, Sendmail lets you authenticate TLS tunnels with either SASL (SMTP AUTH) or TLS-style X.509 certificate-based authentication. For more information on this and other uses of STARTTLS in Sendmail, see Claus Aßmann's article "SMTP STARTTLS in sendmail/Secure Switch" (http://www.sendmail.org/~ca/email/starttls.html). 7.4.9.1 Versions of Sendmail that support STARTTLSSendmail Versions 8.11 and 8.12 support STARTTLS. However, your Linux distribution's Sendmail package may not have this support compiled in. While Red Hat's stock sendmail package does support SMTP AUTH, it does not include STARTTLS support. If you are a Red Hat user, you'll need to obtain source code from http://www.sendmail.org and compile it yourself. The Claus Aßmann article I just mentioned includes compiling instructions that are much, much simpler than those scattered throughout the source-code tarball itself. (By any measure, trying to decipher Sendmail source-code documentation can be both frustrating and futile!) SuSE and Debian, however, are more accommodating: the packages described earlier that support SMTP AUTH on these distributions also support STARTTLS. If you use SuSE, you'll need the sendmail-tls package; if you use Debian, you'll need sendmail from Debian's testing release ("Woody"). (Actually by the time you read this, it's quite possible that Woody will have been promoted to stable status.) In addition to a STARTTLS-enabled binary of Sendmail 8.11 or 8.12, you'll also need a TLS or SSL package, if you plan to create and sign your own certificates: I recommend OpenSSL. The binary packages for OpenSSL on RedHat, SuSE, and Debian are all titled simply openssl, and current versions of all three distributions should provide a recent-enough version of OpenSSL to work properly with Sendmail. 7.4.9.2 Getting keys and certificatesIf you're new to PKI, digital certificates, or public-key cryptography, a good starting point is the RSA Crypto FAQ, available at http://www.rsasecurity.com/rsalabs/faq; so is Bruce Schneier's excellent book, Applied Cryptography (Wiley). Suffice it to say that TLS and SSL use x.509 digital certificates, a type of public-key cryptography in which one's public key is formatted to include a certain amount of identification information (besides just your key ID and the public key itself), including the digital signature of a "Certificate Authority" (CA) that vouches for the authenticity of the certificate. If you want an SMTP server to communicate with other SMTP servers using TLS, it needs a digital certificate, including a separate private key, and you need the certificate to have been signed by some CA. If your organization uses PKI in some capacity and you already have either a CA of your own or a relationship with some external CA (e.g., Verisign or Thawte), you can create your certificate locally but will need to have your CA sign it. If you only intend to use SSL for Sendmail, however, you'll probably want to be your own CA. Being a CA for such limited purposes amounts to generating a CA certificate and using it to sign your other certificates. Chapter 5 contains step-by-step instructions on how to set up a CA using the excellent and free OpenSSL and how to create and sign x.509 certificates. See "How to become a small-time CA" and "Generating and signing certificates" in Chapter 5 For what follows here, you'll need a copy of your CA's certificate (usually called cacert.pem), a signed server certificate for your SMTP host (called newcert_signed.pem in Chapter 5 and in subsequent examples), and the certificate's corresponding private key (called newcert_key.pem in Chapter 5 and here). 7.4.9.3 Configuring Sendmail to Use TLSNow you've created your site-wide CA certificate (or obtained a copy of it if someone else controls the CA), created a new server certificate, and signed the server certificate (or gotten it signed) with the CA key. All that's left to preparing Sendmail is putting things where it can find them and telling it where they are. The logical place to put Sendmail's copies of these certificates is in /etc/mail/certs: create this directory if it doesn't already exist, and make sure it's owned by root and its mode is set to drwx------. Copy your CA certificate (but not its private key) — cacert.pem, in the previous examples — into /etc/mail/certs. Copy your server certificate there too, along with its corresponding private key (which are shown as newcert_key.pem and newcert_signed.pem, respectively, in subsequent examples). Make sure that all files in /etc/mail/certs are set to mode 0600 (-rw-------); otherwise, Sendmail will refuse to use them, and TLS will not work. Example 7-18 shows a long listing of our sample /etc/mail/certs directory. Example 7-18. A sample /etc/mail/certs directory listingdmzmail:/etc/mail/certs # ls -l total 30 drwxr-x--- 2 root root 272 Feb 16 20:39 . drwxr-xr-x 4 root root 1293 Feb 16 20:38 .. -rw------- 1 root root 1367 Feb 16 18:55 cacert.pem -rw------- 1 root root 2254 Feb 16 20:36 newcert_key.pem -rw------- 1 root root 3777 Feb 16 20:32 newcert_signed.pem Now just direct Sendmail's attention to these files, and you'll be ready to go. A combination of the following sendmail.mc directives, all of them variable definitions, achieves basic server-side TLS configuration:
Example 7-19 lists these directives on our sample Sendmail server dmzmail.polkatistas.org, which is set up to be both a TLS server and a client. Example 7-19. Sample TLS directives for sendmail.mcdefine(`CERT_DIR', `/etc/mail/certs')dnl define(`confCACERT_PATH', `CERT_DIR')dnl define(`confCACERT', `CERT_DIR/cacert.pem')dnl define(`confSERVER_CERT', `CERT_DIR/newcert_signed.pem')dnl define(`confSERVER_KEY', `CERT_DIR/newcert_key.pem')dnl define(`confCLIENT_CERT', `CERT_DIR/newcert_signed.pem')dnl define(`confCLIENT_KEY', `CERT_DIR/newcert_key.pem')dnl After you set these directives, regenerate sendmail.cf, and restart sendmail, your server will accept encrypted SMTP sessions via the STARTTLS command. |