Improving Sendmail Security by Turning it Off

Sendmail is, for better or worse, the de facto standard Mail Transfer Agent (MTA) for Unix systems. While many tomes could be written about the pros and cons of replacing Sendmail with an alternate MTA-- such as Postfix, Qmail, or Exim-- the reality is that most Unix shops have a huge installed base of machines running Sendmail daemons as part of their default install. However, the surprising news is that the vast majority of these systems do not need to be running a Sendmail daemon at all.

This is likely to become a critical security issue for sites in the near future. The Sendmail buffer overflow exploit announced in March is almost certainly going to be programmed into an automated worm within the next six months. Such a worm could do for Unix systems what Code Red did to the Windows world-- simply because there are so many potentially vulnerable Unix systems on the network today. Shutting off the Sendmail daemon on 99.9% of the systems in your environment would greatly reduce the potential impact of such a worm.

The Role of the Sendmail Daemon

The reality, however, is that the Sendmail daemon on a machine is only responsible for two things:

Listening on port 25/tcp for incoming messages from outside of the machine Flushing the local queue of unsent messages on a periodic basis

Having a Sendmail daemon listening on 25/tcp is what opens the system up for remote exploits like the recently announced buffer overflow issue. But note that the system only needs to be listening on 25/tcp if it is actively expecting to receive email messages from other systems. However, the only systems on the network that receive external email are the machines that are acting as mail servers and mail relays. A given site will typically only have a small handful of these machines (many of which are Windows machines running Exchange these days anyway). The other 99.9% of the systems on the network are email "clients"-- that is they may emit email messages from time to time, but never expect to receive a message from another machine. On these machines it is probably best to simply disable the Sendmail daemon altogether in order to completely eliminate the potential for remote exploits.

But what about outgoing email generated from the local system? It turns out that Unix email clients send outgoing email by invoking the Sendmail binary directly off the disk. This new Sendmail process simply attempts to deliver the message to its next hop directly, rather than communicating with the local Sendmail daemon running on the system. So while it is necessary to have a proper Sendmail configuration file on each local system, it is not necessary to have a Sendmail daemon running in order for users and processes on the system to send email out of the machine. Actually, the release of Sendmail v8.12 has complicated this simple view of the world somewhat, as we will discuss later in this article.

Remember, however, that the local Sendmail daemon is also responsible for managing the local queue of unsent messages. For example, when a user creates an email message, the local Sendmail process invoked by the user's mail client may not be able to reach the next hop mail server immediately. This message is then queued in the system's local mail queue. If the local Sendmail daemon on the system is shut off, then there is nothing to process the local mail queue, and this unsent message will never be delivered! So when shutting off the local Sendmail daemon to avoid remote exploits, it is important to remember to arrange for some mechanism to flush the local mail queue on a regular basis.

So let's tackle all of these issues. First we'll look at how to manage the local mail queue, and then discuss appropriate Sendmail configurations for "client" type machines-- both for older versions of Sendmail and the new v8.12 releases.

Dealing with the Queue

/usr/sbin/sendmail -bd -q15m

The -bd flag is what tells the Sendmail daemon to listen on 25/tcp for incoming email. The -q15m flag tells the Sendmail daemon to attempt re-delivery of queued messages every fifteen minutes.

One option is to simply run the Sendmail daemon without the -bd flag. The daemon will still run and flush the queue every fifteen minutes, but it will not actively be listening on 25/tcp for incoming messages. Newer Unix operating systems are making it easier for administrators to configure their systems to run in this mode. For example, starting with Solaris 8 the /etc/default/sendmail file can be used to configure this behavior (set MODE="" ), and RedHat has implemented a similar mechanism in /etc/sysconfig/sendmail (set DAEMON=no ). If your operating system vendor supplies a mechanism for configuring this behavior, then it is probably best to go with the vendor-supported interface.

On the other hand, some Unix systems present only the simple choice of having the daemon running and listening on 25/tcp or not running the daemon at all. Certainly the administrator could hack the appropriate boot script to remove the -bd flag from the Sendmail invocation, but it may be more maintainable in the long run to simply shut the daemon off altogether. But how to make sure the queue gets flushed if the daemon is no longer running? One simple approach is to add a line to root's crontab:

0 * * * * /usr/sbin/sendmail -q

This will run sendmail -q at the top of every hour to attempt delivery of any unsent messages. This is probably a sufficient interval, since the queue should be empty under normal circumstances anyway.

