Setting up sendmail on a firewall, Part 2

Unix Insider –

Last month, I started this series on sendmail 8.9.3 with the intention of pointing out the advantages of upgrading to this more secure version that includes antispam and antirelaying features. Little did I know at the time that the release of the Melissa virus would demonstrate the value of using an open source mail system such as sendmail. Accompanying the release of the CERT advisory regarding the virus was a method for filtering out the affected mail with sendmail -- even though sendmail wasn't the target in this case.

Aside from the Melissa virus, some of the systems I support were recently subjected to a surprise audit. The firewall that was running sendmail 8.9.3 thwarted every mail attack, in many cases because the source address was invalid. The auditors made quite an issue over the fact that systems not yet upgraded to sendmail 8.9.3 permitted mail relaying and were subject to spamming. The upgrade is in progress.

To continue where I left off last month, I'll describe the sendmail configuration file and explain the template file that works for me on my firewall. I use a variation of this template in most places with a few changes, depending on how I want to route mail. Generally, I do not recommend that the firewall handle routing to multiple mail gateways; if one of the mail gateways goes down, it can cause a denial-of-service problem on the firewall. I recommend that the firewall just send all mail for the company to one master mail gateway on the internal DMZ. This system can handle subdomain routing. This way, if the mail system gets flooded, other firewall services can still function. To keep things simple, I'll just describe the configuration file for the firewall.

The configuration file

Now comes the fun part -- creating the configuration file. I generate a new one every time I update sendmail to verify that I can create one from scratch, if required. This is not as complicated as it sounds, providing I have a template file that reflects my local configuration. Too often, I have seen sites with a legacy sendmail

<font face="Courier">cf</font>
file that was originally written by an administrator who left the company years ago. This configuration file usually becomes a hopelessly confusing set of redundant and conflicting rules that the current staff is afraid to clean up. I have found it much easier, in the long run, to start from scratch and create a new file. You will have to do this anyway if you are running a much older version of sendmail. While there is effort required in doing this the first time, subsequent releases are much easier because you can use the same template file.

m4 configuration

The open source version of sendmail comes with m4 macro configuration (

<font face="Courier">mc</font>
) template files to create a sendmail
<font face="Courier">cf</font>
file. These files are in
<font face="Courier">/usr/local/src/sendmail-8.9.3/cf/cf</font>
and have the suffix
<font face="Courier">mc</font>
. Using the template file (and keeping it up to date!) makes upgrading to new releases relatively painless. I keep my template files in a special directory and then copy them when I need them. If you are starting with an existing template file, make sure you test its validity by generating a sendmail
<font face="Courier">cf</font>
file with it and comparing it to your production sendmail
<font face="Courier">cf</font>
file. This will let you know if someone has edited the production sendmail
<font face="Courier">cf</font>
file without updating the
<font face="Courier">mc</font>
template file. I have to confess that I have been guilty of editing the sendmail
<font face="Courier">cf</font>
file live, but I usually go back and make sure the
<font face="Courier">mc</font>
file is updated.

Copy the generic template file for your operating system. If you're running Solaris 2x, the file is

<font face="Courier">generic-solaris2mc</font>
. If there isn't a generic template file for your OS, pick one and edit it to change the
<font face="Courier">OSTYPE()</font>
to match your OS (an
<font face="Courier">ls</font>
of the directory
<font face="Courier">/usr/local/src/sendmail-8.9.3/cf/ostype</font>
shows the available operating systems). For example, there is no Linux template file, but there is a
<font face="Courier">linux.m4</font>
file in the ostype directory. Just change
<font face="Courier">solaris2</font>
to "
<font face="Courier">linux</font>
for
<font face="Courier">OSTYPE</font>
. I usually copy this file to the system's name, as in
<font face="Courier">firebox.mc</font>
. You'll need to edit this file for your site's configuration. The example I am giving works on most firewalls I've configured that have to route mail to an internal mail gateway. There are, no doubt, other ways to do the same thing. Chapter 19 in Bryan Costales's book about sendmail has a very useful description of the sendmail m4 macros. It is very important to remember that sendmail expects tabs, not spaces between the fields in the rulesets. If you do a cut and paste, you will have to go back and change the spaces between the fields to tabs.

The remainder of this section describes the

