Postfix - The Sendmail Replacement, Part II

November 22, 2000 - I've written about Postfix before, over a year
ago, and since then it has gotten even better. I must confess that I've been using
the 31 Dec. 1999 release on my servers until last week, which, while extremely stable,
lacks a lot of the features now available in current snapshots of Postfix. Postfix
is now more useful than ever as a gateway mail server. I'll cover some
of the more interesting available features and how you can use them to secure
and protect your email infrastructure. Most of these features are actually quite
old, but are probably news to most users.

This article was written using Postfix snapshot 20001030. Since then several
things (like virtual) have changed, making some points in this article
incorrect.

Check_recipient_access

This is probably the best way of restricting incoming email to valid email
accounts only. Let's assume you have a decent-sized corporate LAN based on Windows
and are using Exchange server for email. Exchange can only validate incoming
email based on the domain, not the user, and since it will attempt to deliver
the email for 48 hours, your system can get quickly clogged up - with
no easy way to clean it out. Place your Exchange server behind a firewall so
no one on the Internet can connect to it directly, and then place a Postfix server
on the public side. Add this to your main.cf:

You will also need to create the hash file. The following command will do so:

postmap /etc/postfix/access

You could also use the generic access file, but splitting it up allows for extremely
selective access controls. You can then have the mail delivered locally or forwarded
to another (internal) system. If an email is sent to an email address not listed
specifically, and the domain is covered by a reject rule, the sender will receive
an email with an error like,

You can also specify a custom error such as "useraccount does not exist."
However, a spammer could theoretically use this to build an address list by simply
testing all the email addresses - those that generate an error message do not
exist, and those that do not generate one do exist.

Virtual

This feature can be used as intended, for having virtual users (i.e.,
if you handle multiple domains and more than one wants a webmaster@ email address)
as well as for protecting internal servers.

If incoming email does not match a virtual user, mapping it is sent to another
address, in this example a local user called "bounce-local." It may
then be blackholed to /dev/null, simply bounced (no such user), or sent to an
admin email account - where it is deleted or forwarded to the correct person,
if an obvious typo was made in the address, or whatever. You can also use a database
backend instead of a hash or dbm file. This is definitely the way to go for
large installations. See man virtual(5) for more information. Simply use the
same machine as the outbound mail server (i.e., smart host) and it will rewrite
the email addresses outgoing from @internal-mail.example.org to @example.org
(or whatever you want).

Local_recipient_maps

This keyword lets you allow only local delivery of email to valid users
and/or definitions in the aliases map. Thus any email bound for a nonexistent
user gets bounced immediately with an error message saying the user does not
exist. This is useful if you the postmaster do not want to receive as many error
messages. Potentially, however, an attacker could use this to find valid names
(anything valid won't generate an error). This is probably most useful for large
installations such as ISPs and large corporations. An additional consideration
would be to use relocated_maps. Simply put this in your main.cf:

local_recipient_maps = $alias_maps unix:passwd.byname

This will accept any email defined in aliases or for user accounts in the password
database.

Relocated_maps

This is an ideal feature for large companies that want to remap users without
too much trouble. It allows you to specify the original email address and
the new email address. For example, user joebob goes to another ISP instead of
forwarding all their mail, which results in senders not realizing it has changed.
They get an error message specifying the new email address. This can be
used for wholesale domain moves as well. Simply add the following to your main.cf:

relocated_maps = hash:/etc/postfix/relocated

Then put the email address, username or domain name, followed by
the email address or domain name, and anyone sending email in will get a nice error
telling them the new address. See man relocated(5) for more information.

Blocking Spam

This is probably one of the favorite features for administrators; under Postfix
it is trivial to implement. Simple add the following to your main.cf:

maps_rbl_domains = rbl.maps.vix.com, dul.maps.vix.com

The rbl is the real-time blackhole list, basically a list of known spammers
and open relays that spammers use. The dul is the dialup list. Generally speaking,
you shouldn't be receiving to much email directly from dialup users, i.e.,
people using their own servers. However, quite a few legitimate users do set up
their own email servers for use on dialup links, and blocking them inadvertently
may be a problem.

Database Backends

One thing I really love about Postfix is the ability to use databases instead
of flat text files or hash and dbm files. Currently only MySQL is supported,
but that is more than sufficient for most users. You must first compile in support
for MySQL. See the "MYSQL_README" file for more information on this.
Then you simply create a table in the MySQL database of usernames, virtual
mappings or whatever. The cool thing is, this allows for very efficient sharing
of configuration files between servers; and since you can specify multiple MySQL
servers, you can replicate the database and avoid a single point of failure as
well as being able to vary the order the databases are listed in on various
servers, as a simplistic form of load balancing.

MySQL has plans to add database
replication to its available features. For now, you will have to create your
own solution, such as a simple tool that connects to and updates all the databases
at once. The configuration is reasonably simple. In your main.cf, put something
like,

This would allow you to have a table called "mxaliases" in the database
called "customer_database," where the field "forw_addr" matches
and where the "status" field is set to "paid" (so you can easily block
email to customers who don't fork over). The really useful thing is that you
can easily update configuration files on the fly. As soon as it is updated in
the database, it's ready to go. Additionally, this makes giving users control
over their own accounts much easier. A Web hosting provider could easily let
people handle virtual user mappings on their own domain, for example, through
a cgi interface.

TLS

Transport Layer Security is to email as SSL is to Web browsing. TLS allows
you to encrypt email transfers from server to server, but more importantly, it
allows you to add authentication to the mail server. Instead of having to allow
access based on IP and hostname, you can use usernames and passwords. That way
people can connect securely from off-site - while using dialup on the road - and spammers are not able to use you as a relay.

There is an add-on TLS package
for Postfix (see URL at bottom) available from Germany. (Germany is very pro-encryption;
the federal government has even gone so far as to sponsor GnuPG development.) TLS
is becoming more common now that the RSA patent has expired. Red Hat 7.0 ships
Sendmail configured for TLS out of the box.

Regular Expressions

Postfix supports the use of regular expressions for header rewriting and other
neat tricks. There's support for basic regex (regexp), and support for perl-compatible regular expressions (PCRE). The first are simpler. To use them, just
put this in your main.cf:

header_checks = regexp:/etc/postfix/header-checks

And then add rules to your header-checks file; the target can be REJECT,
OK or a custom error.

See man regexp_table(5) for more information. You can also use PCRE by simply
specifying pcre: instead of regexp: in your main.cf. The rules are basically
the same, except that the syntax used for pattern matching is a bit more advanced.

/^friend@(?!my.domain).*$/ 550 Stick this in your pipe $0

See man pcre_table(5) for more information.

Summary

Postfix is ideal for large installations, with its database backends and extremely
tight control of mail delivery. Additionally, it supports numerous security features,
such as TLS and even the ability to specify which users are allowed to send
mail off-site and which aren't - again, in a very selective manner. Qmail has
quite a few of these features, but has one significant problem: The license makes
it extremely difficult to distribute in a binary format, which is what most
people want.

Postfix, on the other hand, comes under the IBM Public License, which
is surprisingly considerate to end users. My real favorite is the simplicity
of configuration. An average main.cf is under 30 lines of configuration directives.
Hopefully more vendors will start shipping Postfix with their distributions.