Section 7.4. Sendmail

Sendmail 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 Cons

On 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.

A Disclaimer

I'm a Postfix fan myself. I run Postfix as my domain's public SMTP gateway (though I do use Sendmail on my private network for local mail delivery). Therefore, nothing in this section, including its very existence, should be construed to mean that I think Sendmail is the best choice for everyone's MTA needs. You'll need to decide for yourself whether Sendmail is the best tool for your environment.

However, I will say that I've spent a good deal of time over the past few years using and helping others to use Sendmail, and I think it's a lot better than many people give it credit for. In my experience, Sendmail is not the lumbering, slobbering, fragile beast some of its critics make it out to be.

In fact, I've found Sendmail to be stable and powerful, if a bit scary in its complexity. Furthermore, since the last CERT advisory involving a remote-exploit vulnerability in Sendmail was in 1997 (number CA-1997-05), I'm simply not convinced that Sendmail is inherently unsecurable, as D. J. Bernstein and others insist. If it were, the CERT advisories would continue to roll right out: Sendmail has been under more scrutiny in the past five years than it was beforehand!

So while other MTAs (notably Postfix and Qmail) may have clear advantages over Sendmail in performance and, yes, security, I also think that Sendmail is nonetheless useful and securable enough to take seriously.

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 Architecture

As 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 Sendmail

I 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.

Sendmail Versions on Debian

Debian GNU/Linux v2.2 ("Potato") still supports Sendmail v.8.9.3. Although this is a stable and apparently secure release, it's now two major versions old (if one considers the second numeral to represent a major version, which I do since the first numeral has been "8" for half a decade). Furthermore, 8.9.3 doesn't support TLS or SMTP-AUTH.

If you want TLS or SMTP-AUTH, or are simply uncomfortable running such an old version, you can always uninstall the package, download the latest source-code tarball from http://www.sendmail.org, and compile and install Sendmail from source. The source-code tarball is well documented and compiles very easily under Linux.

Note that as with Sendmail, the Debian 2.2 package for Postfix predates that application's support for SMTP AUTH. However, Debian's preferred mailer, Exim, does support SMTP AUTH in the version (Exim v3.12) provided in Debian 2.2.

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 preparation

If 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 preparation

If 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 preparation

If 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: Overview

The easiest way to generate Sendmail configurations is to follow these steps:

  1. Enable needed features and tweak settings in sendmail.mc.

  2. Set up domain-name masquerading, if needed, in sendmail.mc.

  3. Run m4 to generate sendmail.cf from sendmail.mc.

  4. Configure delivery rules by editing mailertable.

  5. Configure relaying rules by editing access.

  6. Configure multiple-domain handling rules by editing virtusers.

  7. Define local user-aliases in aliases.

  8. Convert mailertable, access, virtusers, and aliases to databases.

  9. Define all valid hostnames of the local system in the file local-host-names.

  10. (Re-)start sendmail.

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.mc

The 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.