<font face="Courier">mc</font>
file that I would typically use for a firewall. The actual lines from my
<font face="Courier">mc</font>
file are in bold face, and the description of their purpose follows. You could probably use this with modifications for your particular domain (represented here as
<font face="Courier">company.com</font>
).

VERSIONID(`@(#)cbf.mc 8.9.3 (Wizard's Keys) 2/19/1999')

Edit the VERSIONID line to something meaningful for your site. This is not

necessary to make anything work, but it's good housekeeping.

OSTYPE(solaris2)dnl

The next line should be your operating system type. If you're running

Linux, replace

<font face="Courier">solaris2</font>
with
<font face="Courier">linux</font>
. I've configured for both. The

<font face="Courier">dnl</font>
(delete through new line) ending on each line keeps
<font face="Courier">m4</font>
from

inserting blank lines. It isn't necessary, just aesthetic.

DOMAIN(generic)dnl

You can have your own domain file for site-specific configuration

options. A generic file, as well as examples of other domain files, are

provided in the

<font face="Courier">endmail-8.9.3/cf/domain</font>
directory. This file isn't

required, but if you support multiple sendmail configurations at your

site (for example, an external firewall, an internal firewall, an

internal mail gateway, etc.), it can be very useful.

FEATURE in the mc file

This portion of the

<font face="Courier">mc</font>
file is where you can get creative and make sendmail do all sorts of things without you having to write a special rule. Make sure you read up on these features (I recommend you review both Costales's Sendmail and the Sendmail.org site). I'll just go over the ones I typically use.

FEATURE(nouucp)dnl

I don't have any

<font face="Courier">uucp</font>
-type addresses, so I don't see any point in

processing

<font face="Courier">uucp</font>
rules that I don't need; however, there's no harm in

leaving in the

<font face="Courier">uucp</font>
support.

FEATURE(always_add_domain)dnl

It is recommended that this feature be used to force the local or

program mailer to fully qualify mail.

FEATURE(allmasquerade

I use this feature on the firewall to force all mail to appear to

originate from the site's official domain name. However, I don't use

it on the internal mail gateway. You need to use this feature in

conjunction with

<font face="Courier">ASQUERADE_AS</font>
.

FEATURE(masquerade_entire_domain)

This feature forces any host within my domain to appear to come from

the same domain. I don't use this feature internally because I want

to make decisions based on subdomains. To the public Internet, I want

everything to appear to come from my top-level domain.

FEATURE(masquerade_envelope)

This feature causes the envelope to be masqueraded to and is useful for

centralizing error messages on one host. I use this feature on both the

internal mail gateway and the firewall.

FEATURE(smrsh, /usr/local/etc/smrsh)dnl

I run sendmail in a

<font face="Courier">chroot</font>
cell, but a little extra paranoia on the

firewall doesn't hurt. The source for smrsh (sendmail restricted

shell) comes with the release, but needs to be compiled and installed

separately.

<font face="Courier">/usr/local/etc/smrsh</font>
is used instead of
<font face="Courier">/bin/sh</font>
by the

program mailer. To have

<font face="Courier">smrsh</font>
execute a program, it must be placed

in the directory

<font face="Courier">/usr/adm/sm.bin</font>
(or by setting
<font face="Courier">CMDDIR</font>
to something

else in your site-config file).

<font face="Courier">smrsh</font>
will search this

directory to validate a requested program or script and will then

use

<font face="Courier">/bin/sh</font>
to execute that program or script. If the program or

script isn't in the directory, the request is rejected.

FEATURE(relay_entire_domain)

As I described last month, this feature allows any host within my

domain to relay mail through my system. For a private, small company

this approach is fine; for some larger clients with multiple

organizations, I won't use this feature.

FEATURE(blacklist_recipients)

I'm tired of getting mail directed to

<font face="Courier">www</font>
when I don't yet have

a Web server. (I've been a bit busy.) I use this feature to block mail sent to

<font face="Courier">www, nobody,</font>
and
<font face="Courier">guest</font>
. As I mentioned last month, you have to

set up the access database to use this feature.

MASQUERADE_AS(company.com)

Obviously, this is the value I want used for the masquerading

features I defined above.

MASQUERADE_DOMAIN(company.com othername.com)

Use this feature if you're known as many internal domains, but want to

appear to be from the domain you listed in

<font face="Courier">MASQUERADE_AS</font>
.

define

You can define your own macros for sendmail or use the one that are built in.

If you define your own, be careful not to pick a macro name (or letter)

that is already in use! It can cause some unexpected behavior. All

lowercase letters are reserved for sendmail as well as some uppercase

letters. (See Table 31-7 in Costales's Sendmail and also visit

the Sendmail.org site.)

MAILER(local)dnl

You definitely need this feature to deliver mail locally. Although

no users are on the firewall, you still have to be able to have
<font face="Courier">cron</font>

jobs send mail to root.

MAILER(smtp)dnl

You need this feature to be able to process SMTP mail. You can add

other mailers if you use them.

LOCAL RULES in the mc file

This portion of the

<font face="Courier">mc</font>
file is where the (black) magic of sendmail comes in. You can make sendmail do almost anything, if you know how. A word of caution: If there is already a built-in feature to do what you want, use it. Try to avoid the temptation of adding complexity. Don't forget the period (.) after
<font face="Courier">{MyNames}</font>
. MyNames is a variable -- you can call it anything that's not reserved. Also, as I stated before, there must be a tab between
<font face="Courier">{MyNames} . ></font>
and
<font face="Courier">$#smtp</font>
to distinguish between the left side and the right side.

<font face="Courier">LOCAL_RULE_0
R$+  <  @  $*  $={MyNames}  .  >  	$#smtp   $@   mailgate.company.com   $:   $1   < @  $m  >
LOCAL_CONFIG
C{MyNames}company.com  othername.com
</font>

Building the config file

If you've been following along, you should know have a template

<font face="Courier">firewall.mc</font>
file for your system in the directory
<font face="Courier">/usr/local/src/sendmail-8.9.3/cf/cf</font>
. To turn this into a sendmail
<font face="Courier">cf</font>
file, you have to use the m4 macro compiler:

	m4  ../m4/cf.m4  firewall
<font face="Courier">mc</font>
> firewall
<font face="Courier">cf</font>

If everything goes well, your new configuration file will be

<font face="Courier">firewall.cf</font>
. Copy this file to
<font face="Courier">/etc/mail/firewall.cf</font>
. After testing, you can copy or link it to
<font face="Courier">/etc/mail/sendmail.cf</font>
(or wherever your system keeps its
<font face="Courier">sendmail.cf</font>
file) with mode 600, owned by root.

What the heck is this?

It may look like line noise to you, but the following line is actually very important and warrants explanation:

<font face="Courier">R$+  <  @  $*  $={MyNames}  .  >  	 $#smtp   $@  mailgate.company.com   $:  $  1<  @  $m  >
</font>

I was really trying to avoid explaining rulesets, as it has been covered done at length in Sendmail and other places. To summarize, here are some important things to remember:

  • The left side (in this example,

    <font face="Courier">R$+  <  @  $*  $={MyNames}  .  ></font>
    ) is evaluated and, if it matches, performs the action or rewrites on the right side (in this case,
    <font face="Courier">$#smtp   $@  mailgate.company.com   $:  $1  <  @  $m  ></font>
    ).

  • Spelling counts.

  • The left side and right side must be separated by a tab, not spaces! If you cut and paste a rule, it will not work unless you replace the space with a tab (cut does not maintain tabs).

  • The local rule that is written has to match definitions in your configuration file. For example, if

    <font face="Courier">C{MyNames}</font>
    isn't defined in your config file, this rule will make no sense. While this may seem obvious, I've seen administrators ask their ISP for a line they can add to their
    <font face="Courier">sendmail.cf</font>
    file to route mail from the firewall. As in any program, it's meaningless to use a variable that has not been defined.

  • Always test the configuration file before you put it in place.

  • The syntax for pattern matching is as follows:
<font face="Courier">$*	match zero or more tokens 
$+	match one or more tokens
$-	match exactly one token
$={MyNames}	match a member of class {myNames}  (defined 
with C{MyNames)

R$+  <  @  $*  $={MyNames}  .  >  	$#smtp   $@  mailgate.company.com   $:  $1  <  @  $m  >
</font>

In this example, if the rule gets "carole.fennelly@morrigan.othername.com" it will match:

<font face="Courier">	$+	carole.fennelly (this becomes the positional variable $1)
	$*	morrigan (this could be null and in fact gets dropped but is $2)
	$={MyNames} othername.com (this would also match company.com).
</font>

Because it's a match, the RHS takes effect. The SMTP mailer is called and delivers to the system: mailgate mail for user "carole.fennelly" that is qualified for my domain ($m).

Testing the configuration file

To test the configuration file, invoke the new sendmail binary you created (

<font face="Courier">/usr/lib/sendmail.8.9.3</font>
) with your new configuration file (
<font face="Courier">/etc/mail/firewall.cf</font>
).

This offline test ensures the basic functionality of your configuration.

	/usr/lib/sendmail.8.9.3  -C/etc/mail/firewall
<font face="Courier">cf</font>
-bt -d35.9

This test will produce a lot of output because I specified a fairly detailed debug level and placed us in the test mode. You will enter the rulesets you want to test along with a sample email address (in bold below).

<font face="Courier">	(output deleted)
	define(M as company.com)
redefine(n as MAILER-DAEMON)
define(D as company.com.)
define(Z as 8.9.3)
define(deliveryMode as b)
define(_ as fennelly@localhost)
redefine(deliveryMode as i)
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
><STRONG> 3,0  user@company.com </STRONG>			(Test your domain)
rewrite: ruleset   3   input: user @ company.com
rewrite: ruleset  96   input: user < @ company . com >
rewrite: ruleset  96 returns: user < @ firebox . company . com . >
rewrite: ruleset   3 returns: user < @ firebox . company . com . >
rewrite: ruleset   0   input: user < @ firebox . company . com . >
rewrite: ruleset 199   input: user < @ firebox . company . com . >
rewrite: ruleset 199 returns: user < @ firebox . company . com . >
rewrite: ruleset  98   input: user < @ firebox . company . com . >
rewrite: ruleset  98 returns: $# smtp $@ mailgate.company.com $: user < 
@ company . com >
rewrite: ruleset   0 returns: $# smtp $@ mailgate.company.com $: user <
@ company . com >
> > <STRONG> 3,0  user@internet.com </STRONG>			(now test an internet site)
rewrite: ruleset   3   input: user @ internet . com
rewrite: ruleset  96   input: user < @ internet . com >
rewrite: ruleset  96 returns: user < @ internet . com . >
rewrite: ruleset   3 returns: user < @ internet . com . >
rewrite: ruleset   0   input: user < @ internet . com . >
rewrite: ruleset 199   input: user < @ internet . com . >
rewrite: ruleset 199 returns: user < @ internet . com . >
rewrite: ruleset  98   input: user < @ internet . com . >
rewrite: ruleset  98 returns: user < @ internet . com . >
rewrite: ruleset 198   input: user < @ internet . com . >
rewrite: ruleset  95   input: < > user < @ internet . com . >
rewrite: ruleset  95 returns: user < @ internet . com . >
rewrite: ruleset 198 returns: $# esmtp $@ internet . com . $: user < @ 
internet
. com . >
rewrite: ruleset   0 returns: $# esmtp $@ internet . com . $: user < @ 
internet
. com . >
><<STRONG> control-D </STRONG>> to exit
</font>

Note that for testing, it isn't necessary to use a valid user in the email address as long as the format is legal. What you want to determine is that mail for your domain is routed to your mailgate system, and mail for an outside domain is delivered to the destination domain. It doesn't matter if

<font face="Courier">user@company.com</font>
really exists -- I'm just testing to see if I'm routing
<font face="Courier">company.com</font>
and
<font face="Courier">internet.com</font>
properly. No mail is generated from the test.

Final thoughts

I really appreciate receiving feedback from readers. While most of it is very positive and constructive, occasionally there will be a comment that is neither. I'd like to take this opportunity to clarify my objectives with this column. I write about technical issues that I have worked on. The methods I present are not necessarily the best or only solutions available. They're my solutions, based on what I've done. Hopefully, you can learn something from the solutions I present. I don't want to get into religious wars over software choices.

There has been enough interest based on part one of this series to justify adding a third column on sendmail. Next month's column will present some testing techniques and "stupid sendmail tricks."

Disclaimer: The information and software in this article are provided as-is and should be used with caution. Each environment is unique and the reader is cautioned to investigate with his or her company as to the feasibility of using the information and software in the article. No warranties, implied or actual, are granted for any use of the information and software in this article and neither author nor publisher is responsible for any damages, either consequential or incidental, with respect to use of the information and software contained herein.

What’s wrong? The new clean desk test
Join the discussion
Be the first to comment on this article. Our Commenting Policies