ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


Postfix: A Secure and Easy-to-Use MTA

by Glenn Graham
08/21/2003

On March 3rd, 2003, Internet Security Systems, in cooperation with the Department of Homeland Security, issued a warning regarding a hole found in Sendmail. Sendmail, of course, is responsible for handling over half of the world's e-mail traffic. The warning, echoed by CERT, warned system admins that any version lower than 8.12.8 was vulnerable to a serious root exploit. I heard the warning loud and clear, so I wasted little time upgrading each system on our network.

Sendmail has a long history of security holes, most of which have been thoroughly documented on security sites around the world. Why do people continue to run Sendmail? The majority of my systems used to run Sendmail compared to the minority that ran other MTAs such as Postfix or Qmail. Sendmail isn't easy to configure. It lacks a user-friendly front end. It certainly doesn't come ready to use or with easy-to-understand documentation. Is Sendmail still used because it ships as the default mailer with almost every flavor of Unix? Whatever the reason, many would agree its time to adopt a more user friendly mail transport agent.

Welcome to Postfix

Postfix was developed as a replacement for Sendmail and is known to compile on almost every flavor of Unix including Mac O/S X. Wietse Venema, program founder and security specialist, several years developing the application while working as a researcher at IBM's T.J. Research lab. Postfix is the free version of IBM's commercial Mailer, Secure Mailer. It was released in 1998 and dubbed IBM's Christmas present to the Internet. Postfix became especially popular during the Linux revolution by enthusiasts who were looking for open source code that would compile on a free operating system.

Related Reading

The Complete FreeBSD
Documentation from the Source
By Greg Lehey

Postfix attempts to be fast, easy to administer, and secure, while at the same time being compatible enough with Sendmail so as not to upset existing users. Thus, the outside has a Sendmailish flavor, but the inside is completely different. With this in mind, let's take a closer look at Postfix.

Postfix has a unique internal structure that supports SASLv1/v2, SSL/TLS, DB3, MySQL and LDAP. The application runs in a chrooted environment, and upon execution, chroots (jails) the mail queue and daemons. First time users will benefit from a single, easy to understand configuration file written in plain English, unlike the archaic, cryptic Sendmail counterpart. Most defaults are set to sensible values, allowing you to configure only two or three parameters prior to initial use. Advanced users will benefit from hundreds of additional options including a wide range of add-on software allowing enhanced versatility.

Every mail server, or Mail eXchanger, must have a DNS entry for each domain for which it receives mail. These are called Exchange records or MX entries. They are commonly listed as primary and secondary, each one instructing the domain system to send SMTP traffic destined for some domain to the primary exchanger. In the event delivery to the primary exchanger fails, a secondary exchanger will queue any remaining messages. For more detailed information regarding MX records, please see the DNS manual.

The Postfix receiving cycle consists of seven steps. An in-depth explanation is available through the Postfix website.

Installation

Before we begin, we need to remember that Postfix uses several Sendmail-specific filenames such as sendmail, mailq, and newaliases. These are overwritten during installation, so we need to back these files up prior to installing Postfix. Some operating systems, in particular the *BSDs, come packaged with MailWrappers that allow you to wrap a number of mail packages into one, thus providing the luxury of editing mailer.conf with site-specific paths to existing binaries. For more information see man mailer.conf.

% mv /usr/sbin/sendmail /usr/sbin/sendmail.old
% mv /usr/bin/mailq /usr/bin/mailq.old
% mv /usr/bin/newaliases /usr/bin/newaliases.old

Throughout this article, I'll use examples from the FreeBSD Postfix port installation. Alternately, if you are compiling from source, download Postfix from any number of global mirrors, then uncompress the file to src.

Next, if Sendmail is running, stop it. Also, remove any Sendmail specific security or sanity checks from your cron. Save your current Sendmail configuration files, such as aliases, virtusertable, and access for later reference. The FreeBSD port installs the sendmail binary under /usr/local/sbin/, where it used to exist under /usr/sbin/. To conform with existing scripts, I suggest making a symlink from /usr/local/sbin/sendmail to /usr/sbin/sendmail. Most source installations install under /usr/sbin/

