Deploying Postfix


Copyright 2002, 2003, 2004, 2005, 2006 Andy Barclay
OpenContent License (OPL)

In mid-March, 2003 after sendmail had two root-compromise security
flaws revealed in as many weeks, I decided that I would switch to
postfix for my home mail system. I also wanted to support AUTH.

Version 2.0.7 of postfix has been working well for me since 2003.
In trying to fight the battle against spam, I implemented mailscanner.
Although this worked well, a lot of spam was still getting into my inbox.
I decided to implement greylisting (which worked VERY well, BTW). In order
to do this, I needed the check_policy capability in postfix. That
capability was only available in 2.1 and later, so I decided it was time
to upgrade to the latest version (2.3.6).

If you don't care to build it yourself, then you can simply download the
 postfix 2.3.6 package (available from the web site).

On install of Solaris 9
==============================
# remove existing sendmail
pkgrm SUNWsndmu SUNWsndmr
-all recommended patches installed
-install gcc 3.2
-(if you want gssapi support in cyrus, then download and install
kerberos 5 AKA heimdal-0.5.2.tar)
-download and extract cyrus-sasl-2.1.12
	$ PATH=$PATH:/usr/ccs/bin:/usr/local/bin
	$ export PATH
	$ ./configure --disable-krb4 --disable-gssapi \
		--enable-login
NOTE: if you add  --enable-login, then you will get the LOGIN prompt
on the auth line. THIS IS REQUIRED FOR MANY OUTLOOK CLIENTS.
NOTE: I am using saslauthd to validate the passwords against pam which
checks ldap and local which contain CRYPT style passwords, so, cram and digest
won't work, so I disable them. Your best solution is to go ahead and
compile them, but then simply move the .so files that you don't want,
out of the directory /usr/local/lib/sasl2
-----
cd /usr/local/lib/sasl2
sudo mkdir disabled
sudo mv libcrammd* libdigest* disabled
-----

Make sure saslauthd starts at boot - BEFORE postfix starts.
----
$ saslauthd -a pam
----

Create postdrop group
Create postfix user and group
----
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
----
----
postfix:x:89:
postdrop:x:90:
----
	
-download and extract postfix-2.3.6
	$ make tidy
	$ make makefiles CCARGS="-DUSE_TLS -DUSE_SASL_AUTH -DUSE_CYRUS_SASL -I/usr/local/ssl/include -I/usr/local/include/sasl" \
        	AUXLIBS="-R/usr/local/lib -L/usr/local/lib -R/usr/local/ssl/lib -L/usr/local/ssl/lib -lssl -lcrypto -lsasl2"
	$ make
	# make install
		-accept all defaults

edit /etc/postfix/main.cf
-----
allow_percent_hack = yes
append_at_myorigin = yes
append_dot_mydomain = yes
command_directory = /usr/sbin
config_directory = /etc/postfix
daemon_directory = /usr/libexec/postfix
debug_peer_level = 2
empty_address_recipient = MAILER-DAEMON
mail_owner = postfix
mailq_path = /usr/bin/mailq
manpage_directory = /usr/local/man
masquerade_classes = envelope_sender, header_sender, header_recipient
masquerade_domains = $mydomain
masquerade_exceptions = root,mailer-daemon
mydestination = $myhostname, localhost.$mydomain $mydomain
myhostname = blade.unixpeople.com
newaliases_path = /usr/bin/newaliases
queue_directory = /var/spool/postfix
readme_directory = no
relay_domains = trinnet.net trinnet.com trinnet.org
sample_directory = /etc/postfix
sendmail_path = /usr/lib/sendmail
setgid_group = postdrop
smtp_sasl_auth_enable = no
smtp_sasl_password_maps = hash:/etc/postfix/saslpass
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetowrks, reject_unauth_destination
smtpd_sasl_auth_enable = yes
# AWB - NOTE: Don't use this
# if you do, then auth will be tried as user@$myhostname rather than simply user
#smtpd_sasl_local_domain = $myhostname
swap_bangpath = yes
unknown_local_recipient_reject_code = 450
-----

edit /usr/lib/sasl2/smtpd.conf
-----
# if you want to authenticate against /etc/shadow, you must use this:
# There seems to be no need to add anything to /etc/pam.conf
pwcheck_method: saslauthd
-----

create /etc/mail/aliases
---
root: abarclay
postmaster: abarclay
---

# newaliases

Fire up postfix...
# postfix start

TLS/SSL
=======
Enabling TLS/SSL

1) Generate the certificates
# cd /etc/postfix
# openssl genrsa -des3 -rand /etc/hosts -out mail.unixpeople.com.key 1024
# chmod 600 mail.unixpeople.com.key
# openssl req -new -key mail.unixpeople.com.key -out mail.unixpeople.com.csr
# openssl x509 -req -days 3650 \
   -in mail.unixpeople.com.csr \
   -signkey mail.unixpeople.com.key \
   -out mail.unixpeople.com.crt

6) strip the pass-phrase
# openssl rsa -in mail.unixpeople.com.key \
   -out mail.unixpeople.com.key.unencrypted
# mv mail.unixpeople.com.key.unencrypted mail.unixpeople.com.key

7) Add the following to main.cf
--------------
smtpd_use_tls = yes
smtpd_tls_key_file = /etc/postfix/mail.unixpeople.com.key
smtpd_tls_cert_file = /etc/postfix/mail.unixpeople.com.crt
#smtpd_tls_CAfile = /etc/postfix/CAcert.pem
--------------

