Cover V12, I10

Article

oct2003.tar

Just Can't Get Enough Sendmail

Hal Pomeranz

In the June issue of Sys Admin, I discussed the concept of shutting down the standard Sendmail daemon on most Unix machines (http://www.sysadminmag.com/documents/s=8228/sam0306a/0306a.htm). To recap, this daemon is responsible for two things:

1. Listening on port 25/tcp for incoming messages from outside of the machine.

2. Flushing the local queue of unsent messages on a periodic basis.

If the machine is not a mail server, then there is no need for your system to be listening on port 25/tcp for incoming email (flushing the queue of outgoing messages can be handled by running Sendmail from cron on a periodic basis). Disabling the Sendmail daemon on most of your machines is a huge security win, since it prevents external attackers from using Sendmail as a mechanism for breaking into your site.

That article resulted in an enormous amount of feedback, but there were a small number of specific issues that came up repeatedly. Clearly, many sites are grappling with similar circumstances, so in this follow-up article, I will cover some of these common problems in more detail.

Black Holes, Bounced Email, and Replies

After implementing my suggested configurations on their systems, several people noticed that they were no longer receiving email that was sent to root or other users by the cron daemon or other processes running on the local machine. Other readers noted that mail bounces and error messages, and even normal replies to messages sent from the reconfigured machine were not making it back to the original sender. What's happening here is "normal behavior" for Sendmail, but obviously not desirable behavior for these sites.

Given a "bare" address like "root" or "mary", Sendmail will automatically add the fully qualified hostname of the local machine on the right-hand side of the address. So, mail to root will end up being sent to root@somehost.yourdomain.com. Now, per the configuration guidance in my previous article, this email will get forwarded to a central relay server elsewhere on your network for final delivery. Unfortunately, this relay server is going to attempt to send the email right back to the machine that generated it, because the delivery address is the machine somehost.yourdomain.com. But that machine is no longer running a Sendmail daemon to receive this incoming email! So, the message will sit in the outgoing mail queue on the relay server until it times out and is expunged. It will never get delivered.

Note that Sendmail also qualifies the sender address in the same way. Thus, outgoing messages leave the machine as being from user@somehost.yourdomain.com. If somebody tries to reply to this message, the response will sit in a mail queue someplace trying to be delivered to somehost.yourdomain.com again and ultimately never be delivered. The same thing happens to bounced messages and other errors.

This is clearly not what we want. Most sites deal with this problem by "hiding" their host names, or masquerading in Sendmail lingo. In other words, bare addresses get qualified with just yourdomain.com, rather than the full hostname of the machine where the email message was generated. Now all messages, replies, and bounces will simply go to user@yourdomain.com, and this traffic can easily be handled by your central mail servers.

To fully enable masquerading, simply add a few following configuration directives to your Sendmail macro configuration file. These directives can be included in either the nullclient.mc or submit.mc file discussed in the previous article:

MASQUERADE_AS(`yourdomain.com')
FEATURE('allmasquerade')
FEATURE('masquerade_envelope')
FEATURE('always_add_domain')
The MASQUERADE_AS directive specifies the domain that should be used to qualify bare addresses instead of the fully qualified hostname of the local machine. Usually this would be your local domain name, but it could be any domain name you want to specify, even a domain that is foreign to the local site. By default Sendmail masquerading only applies to the outgoing sender address. The allmasquerade feature tells Sendmail to use the masqueraded domain on recipient addresses as well. Furthermore, it's necessary to use masquerade_envelope so that the "envelope sender" address is also masqueraded, because this is the address to which bounces and replies will be sent.

The always_add_domain feature is not strictly related to masquerading. This directive tells Sendmail to always qualify both bare recipient addresses (e.g., mail sent to root from the cron daemon) as well as the outgoing envelope sender address. If MASQUERADE_AS has been used to specify a domain name then that name will be used; otherwise, Sendmail just uses the fully qualified hostname of the machine. Qualifying all addresses in outgoing mail (whether you're using masquerading or not) is generally thought to be "good practice".

The Old "Bind to Loopback" Trick

A number of the responses to the original article described a configuration in which the site leaves the Sendmail daemon running on their machines, but instead of configuring the daemon to listen on port 25/tcp on all of the network interfaces on the system, it's configured to only listen to 25/tcp on the internal software "loopback" interface of the machine. This is the interface with IP address 127.0.0.1 on your system, which is only accessible to processes running on the local machine. Several of the emails I received noted that this is the default configuration for Red Hat and possibly other Linux distributions.

This configuration certainly accomplishes our primary security goal, because the Sendmail daemon is no longer available to an external attacker. On the other hand, this configuration still allows a local user -- or an attacker with access to a local machine as an unprivileged user -- to use the local Sendmail daemon as a potential privilege escalation path to "break root" on the system. Perhaps this is not a huge issue in the home/hobby environment, but it could be a significant problem for large enterprises and high-security environments.

The "bind to loopback" configuration does make things easier for sites upgrading to Sendmail v8.12, because the default Message Submission Process (MSP) wants to deliver outgoing email to a Mail Transfer Agent (MTA) listening on 25/tcp at the loopback interface. Perhaps that's why Red Hat chose this as their default configuration.

The way to configure Sendmail to listen on a specific address and port number is with the DaemonPortOptions in the sendmail.cf file:

# SMTP daemon options
o DaemonPortOptions=Addr=127.0.0.1,Port=smtp,Name=MTA
The configuration line shown here forces Sendmail to listen on the smtp port (usually 25/tcp as defined in /etc/services) on the loopback interface (address 127.0.0.1).

If you prefer, you may also set this option in the m4 macro configuration file. If you are using Sendmail v8.11 or later, then use the following configuration directive:

DAEMON_OPTIONS(`Addr=127.0.0.1,Port=smtp,Name=MTA')
For versions prior to v8.11, use:

define('confDAEMON_OPTIONS',`Addr=127.0.0.1,Port=smtp,Name=MTA')
In either case, the sendmail.cf file you generate should have DaemonPortOptions set appropriately.

Local Alias Expansion

A number of people wrote to say that my configuration suggestions had "broken" aliases they had set up on their local systems. For example, several sites had a local alias set up for root so that this email would go to the specific admin for that machine. Once the system was reconfigured per my instructions, the alias was no longer being resolved and email was going to unexpected places.

Again, this is "expected" behavior, though maybe not desirable. Alias expansion is handled by Sendmail's "local delivery" mailer. However, the configuration in the previous article turned the local machine into a simple mail relay, completely bypassing any attempt at local delivery on the system. This means that alias expansion will never happen.

I would argue strongly that relying on specific aliases configured on individual client systems scattered throughout your organization is poor configuration practice. You are administratively much better off centralizing your aliases on your primary mail servers wherever possible.

Still, perhaps you don't control the central mail servers or have some other good reason for needing to use the local aliases file. In this case, you must run a mail server on the local machine to handle "local delivery" -- at least as far as expanding an address from the local aliases file and then delivering the email to its final destination on some other host. This is probably another good use for the "bind to loopback" configuration described in the previous section, since there's usually no reason for the system to ever accept incoming email from outside the machine.

Conclusions

Masquerading is clearly a useful addition to the concepts I covered in my original article. Note that you will typically use masquerading on your mail servers as well, since you would like hostnames to be hidden on all email originating at your site.

I admit to being highly ambivalent about running the Sendmail daemon bound to the loopback interface only. This configuration may make sense in SOHO situation where you might not have an external mail server that you can use as a relay, or in the case where you need to do local alias expansion on the machine. In an enterprise-type environment, however, I prefer to simplify things by disabling the Sendmail daemon on all but my central mail servers.

Hal Pomeranz (hal@deer-run.com) is the founder and technical lead for Deer Run Associates, a consulting company in the San Francisco Bay Area. He has been a Sendmail wrangler for more than 15 years.