If you are installing via the FreeBSD port, make will spawn an ncurses-based GUI where you may add compilation options such as support for SSL/TLS, SASL, DB3, MySQL, and LDAP. This is especially advantageous for those planning to include add-ons such as phpMailAdmin or other apps requiring LDAP/MySQL compiled support. Users requiring only basic functions may bypass this option and continue with make.

The install target is an interactive script that adds other options such as postfix users, groups, and file locations. The defaults should suffice for most users.

BSD users should keep in mind that make world will reinstall Sendmail binaries, over-writing the Postfix installation. Remember to keep a current copy of your Postfix binaries and config files in the event you plan to make world.

Configuration is accomplished through a single, easy to understand configuration file. The default configuration path is usually /etc/postfix, while the default FreeBSD port installs under /usr/local/etc/postfix. By editing main.cf, a few options need be changed to suit your system prior to running the application:

These are later referenced in the sample configuration file.

By default, Postfix looks to /etc for the aliases.db file. Depending on where your aliases and aliases.db files are located, you should make a symlink to /etc. The location of this file may be configured under main.cf, with the alias_maps directive. To initiate your aliases database, run the standard Sendmail command newaliases. The aliases file uses the standard Sendmail format. Note that attempting to run Postfix without aliases.db in the path will cause an error.

To start Postfix, run:

% postfix start

To stop Postfix, run:

% postfix stop

Anytime you make changes to main.cf, restart Postfix by running:

% postfix reload

Next, let's test our server by issuing a telnet connection on port 25, then send some common mail commands (like those sent by an SMTP client) to the server. After each command is issued, the mail server should respond with an acknowledgment.

command: telnet machine1.domain.com 25
response: Trying 209.58.173.10...
Connected to machine1.domain.com
Escape character is '^]'. 
220 machine1.domain.tld ESMTP Postfix
(Connected to machine1.domain.tld identified by ESMTP postfix)

command: HELO test.com
response: 250 remotehost.domain.com

Machine1.domain.tld responds by saying hello back to remotehost.domain.tld by doing a reverse dns lookup. This helps prevent host spoofing.

command: MAIL FROM:
johnny@test.com
response: ok

The server responds that the email address johhny@test.com is acceptable and issues an ok.

command: RCPT TO: glenn@localhost
response: 250 ok

The server recognizes glenn as a valid system user and issues another ok reply. If the recipient does not exist, the server would issue a user unknown response.

command: DATA:
Type in the data of the mail message you wish to send to
glenn.  End this message with a . after a
carriage return on a line by itself

command: . 
response: 250 Ok: queued as EAAD3167

The mail message has been queued for delivery to glenn with the ID: EAAD3167.

command: QUIT
(Issue the quit command to end the connection)

Use a simple mail reader, such as pine, to check the user's mail on the local system to ensure delivery. In the event mail is not received, check that aliases.db resides under /etc and that a user exists under /var/mail. Some archaic systems require the mail drop to be created manually. This is accomplished by doing

% touch /var/mail/user; chown user:postfix /var/mail/user

If syslogd logs mail messages to a specific logfile such as /var/log/maillog, you should tail this file to ensure proper delivery or to check for errors in configuration.

Next, try sending a test message to a local user on the system from another host on your network, for example, user@fullyqualified.domain.com. Your message should arrive without error.

Setting the Production Environment

If you're running Postfix in a production environment, you'll need to add some additional configurations such as a Primary MX, Virtual Domains, Host Relays and a Secondary MX. Some of these options require building a hash style database. Postfix uses a utility called postmap, a replacement for makemap with a similar syntax.

Primary MX entries

If your machine accepts mail for domains outside your network, setting the primary MX entries correctly is a critical component in the Postfix configuration. This is accomplished by editing main.cf and appending to the end of the file:

relay_domains = $mydestination, /usr/local/etc/postfix/relay-domains

Edit the file relay-domains according to this format:

