Cover V06, I03
Article

mar97.tar


Customizing Sendmail

Lars Magnusson

Sendmail is a program that has always given its administrators mixed feelings. It inspires both hatred and amazement, often at the same time. Notwithstanding this love/hate relationship, sendmail is without question the most widespread SMTP Mail Transport Agent (MTA) on the Internet today. None of its competitors are even close to it. The purpose of this article is to describe how to create a simplified local sendmail configuration file that handles different types of traffic. I will also explore some very useful features that are often forgotten or neglected in the ongoing discussion of sendmail's pro and cons.

Security

In addition to being complex and cumbersome, sendmail is often regarded as unsecure. However, I have yet to see an alternative that allows the same flexibility and adaptibility. The challenge is to handle its inabilities in a secure way and use it as efficiently as possible, without compromising the basic security and reliability.

It can't be denied that sendmail has been the culprit of many Internet incidents including the infamous Internet worm in 1988. Many of these incidents have resulted from using the sendmail program supplied by the operating system vendor, which may lag behind publicly available sources with respect to fixes of security bugs. A better solution is to obtain the source code from one of the archive sites, then compile and install it locally. (The UIUC IDA Sendmail version 5.65c is available from ftp.uu.net and BSD V8 sendmail can be obtained from ftp.cs.berkeley.edu.)

Given the vulnerability introduced by Internet connectivity, I feel that it is also preferable to isolate systems from direct Internet contact, either by using a firewall or by using a dial-up connection for mail transfers. By using this approach, you automatically distance sendmail from Internet hazards. The firewall should provide a proxy process, isolating the MTA from direct connection with the Net. That is, I do not run sendmail on the firewall, but rather run a simple, stupid process that passes the messages along to the MTA inside the firewall.

A dial-up connection through a UUCP feed is considered by many to be an outdated method. From a security point of view, however, it is a very good solution if mail only is allowed through the feed, and access by the remote host is limited to basic spool directories. Many sites in need of high-security standards should take a closer look at this approach. Assuming reasonable service from the ISP, the UUCP approach is only a minor inconvenience to users, delaying mail half an hour or so. Most users will never notice the delay.

Whether you use a firewall or UUCP to provide the level of security you need for your site, it is also a good idea to monitor the sendmail newsgroups as a means of keeping abreast of the latest security issues associated with sendmail operations. Many UNIX security books also touch on sendmail security issues.

Configuration

Sendmail is used to prepare mail for distribution, both internally and for the outside world, with an underlying objective of insulating users from email addressing quirks. The easiest way to accomplish this is to designate one system as the local sendmail hub or mail gateway.

The major drawback of the hub or gateway setup, however, is the reliability of the MTA system. Using this approach, I concentrate all communications through one link, thereby creating an undesirable single point of failure. But, compared to the overall advantages, it is an acceptable price to pay, especially as the use of a central MTA, or mailhub, provides some benefits when configuring the MTA.

Many system/mail administrators were once horrified when they came across the sendmail.cf file supplied with the sendmail distribution or as part of the vendor supplied system. These files were large, complex, and daunting. The distribution sendmail.cf files, however, were made to handle a non-mailhub configuration, and therefore had to handle all conceivable mail situations associated with direct Internet connections that were the norm.