Making use of Maildir format
============================
Instead of storing all incoming mail messages for a user in a single file,
(mbox format), this results in storing each message as a different file -
usually in a directory called Maildir in the user's home directory.

Why do this
-----------
No file locking is necessary, so its faster and some mail systems insist
on this format - like Courier - so if you want postfix to co-exist with
some other Mail system, you may have to do this.

Add the following line to main.cf
----------
home_mailbox = Maildir/
----------

Then, postfix will attempt to deliver mail for "fred" to the directory
~fred/Maildir.

Next, you need to make the Maildir directory.

# mkdir ~fred/Maildir
# mkdir ~fred/Maildir/new ~fred/Maildir/tmp  ~fred/Maildir/cur
# chmod -R 700 ~fred/Maildir

What about RBLs
===============
DON'T USE THEM..... I'll explain why in a minute.

RBLs stand for "Relay Blocking Lists", but actually, they have outgrown
that definition.
They work by doing a DNS type "A" record lookup of the IP address with
the specified zone appended.
This example would search the spamcop RBL.
-----
smtpd_client_restrictions = reject_rbl_client bl.spamcop.net
-----
So, if I connected from woody.unixpeople.com (167.216.255.210) to the
mail server, it would lookup an "A" record for:
210.255.216.167.bl.spamcop.net.

Ok, so why do I say not to use these? When I was using these, I had
several cases where legitimate email from users were blocked. I've
even been on the other end and had my email blocked because my
home system is on the DUL... The better solution to this is to
use MailScanner. MailScanner uses spamassassin which does check the lists,
but being on the list is simply another attribute that is considered when
deciding whether the email is spam or not.

Virtual Users
=============
I host several e-mail domains on my server. I want individual users
to be able to control their own accounts.

One solution to this is to route all e-mail for a single domain
directly to a single user account. Then the owner of that
account can fetch the e-mail via imaps or pops, and then use
procmail to put it in the correct mailboxes.

In order to do this, I added the following line to 
/etc/postfix/virtual
----
@objectmatrix.com			krish
----

Then I had to build the maps
# postmap /etc/postfix/virtual

Then add the following line to /etc/postfix/main.cf
-----
virtual_alias_maps = dbm:/etc/postfix/virtual
-----
NOTE: Often is "hash" rather than dbm. Use "postconf -m" to see which
algorithms are supported.

Relaying through a specific server
==================================
I just noticed that after 5 days, I'm getting mail returned
from aol.... Trying to telnet to the mail port on the MX, I get
a message that says that because I'm in a dynamic range, I
can't send email to them.... ouch!

Ok, need to send ALL mail though the sbc mail server. In order to do that,
need to use the postfix "transport" facility.

First, create the file /etc/postfix/transport
----
unixpeople.com	:
* smtp:smtp.sbcglobal.yahoo.com
----

CRITICAL:CRITIAL
If this system is the final destination for any domains, you MUST
specify them first in the file WITH A NULL relay.
I only used this to prove a point. I could have simply routed
aol.com through that server and left everything else alone....

now, convert it to dbm format:
# postmap /etc/postfix/transport

Tell postfix to use this map by adding the following line to 
/etc/postfix/main.cf
----
#override mail relays for some domains
transport_maps = dbm:/etc/postfix/transport
----

Unfortunately, the smtp server for sbc requires authentication, so I need to
forward all mail through that server AND do unattended auth...

create the file /etc/postfix/saslpass
---
smtp.sbcglobal.yahoo.com	andrew.barclay@sbcglobal.com:secret
---

now, convert it to dbm format:
# postmap /etc/postfix/saslpass

# chmod 600 /etc/postfix/sasl*
# reload postfix

edit the /etc/postfix/main.cf
-----
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = dbm:/etc/postfix/saslpass
# this is required cause the pacbell server doesn't support TLS
smtp_sasl_security_options =
-----

NOTE: The damn sbc server doesn't support TLS, so my password
will be travelling in plaintext - postfix won't do that by default,
so I had to add the empty smtp_sasl_security_options

Forcing the sending server to use helo
======================================
Add this to main.cf
-----
smtpd_helo_required = yes
-----

Relaying mail from certain hosts
================================
The entire IP range of the ISP for my work (Cogent) was added to the
SPEWS list. IMHO, its a really bad idea to trust just one source
when deciding whether to bounce email, but some system admins DO
refuse email from domains that are listed on the SPEWS list. I believe
that membership in the SPEWS list should simply add to the total
SPAM score (like spamassassin). Unfortunately, not everybody listens
to me! Ok, so my CTO and others need to send email to these domains,
but they are being prevented, so I would like my home system to 
allow my work system to relay mail through it. I could create an
account on my home system, then use the SASL client solution outlined
above, but in this case, thats overkill. Its easier to just allow
the sending system's IP address to relay mail through my server.

First, on my home system, I ran "postconf" and looked at the value
of mynetworks (since it wasn't explicitly specified in the main.cf.
Then I added an explicit entry to my main.cf thusly:
mynetworks = 127.0.0.0/8 192.168.37.0/24 66.250.6.18/32

Note that the 66 address is my work email server. The other two
networks were already on the list. Then I did a "postfix reload"

On the work server, I created the appropriate file to send certain
domains through my home system (I use courier at work - the file
is /usr/lib/courier/etc/esmtproutes

Then I tested it by telneting from the work machine to port 25 on my
home system, and it accepted the mail as a relay.