Depending on which Linux distribution you use, a complete configuration reference for sendmail.mc can be found in /usr/lib/sendmail-cf/README.cf (Red Hat and its derivatives), /usr/share/sendmail/README (SuSE), or /usr/share/doc/sendmail/cf.README.gz (Debian).

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 file
divert(-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 definitions

Let's look at specific sendmail.mc directives that affect security, beginning with some definitions:

define(`confDEF_USER_ID',`` userid:groupid')dnl

The confDEF_USER_ID definition tells Sendmail under which user ID and group ID it should run by default. If this variable isn't defined, its values default to 1:1 (user = bin, group=bin), but I recommend changing it. Red Hat's default of 8:12 (user=mail, group=mail) is more sensible. Sendmail is intelligent enough to run as root while listening on TCP port 25 (which is a privileged port) but to demote itself to whatever value is set in confDEF_USER_ID once mail arrives.

Beforehand, you may need to add a user and group for Sendmail to use. If your system doesn't already have a group named mail, use this command:

groupadd -g 12 mail 

Similarly, if your system doesn't have a user account named mail, use this command to create one:

useradd -u 8 -g 12 -d /var/spool/mail -s /bin/false mail
define(`confPRIVACY_FLAGS', ` flag1,flag2,etc.')dnl

As you can see, when we define the macro confPRIVACYFLAGS, we can specify a list of one or more flags that determine how Sendmail behaves in SMTP sessions. Table 7-1 shows some flags I recommend using on any publicly accessible Sendmail server.

Table 7-1. Useful privacy flags in Sendmail

Privacy flag

Description

Goaway

Sets all privacy flags except noreceipts, restrictmailq, restrictqrun, restrictexpand, and noetrn.

needmailhelo

Forces all SMTP clients to begin their sessions by identifying themselves with a HELO or EHLO command.

Noexpn

Disables the EXPN and VERB commands.

Novrfy

Disables the VRFY command.

noreceipts

Disables the returning of return and read receipts.

restrictmailq

Allows only members of the group that owns /var/spool/mqueue to view Sendmail's queue files via the mailq command. Note that if you set this flag, the permissions on /var/spool/mqueue may still be at 0700 without impairing mail-group members' ability to run mailq.

restrictqrun

Allows only root or the owner of /var/spool/mqueue to process Sendmail's queue (i.e., to tell Sendmail to attempt to send all messages currently in its queue, a là sendmail -q).

authwarnings

Indicates discrepancies (e.g., sender claims her hostname is tubby.tubascoundrels.org, but her IP reverse-resolves to matahari.boldimposters.net) within the affected message's X-Authentication-Warning header.

needexpnhelo

Indicates that SMTP clients needn't begin with HELO/EHLO unless they wish to use the EXPN command at some point, in which case they must HELO or EHLO first.

needvrfyhelo

Indicates that SMTP clients needn't begin with HELO/EHLO unless they wish to use the VRFY command at some point, in which case they must HELO or EHLO first

define(`confSMTP_LOGIN_MSG', ` message')dnl

This variable defines the banner string that sendmail sends to remote clients at the beginning of each SMTP session. By default, this string is set to $j Sendmail $v/$Z; $b, where $j expands to the local Fully Qualified Domain Name (FQDN), $v expands to the sendmail daemon's version, $Z expands to the version number of the m4 configuration, and $b expands to a time/date stamp.

In truth, none of this information needs to be provided. I personally prefer to set my Sendmail login message to a minimal `Sendmail'.

define(`confSAFE_FILE_ENV', ` /path/to/jail')dnl

This definition tells Sendmail to set sendmail.cf's SafeFileEnvironment variable to which some subdirectory of / that sendmail will chroot when writing files. For more information, see Section 7.4.6.

define(`confUNSAFE_GROUP_WRITES')dnl

In Example 7-1 confUNSAFE_GROUP_WRITES has been set to true. If true, confUNSAFE_GROUP_WRITES causes Sendmail to log a warning message whenever mail is handled by a .forward or :include: file that is group- or world-writable. Furthermore, if such a .forward or :include: file contains any address pointing to an unsafe file, such as an executable, the message being processed will be bounced and logged accordingly.

This is an extremely useful feature for SMTP shell servers, for the obvious reason that a world- or group-writable .forward file carries a high risk of being altered by some malicious local user and therefore shouldn't be trusted. confUNSAFE_GROUP_WRITES isn't as meaningful for SMTP gateways, however, on which there aren't ordinary end users to worry about.

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 Semichrooted

As 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 jail
bash$ 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 directives

Features, 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 formats
bash-# 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:

FEATURE(`mailertable',` hash| dbm| btree [-o ] /path/mailertable.db')dnl

The mailertable feature causes sendmail to reference the file /etc/mail/mailertable.db in determining how to route incoming mail. This feature thus adds to the modularity of Sendmail's configuration.

The comma and everything that follows it is called the "map definition," and it's used to specify the file format and path of the map being defined. If your map definition includes the -o ("optional") flag, Sendmail will check for mailertable.db but not require it. If the map-definition portion of this statement (the comma and everything after it) is omitted, it defaults to `hash /etc/mail/mailertable.db'

We'll look at syntax and examples of the mailertable itself in Section 7.4.6.

FEATURE(`access_db',` hash| dbm| btree [-o ] /path/access.db')dnl

This is another modularizing feature. Creating an access database provides a convenient way to maintain a list of both allowed and explicitly denied relaying hosts and domains. (See FEATURE(`mailertable'...) for a description of valid database types and of the -o ("optional") flag). If the map definition portion of this statement is omitted, it defaults to `hash /etc/mail/access.db'

As with mailertable, we'll cover access syntax and examples in Section 7.4.4.

FEATURE(`virtusertable',` hash| dbm| btree [-o ] /path/virtusertable.db')dnl

The virtual user table, or virtusertable, is yet another separate configuration file for sendmail that can be maintained separately from sendmail.cf. This one determines how virtual domains are handled. The simplest definition of virtual domains is "email addresses hosted by the server, but with different domain names from the one in which the server's FQDN resides." (See FEATURE(`mailertable'...) for a description of valid database types and of the -o ("optional") flag). If the map-definition portion of this statement is omitted, it defaults to `hash /etc/mail/virtusertable.db'

virtusertable, too, is covered in Section 7.4.4.

FEATURE(`use_cw_file')dnl

If listed, this feature causes sendmail to use the file /etc/mail/local-host-names to determine valid local names ? i.e., names that, if used to the right of the "@" in an email address, will cause that mail to be delivered locally. This is part of Sendmail's anti-SPAM-relaying functionality.

FEATURE(`smrsh', ` /path/to/smrsh')dnl

Like confUNSAFE_GROUP_WRITES, the Sendmail Restricted Shell (smrsh) protects your server from unpredictable local users and is therefore of more use on SMTP shell servers than on SMTP gateways. smrsh restricts which programs your users may execute from their .forward files to those that reside in (or are pointed to by symbolic links in) smrsh's directory, usually /usr/lib/sendmail.d/bin/.

FEATURE(`dnsbl', ` blackhole.list.provider')dnl

Use a special DNS look-up to check all senders' hostnames against a "black hole list" of known sources of UCE. If omitted, the name of the blackhole.list.provider defaults to blackholes.mail-abuse.org. Note that this is a subscription-based service: mail-abuse.org charges a yearly fee for nonpersonal use. See http://mail-abuse.org/rbl/ for more information.

FEATURE(`blacklist_recipients')dnl

Check recipient addresses of incoming mail against the access database to block mail to selected usernames (e.g., lp).

FEATURE(`nouucp')dnl

If you don't share mail via the old UUCP protocol, this directive completely disables UUCP support in Sendmail.

7.4.6.2 Masquerading

Masquerading 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):

MASQUERADE_AS( host.or.domain.name)dnl

This macro lets you specify what you want to appear after the "@" in your From addresses. For example, if I specify MASQUERADE_AS(tubby.tubascoundrels.org)dnl, mail handled by my server will seem to originate from the host tubby.tubascoundrels.org regardless of my server's hostname or even domain name (depending on other macros).

If I specify MASQUERADE_AS(tubascoundrels.org)dnl, my From addresses will be rewritten to show only the domain name tubascoundrels.org, not the full hostname of the host on which the message actually originated ? e.g., mick@tubascroundrels.org rather than mick@micksdesktop.tubascoundrels.org.

MASQUERADE_DOMAIN( domain.name)dnl

By default, mail originating on the Sendmail server (i.e., From addresses containing hostnames listed in /etc/mail/local-host-names) will be masqueraded. If mail from other hosts is handled by this host and that mail is to be masqueraded as well, each fully qualified hostname needs to be listed in a MASQUERADE_DOMAIN directive. Continuing my previous example, if the SMTP relay tubby.tubascoundrels.org domain also handles outbound email from weird-al.polkatistas.org, the relay's sendmail.mc file will need to include the directive MASQUERADE_DOMAIN(weird-al.polkatistas.org)dnl for both hosts' mail to be masqueraded.

MASQUERADE_DOMAIN_FILE(` /path/filename')dnl

If you have a lot of hosts/domains to masquerade, you may wish to specify them in a separate text file (one domain name per line). The MASQUERADE_DOMAIN_FILE directive lets you name such a file, conventionally /etc/mail/domains (not to be confused with /etc/mail/domaintable).

FEATURE(`masquerade_entire_domain')dnl

The feature masquerade_entire_domain causes MASQUERADE_DOMAIN to be interpreted as an entire domain rather than a hostname.

FEATURE(`masquerade_envelope')dnl

This feature causes sender addresses not just in the From: header field but also in the SMTP envelope to be masqueraded.

EXPOSED_USER( username)dnl

EXPOSED_USER specifies a username for whom the From address should not be masqueraded. root is a popular candidate for this, since email from root often contains alerts and warnings: if you receive such an alert or warning, you generally want to know which host sent it.

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 configuration

To 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 Files

Generating 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-names

If 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-names
localhost

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 mailertable

If 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 mailertable
fake.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 database

Next 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 file
localhost.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 virtusers

The 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 virtusertable
postmaster@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 aliases

There'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/aliases
postmaster:       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 loop
postmaster:       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 AUTH

The 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 Relaying
figs/bssl_0701.gif

The 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 relaying
figs/bssl_0702.gif

Depending 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 AUTH

SMTP 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 sen