Local Sendmail Configuration

include(`cf/m4/cf.m4') define(`__OSTYPE__',`') FEATURE(`nullclient', `mailhost')

The second argument to FEATURE(`nullclient') is the name (or IP address) of the mail server outgoing email should be relayed to. Obviously, you will need to change this hostname to something appropriate for your site.

The other two lines in this configuration also deserve a little explanation. The cf.m4 file contains all of the macro definitions which expand items like FEATURE(`nullclient') into the actual Sendmail configuration language that is used in the sendmail.cf file. The cf.m4 file is found in the Sendmail source distribution under the cf/m4 subdirectory-- be sure to replace the pathname in the first line above with the correct pathname to the cf.m4 file on your system.

The second line defines the OSTYPE macro to be the empty string. Normally, OSTYPE would be set to a string that indicates what OS platform the config file would be used on, and controls various OS-specific parameters (file locations, command line arguments, et al). However, for a simple nullclient configuration, none of that OS-specific information is important so we can just generate a completely generic configuration file that will work on any OS platform simply by setting OSTYPE to null.

In order to generate a Sendmail configuration file for your system from the above macros, simply type the above three lines into a text file taking care to preserve the balanced left and right quotes and making the appropriate changes on the first and third lines for your local environment. Assuming the new file name is nullclient.mc , you can generate a sendmail.cf file with the following command:

m4 nullclient.mc > sendmail.cf

Install the resulting sendmail.cf file in the appropriate location on your system (usually /etc/mail/sendmail.cf , but sometimes just /etc/sendmail.cf ).

Dealing with Sendmail v8.12

The problem is that the default behavior of the MSP is to attempt to deliver outgoing email by talking to the MTA over the system's internal loopback interface. This means that if we shut off the local MTA, then the default MSP will be unable to send email out of the system! This is not a feature.

It turns out that the MSP doesn't have to emit email by talking to the local MTA over the loopback interface. It can talk to any mail server on the network that the administrator desires. In this mode, the MSP is acting very much like the nullclient configuration that we discussed in the previous section. The macro configuration file is only slightly more complicated:

include(`cf/m4/cf.m4') define(`confCF_VERSION', `Submit') define(`__OSTYPE__', `') define(`confTIME_ZONE', `USE_TZ') define(`confDONT_INIT_GROUPS', `True') FEATURE(`msp', `mailhost')

Again, set the pathname on the first line and the name of the machine on the last line as appropriate for your site. The configuration file produced from the above macros should be installed as /etc/mail/submit.cf on your systems.

Note that you can also simply hack the submit.cf file provided by your vendor. Just look for the line that reads

D{MTAHost}[127.0.0.1]

Just replace [127.0.0.1] with the name of your new relay host. For example,

D{MTAHost}mailhost

Save your changes, and you're done!

The split between MTA and MSP is also reflected in how the Sendmail daemon is started at boot time. When using Sendmail v8.12, two daemons are normally started by the system boot scripts:

/usr/sbin/sendmail -bd -q15m /usr/sbin/sendmail -Ac -q15m

The first line looks identical to the normal Sendmail invocation for Sendmail v8.11 and earlier-- this is the MTA process that is listening on 25/tcp for incoming email, and which processes a queue of messages received by this process. The second line invokes a daemon for the MSP. This daemon doesn't listen on any port for incoming messages: its sole duty is to process a separate MSP queue for messages generated on the local machine but which could not be delivered immediately because the MSP's mail relay was unavailable for some reason.

So in v8.12 Sendmail, the MSP has its own message queue and its own daemon for flushing that queue on a regular basis. This means that on email "client" type machines the MTA daemon is completely unnecessary and can be shut off completely. In order to get this to happen, however, it will probably be necessary to hack the default boot script provided by your vendor. I have yet to find a vendor who has a simple configuration switch for disabling the MTA process without disabling the MSP. In fact, most vendors in my experience don't even realize that you can run the MSP without a local MTA.

Conclusion

Of course you will have to still have a process listening on 25/tcp on your mail server machines so that they can receive and process incoming email, and so you must be careful to stay up-to-date on Sendmail security fixes on these machines. Still there's a huge difference between having to rapidly push out a Sendmail security fix to a handful of known critical email servers in your environment, and having to push that same patch to every single Unix system in your environment just because they happen to be running Sendmail in daemon mode by default.

Author's Note: This article provoked so much response from readers that I created a followup article with further information and clarification.