another_domain.com
second_domain.com
third_domain.com

Secondary MX entries

In the event your server is used as a secondary exchanger as defined in the DNS record (MX), you may define allowable domains by editing main.cf and adding the line:

relay_domains = $mydestination the.backed-up.domain.com

You may optionally choose to allow the world to MX through your host. Edit smtpd.cf, then add the line:

smtpd_recipient_restrictions = permit_mx_backup

Remember to reload Postfix after changing main.cf.

Virtual hosting

Virtual Hosting is the ability to receive and redirect mail for a user of another domain, not our own, to a local user or a user on a remote system. For example, joe@foo.com might redirect to joe@localhost, or joe@foo.com may also redirect to joe@another_domain.com.

Creating a Virtual Domain is accomplished by editing main.cf and appending to the end of the file:

virtual_alias_maps = hash:/usr/local/etc/postfix/virtual

Edit the file virtual according to this format, the same as of virtusertable under Sendmail:

user@domain.com         
user@localhost
# or user@remote.domain

Then, hash it to a database.

% postmap /usr/local/etc/postfix/virtual < /usr/local/etc/postfix/virtual

Relay Domains

If you allow your host to act as an SMTP relay, you need to configure the relay options under main.cf. Under the section Trust and Control, look to mynetworks for a list of variable options. In this example, we allow relaying based on two network subnets. This means that hosts within the class C ranges of 168.100.189.0 and localhost 127 can relay.

mynetworks = 168.100.189.0/24, 127.0.0.0/8

If you run into problems or require additional configuration sets, I suggest consulting the Postfix FAQ.

Example configuration

# Global Postfix configuration file. This file lists only a subset
# of all 250+ parameters. See the sample-xxx.cf files for a full list.
# NOTE - CHANGE NO MORE THAN 2-3 PARAMETERS AT A TIME, AND TEST IF
# POSTFIX STILL WORKS AFTER EVERY CHANGE.
queue_directory   = /var/spool/postfix
command_directory = /usr/local/sbin
daemon_directory   = /usr/local/libexec/postfix

mail_owner = postfix
myhostname = bar.foo.com
mydomain   = foo.com
myorigin   = $bar.foo.com

unknown_local_recipient_reject_code = 450

# Here is the MX (mx) stuff
relay_domains = $mydestination, /usr/local/etc/postfix/relay-domains

# The aliases
alias_maps     = hash:/usr/local/etc/postfix/aliases
alias_database = hash:/usr/local/etc/postfix/aliases

debug_peer_level = 2
debugger_command = PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin \
	xxgdb $daemon_directory/$process_name $process_id & sleep 5

sendmail_path   = /usr/local/sbin/sendmail
newaliases_path = /usr/local/bin/newaliases
mailq_path      = /usr/local/bin/mailq

setgid_group    = maildrop

manpage_directory = /usr/local/man
sample_directory  = /usr/local/etc/postfix/samples
readme_directory  = no

# Here is the Virtual User stuff
virtual_alias_maps = hash:/usr/local/etc/postfix/virtual

# Allow local and remote network to relay through this machine
mynetworks = 168.100.189.0/24, 127.0.0.0/8

Start scripts

Postfix uses the same start parameters as Sendmail, so most existing start-scripts should suffice. In the unlikely event your sendmail-ish scripts fail or hang, try starting Postfix from rc.local or, under BSD, /usr/local/etc/rc.d/postfix.sh. The syntax is:

% /usr/local/sbin/postfix start &

Summary

Postfix is a robust, secure MTA. I was impressed with the ease of installation, well-defined documentation, and its ability to receive and relay mail without complex configuration. I've compiled Postfix under Solaris, various flavors of BSD, Slackware, and Red Hat. A wide range of add-on software including phpMailAdmin helps add an additional layer of functionality. Today I see Postfix as a major contender in the race for secure E-mail communications.

Glenn Graham has been working with telecommunications since 1977.


Return to the Linux DevCenter.

Copyright © 2009 O'Reilly Media, Inc.