Today, most of the external sendmail complexity is handled by the ISP. Local sendmail configuration only needs to deal with "special cases," rewriting odd local mailer addressing to a more normal format and vice versa. It is possible to dispose of the complicated, all-purpose .cf file and use a more simplistic approach. Those of you that have read Sendmail (Costales, Allman, and Rickert, 1993, O'Reilly & Associates) have most likely seen the minimalistic sendmail.cf (client.cf) presented in the book. That .cf file handles only Ethernet-based connections, but can easily be modified to handle other types of traffic. The mailhub .cf file presented in this article is just such an extension of the minimalist example in the O'Reilly book. (The sendmail.cf example file is available from: ftp.mfi.com in /pub/sysadmin.)

The balance of the discussion is separated into three threads. The first is the use of macro variables to generalize and to clarify the script. The second thread shows how to insulate users from having to know how Internet mail interacts with other parallel mailing systems, such as X.400. The last thread looks briefly at address handling for UNIX mailers such as UUCP.

Macros

There are two levels of macro usage associated with sendmail: simple variable assignments within the .cf file, and more complex, external M4-based macros. There is considerable discussion of M4-based macros in the Sendmail book, but I lack good examples on how to use them. For the sake of simplicity, I will use an example feeding one ethernet-connected system and two UUCP sites, using only macro assignments within the .cf file. I will not discuss the overall structure of the sendmail.cf file here, but rather look only at the lines that are of direct concern to us. Please refer to the O'Reilly book for additional details.

I named these hosts "dept1" on the local Ethernet, plus "dept2" and "friend.com," both reached via UUCP. Although located at different sites, the first two hosts are internal to the organization, while the latter is an external neighbor that I'm helping out.

The rule lines for these three hosts, found in Ruleset0, will look like this:

R$*@$=dept1.$*          $#ether $@$2 $:$1<@$2.$3>
R$*@$=dept2.$*          $#uucp  $@$2 $:$1<@$2.$3>
R$*@$=friend.$*         $#uucp  $@$2 $:$1<@$2.$3>

The first column is the pattern that sendmail tries to match within the address and the second column defines what the address will look like after the rewrite. The R in the first character position on the line indicates that this is a rule line. An optional third tab-separated column may contain a comment, without the usual preceeding # character.

For "dept1," the rule will catch any address in the form of userid@dept1.domain. For example, John.Doe@dept1.beavis.com would fit this pattern. The first $* equals "John.Doe" and the last $* references "beavis.com," while $=dept1 defines a position with a specific text value, "dept1."

After the tab, you'll see the required mailer protocol for this connection, the $# field. Then you see an id-field for the receiving computer, $@$2, where the $2 relates back to the $= -field in the rule column. Last, you see the address part of the rewrite, the $: -field. The $1, $2, and $3 all reflect back to their relative positions in the first column. As a result, the rewrite will be:

"$#ether $@dept1 $:John.Doe<@dept1.beavis.com>"

If I differentiate the userid into its components, for example, R$*.$*@$=dept1.$*, then the rewrite would look like $:$1.$2<@$3.$4. If the site I connect to has subdomains, then I would need a rule like:

R$*@$*.$=dept1.$*       $#ether $@$3 $:$1<@$2.$3.$4>

As you can see, an extra $* to handle the subdomain appears directly after the "@" in first column.

For those not familiar with sendmail, $* equals one or more fields separated with any of sendmail's field separators. Dot and bang are the most common of these. $- matches only one field, while $+ matches many fields.

Once you understand how the rules of the .cf file are built up, you can begin looking for repetitive patterns, or common denominators - situations in which using a macro might be helpful. In the case above, there is either the organization affiliation or the required transport mechanism. In these three cases, I prefer the transport mechanism as the most suitable denominator. There is one Ethernet-based host and two UUCP-based hosts. The macro type I want to use is the class macros, C. I define two, one for each transport mechanism, CE for Ethernet and CU for UUCP.

In the beginning of the .cf file, I therefore include the following lines (remember that online comments can save work later on):

# These hosts communicate with us through Ethernet
CE dept1

# These hosts communicate with us through UUCP
# UUCP-sites must have a simple hostname, no
# top domains here.  Handle those in ruleset
CU dept2 friend

The rewrite of the previous rulelines gives us the following:

R$*@$=E.$*          $#ether $@$2 $:$1<@$2.$3>
R$*@$=U.$*          $#uucp  $@$2 $:$1<@$2.$3>

Now there is one and only one line for each transport protocol. When I start to supply a new site with mail, I just add its name to the macro. No more editing in the ruleset, because that can introduce errors. It also reduces the time needed to add new sites.

As mentioned earlier, this example uses a mailhub, a site that collects mail and then sends it to the smarthost or ISP connecting us to Internet. I usually use two variable macros to control this, one for the transport mechanism and one for the host. To create a variable macro within the .cf file, I use the key letter D in the first character position followed by the macro letter and then the definition, all without spaces. In the macro section of the .cf, I have:

# Type of relay to external smarthost, uucp,
# ether or smtp
DMsmtp

# This is the name of the smart host we deliver to
# We also have a class macro assigned
DRyoursmarthost
CR yoursmarthost

As the last rule in Ruleset0, you'll see the following line, handling all those mails, not matched by preceding rules. Observe that it does a very general match here, taking all addresses that are left.

# To smartmailer for non-local sites.
# Use to be the ISP.
R$*                     $#$M $@$R $:$1

The "$M" is from the value macro DM, and "$R" from the variable macro "DR." From this, I can also deduce that class macros are used in the rule match and value macros in the rewrite.

Special Cases, Odd Mailing Systems

Unfortunately, the Internet isn't the only distribution system of email. X.400 is one major alternative system. In Scandinavia and to some extent in northern Europe and the United States, a system called Memo also exists, mainly connecting IBM systems running MVS.

The x.400 operators still have some way to go to connect themselves internally and to the Internet. Memo used to have two very intuitive gateways to the net, one at Volvo and one at Ericsson Telecom. Unfortunately, these no longer handle traffic to the rest of Memonet. I am going to use one example anyway, since it can give a very clear picture how to hide gateways to other nets with sendmail.

Generally, the necessary rules are placed in the beginning of Ruleset0, but this makes Ruleset0 very cluttered. I therefore prefer to make a special ruleset for these cases. In this example, it is called Ruleset5. To get this new ruleset to work, however, I must first force sendmail to take a tour of Ruleset5, before it proceeds with Ruleset0 translations. The following line in Ruleset0 accomplishes the needed detour.

# We may want some special filters, to handle x.400
R$*                     $: $>5 $1

The $>5 says "go to Ruleset5" and the $* in the first column applies the rule to all addresses, thus making sure that x.400 issues are considered in all cases.

Four rulesets are required for each network in Ruleset5 to catch all possible patterns. Additionally, the example includes another rule that allows other sites to gateway x.400 mail through our mailhub.

# x400, identified by the use of
# equal sign "ADMD=400net"
R$*=$-@x400             $1=$2
R$*=$-@$m               $1=$2
R$*=$-@x400.$m          $1=$2
R$*=$-      "$1=$2\"@400net.tip.net

Note that I used the equal sign between x.400's field descriptor and value as the trigger for a match. I used the last equal sign in the address as a pattern match, as seen with $*=$-. The example .cf file makes three assumptions about mail based on the syntax of the address:

addresses with an equal sign must be x.400;

those with "@" must be domain addresses; and

those with "!" must be old-style UUCP "bang" addresses.

Thus, assuming the user client does not impose addressing restrictions, the user can write a mail address as it appears on the mail recipient's business card.

X.400 and domain addresses cannot be mistaken for each other, so why bother the user with deciding which system to use? The system can do this perfectly well, that's "Human Engineering." Of the clients I have tested, mailx and Pine do not allow for this type of mail hiding, while Pegasus Mail handles it quite well.

Memo, similar to MS Mail, has a dot-separated three-field address, such as eri.etx.etxxxx. The first field is the organization, the second is the suborganization, and the third is the userid. Assume that I don't have any users in my organization with three field usernames, but that all three field addresses are Memo addresses. I can then catch them with following rule:

R$-.$-.$-            $1.$2.$3@memo.ericsson.se

Or, I can do what I did with Memo-users at a previous employer. I wanted the user to be visible within our organization domain, instead of having them under the Ericsson domain. A rule like the following fixed that:

R$*@$=memo.amu.se    dafa.amu.$1@memo.ericsson.se

Thus, mail to amuxxx@memo.amu.se was rerouted to the Memo user, dafa.amu.amuxxx, through the Ericsson gateway, giving the user a more normal Internet address and hiding the more complex memo address. If you have a lot of traffic going to another email network, you can simplify access to these networks for your users in a similar manner.

The Envelope

Sites that use only UUCP for email transfers often have problems with domain-style addressing, because the underlying rmail process expects only bang path addresses. The last part of the example .cf file that I am going to look at handles the necessary translation of domain addresses to bang paths for UUCP transmission.

Handling this case is relatively easy. If you look at a UUCP mailer directive, found in the .cf file, you see this:

Muucp,  P=/usr/bin/uux, F=msDFMh, S=13/33, R=23,
A=uux - -r $h!rmail ($u)

In the end of the first line, there is an S=13/33. This handles the rules for the sender address, signifying that Ruleset13 is to be used for the envelope and Ruleset33 for the address. In Ruleset13, I want sendmail to give a bang address that rmail accepts. In Ruleset33, I supply a domain address, so the recipient can reply to me.

# make a bangpath
S13
R$=w!$+          $2            Remove hostname
R$=$m!$+         $2            Remove domain
R$=$m.$+!$+      $:$2!$3       Remove domain
R$=U!$+          $:$1.$j!$2    If UUCP, add hostname
R$-              $:$j!$1       If user, add hostname

# Convert uucp sender (From:) field (Letter)
S33
R$-              $1@$m         If user, add domain

This set of rules has worked for me at several installations. Depending on how your ISP handles this type of address, however, you might need to change the format in Ruleset13 to conform to the ISP's requirements. You can test this by running sendmail with the command:

sendmail -bt -d21.12 -Cnew_file.cf

This turns on debugging, sets the configuration file to new_file.cf, and then displays the debug test prompt, ">". We can test the new rules in new_file.cf by entering 13 mtv.com!john.doe at the ">" prompt. Debug mode tests this address and gives a detailed trace of the conversion.

Conclusion

Sendmail is a beast, but when used in a constructive way, it can be a pleasant one. As shown here, taking a simplified approach for the configuration of your mailhub and allowing the ISP to handle the more complex general cases works quite well. Use of M4 macro configuration files is quite possible, but I still prefer to rewrite the .cf file. I feel this approach gives me more direct control. By using the debug mode -bt with or without the extended debugging mode level -d21.12, I can quickly find any pitfalls that might hinder correct mail flow.

About the Author

Lars Magnusson received a B.Sc. in Geology from Gothenburg University in Sweden (1980) and a M.Sc. in Petroleum Exploration from Chalmers University of Technology (1984). He has worked with mining geology/geophysics in Sweden and Greenland, but has also worked as a sys admin, system manager, and teacher in Sweden, Greenland and Denmark. He is now working as a consultant within the areas UNIX, Internet, and email.