Building a Mail Server on CentOS
with MailScanner, Squirrelmail, Mailwatch, spamassassin & ClamAV
What is MailScanner
MailScanner is a free anti-virus and anti-spam filter. It serves as a
wrapper for the MTA of your choice (Sendmail, Postfix, etc),
spamassassin, a variety of other anti-spam tools, as well as a
multitude of anti-virus scanners.
Why CentOS
CentOS is a mature, robust distribution which includes cutting edge,
but stable versions of the many open source projects that are bundled
with it. This is very useful as production mail servers often require
frequent security audits such as the PCI or Payment Card Industry
compliance scans. The rpm update structure and the yum update mechanism
make it very easy to keep a system current and patched for security
compliance. I usually rebuild the production mail servers I
am
responsible for at least every 18 months.
Why CentOS, because CentOS is powerful, cutting edge and easy to
maintain.
Hardware Recommendations For a
Commercial-Grade Mail Gateway
- Dual 64-bit AMD processors
- 2GB of RAM
- RAID5 (RAID1+0 recommended)
For a lab environment or a small business, you can get away with a
Pentium 4 class machine with 1GB of RAM and IDE or SATA drives.
Installing CentOS
- Install CentOS from DVD. Take the defaults for
partitioning. I
usually do not install Gnome or KDE (just the X server package)
but feel free to install your favorite window manager if you
will be administering the server from the console.
- In the CentOS installation, select custom. Under graphical
internet, select only firefox. Under text internet, select only elinks
and lynx. Select basic development libraries. Do not select delveopment
libraries for X or KDE. Deselect Dialup networking.
- After the base CentOS installation has completed, perform a
yum update as root.
Installing MailScanner
and Related Tools
- Download the rpm installation of MailScanner from http://mailscanner.info.
Untar the installation using tar -xvzf
filename and change to the directory created as a result.
Run ./install.sh
- Download the ClamAV/spamassassin
installation package from the additional downloads section of the
MailScanner download page. Untar the file using tar -xvzf filename.
Change to the resulting directory and run ./install.sh
- Download Vipul's
Razor (plugin for
spamassassin) – Download and
install razor-agents-2
and razor-agents-sdk
from http://razor.sourceforge.net.
Vipul's Razor is a distributed, collaborative, spam detection and
filtering network. Through user contribution, Razor establishes a
distributed and constantly updating catalogue of spam in propagation
that is consulted by email clients to filter out known spam. Detection
is done with statistical and randomized signatures that efficiently
spot mutating spam content. User input is validated through reputation
assignments based on consensus on report and revoke assertions which in
turn is used for computing confidence values associated with individual
signatures.
- Vipul's Razor
Installation
– unzip the razor-agents-sdk package with the command bunzip2
filename. Then tar xvf (notice the missing z since we are not unzipping
gzipped compression) the resulting .tar file. Change to the resulting
directory and run the compilation commands listed below. bunzip2 then unpack
the razor-agents tarball and execute the compilation
commands listed below. Finally, perform the command razor-admin -register.
perl
Makefile.PL
make
make test
make install
- Pyzor
Installation - Download Pyzor from http://pyzor.sourceforge.net.
bunzip2 and unpack the pyzor tarball. Execute python setup.py build
and python setup.py
install from the resulting directory.
- DCC
Installation - Download DCC from http://www.rhyolite.com/anti-spam/dcc/.
untar the .Z file (another suffix for GZIP) using tar xvzf
filename. Change to the resulting directory and run ./configure then make then make install. Edit /etc/mail/spamassassin/v310.pre
and uncomment the line to enable the DCC plugin.
Customizing
MailScanner.conf
MailScanner.conf is the primary configuration file for MailScanner. It
is extremely large, so it can be very daunting the first few times you
attempt to customize it for your environment. I have included a list of
the key options that I use for most environments. Most of these options
are required for the proper operation of Mailwatch.
Quarantine User = root
Quarantine Group = apache
Virus Scanners = clamav
Allow Password-Protected Archives = yes
Change Iframe Tags, Form Tags, Script Tags, Web Bugs and Object
Codebase Tags from disarm to yes. This allows incoming HTML
mail
to work properly.
Quarantine Whole Message = yes
Always Include SpamAssassin Report = yes
Change Sign Clean Messages = no
Change Deliver Cleaned Messages = no
Spam List = spamhaus-ZEN
Is Definitely Not Spam = &SQLWhitelist
Is Definitely Spam = &SQLBlacklist
Definite Spam Is High Scoring = yes
Required SpamAssassin Score from 6 to 5
Rebuild Bayes Every = 86400
Spam Actions = store
High Scoring Spam Actions = store
Always Looked Up Last = &MailWatchLogging
Configure Services
- Run system-config-services
& as root. Edit run level 5 and make sure MailScanner, mysqld, httpd, dovecot, saslauthd and named
are checked so that they will start at logon. If you do not plan to use
your server console as an administrative workstation, the initdefault value in
/etc/inittab should
be changed from 5 to 3 and the service edits described in this step
should be completed for run level 3. It is generally a good idea to
configure these services identically for run levels 3 and 5.
MailWatch for MailScanner
Mailwatch is a php/mysql app which provides real-time operational views
as well as historical reporting for a MailScanner server.
- Download the latest version from http://mailwatch.sourceforge.net.
Unpack the gzipped tarball using tar xvzf
filename. Ensure the following settings are configured in /etc/php.ini
short_open_tag = On
safe_mode = Off
register_globals = Off
magic_quotes_gpc = On
magic_quotes_runtime = Off
session.auto_start = 0
- From the mailwatch installation directory execute mysql < create.sql.
Assign a mysql root password with mysqladmin
-u root password password.
Log into mysql with mysql
-u root -p and then specify the password when prompted. At
the mysql prompt enter the following commands:
GRANT ALL ON
mailscanner.* TO mailwatch@localhost IDENTIFIED BY 'yourpassword';
GRANT FILE ON *.* TO mailwatch@localhost
IDENTIFIED BY 'yourpassword';
FLUSH PRIVILEGES;
- Edit MailWatch.pm
and SQLBlackWhiteList.pm
and change the $db_user
and $db_pass
values accordingly and move them to /usr/lib/MailScanner/MailScanner/CustomFunctions.
Log into the mailscanner database with mysql mailscanner -u mailwatch -p.
Create user accounts to log into the mailwatch web interface with:
INSERT INTO
users VALUES ('joe',md5('password'),'Joe Bloe','A',0,0,0,0,'');
- Move the mailscanner subdirectory to /var/www/html. Execute
the following commands:
chown -R root:apache
/var/www/html/mailscanner/
chmod -R ug+rwx
/var/www/html/mailscanner/
cp
/var/www/html/mailscanner/conf.php.example
/var/www/html/mailscanner/conf.php
- Edit conf.php
and change the user to mailwatch
and supply the password. Change the value of
QUARANTINE_USE_FLAG
to true.
Change the DATE_FORMAT variable
to US format.
- Edit /usr/lib/MailScanner/f-prot-wrapper
and change the value of RamDisk=yes
to RamDisk=no (This is necessary if you choose
to use the f-prot virus scanner)
- Move the
Bayesian Database and set up permissions - Edit /etc/MailScanner/spam.assassin.prefs.conf
and set:
bayes_path /etc/MailScanner/bayes/bayes
bayes_file_mode 0770
- Create the 'new' bayes directory, make the directory owned
by the
same group as the web server user and make the directory
setgid:
mkdir /etc/MailScanner/bayes
chown root:apache /etc/MailScanner/bayes
chmod g+rws /etc/MailScanner/bayes
- Update MailWatch.pm to reduce the messages dumped into
maillog and ultimatly mailed out in LogWatch.
vim
/usr/lib/MailScanner/MailScanner/CustomFunctions/MailWatch.pm
Find:
MailScanner::Log::InfoLog("$$message{id}: Logged to MailWatch SQL");
and change to
MailScanner::Log::DebugLog("$$message{id}: Logged to MailWatch SQL");
Find:
MailScanner::Log::InfoLog("Logging message $msg{id} to SQL");
and change to
MailScanner::Log::DebugLog("Logging message $msg{id} to SQL");
- Fix bug in
mailq.php - vim /var/www/html/mailscanner/mailq.php
Find:
case default:
and change to
default:
- Edit
persmissions for mysql: chmod 775 /var/lib/mysql
- Fix bug in
db_clean.php: vim
/opt/installs/mailwatch/tools/db_clean.php
Find:
#!/usr/bin/php -qn
change to
#!/usr/bin/php -q
Find:
dbquery("DELETE LOW_PRIORITY FROM maillog WHERE timestamp <
(now() - INTERVAL 60 DAY)");
change to:
dbquery("DELETE LOW_PRIORITY FROM maillog WHERE date < (now() -
INTERVAL 60 DAY)");
- Copy
mailq.php and other needed scripts into place and set permissions:
mv /opt/installs/mailwatch/tools/mailq.php /usr/local/bin
mv /opt/installs/mailwatch/tools/db_clean.php /usr/local/bin
mv /opt/installs/mailwatch/tools/quarantine_maint.php /usr/local/bin
mv /opt/installs/mailwatch/tools/quarantine_report.php /usr/local/bin
mv /opt/installs/mailwatch/tools/sendmail_relay.php /usr/sbin
chown root:root /usr/local/bin/mailq.php
chown root:root /usr/local/bin/db_clean.php
chown root:root /usr/local/bin/quarantine_maint.php
chown root:root /usr/local/bin/quarantine_report.php
chown root:root /usr/sbin/sendmail_relay.php
- Set up cron
job to run mailq.php: vim /etc/cron.d/mailwatch
Copy the following code into the file:
MAILTO=admin
SHELL=/bin/sh
* * * * * root /usr/local/bin/mailq.php
0 0 * * * root /usr/local/bin/quarantine_maint.php --clean
0 0 * * * root /usr/local/bin/quarantine_report.php
0 0 * * * root /usr/local/bin/db_clean.php
- Ensure the
appropriate Mailwatch requirements are set: vim
/etc/MailScanner/MailScanner.conf
Always Looked Up Last = &MailWatchLogging
Detailed Spam Report = yes
Include Scores In SpamAssassin Report = yes
Quarantine Whole Message = yes
Quarantine Whole Message As Queue Files = no
Quarantine User = root
Quarantine Group = apache
Quarantine Permissions = 0660
Quarantine Dir = /var/spool/MailScanner/quarantine
Is Definitely Not Spam = &SQLWhitelist
Is Definitely Spam = &SQLBlacklist
- Make sure
/etc/cron.daily/clean.quarantine is disabled: vim
/etc/cron.daily/clean.quarantine
$disabled = 1;
- Restart
MailScanner - /etc/init.d/MailScanner restart
- Set up
sendmail_relay service: (assumes a staging directory of
/opt/installs)
mv /opt/installs/mailwatch/tools/sendmail_relay.init /etc/rc.d/init.d
chown root:root /etc/rc.d/init.d/sendmail_relay.init
ln -s /etc/rc.d/init.d/sendmail_relay.init /etc/rc.d/init.d/mailwatch
/sbin/chkconfig --add mailwatch
Configure and Harden
Apache
This documentation assumes running multiple SSL-enabled sites using
name-based hosting. If you have the IP space to provide a separate IP
Alias for each site, you can use IP-based hosting and use the default
https port of 443 for all sites.
- Edit
/etc/httpd/conf/httpd.conf and edit defaults to match the following
settings:
ServerTokens
Prod
Find the Global instance of Options located under <Directory
"/var/www/html">
Remove File Indexes by changing Options Indexes FollowSymLinks
to Options FollowSymLinks
Insert FileEtag None just
prior to the line reading --> DirectoryIndex index.html
Change the default setting of ServerSignature On
to ServerSignature Off
Append to the end of the configuration
file:
NameVirtualHost *:80
NameVirtualHost *:4500
Include sites/*.conf
- Modify
/etc/httpd/conf.d/ssl.conf. Comment out the virtual host
open and close tags, change
Listen 443 to Listen
4500, comment out SSLEngine
On
as this is done on a per Vhost basis, comment out the certificate and
key references as this is done on a per Vhost basis. This allows apache
to serve more than one tls connection using multiple ports in the case
of Name-based Virtual Hosts or multiple instances of port 443 for
IP-based Virtual Hosts.
- mkdir
-p /etc/httpd/sites. Create /etc/httpd/sites/mailwatch.conf
and enter the following content (This creates the apache virtual host
for the mailwatch website. The ModRewrite section hardens the site
against attacks. In this example port 4500 is used for SSL and port 80
is used to redirect to an encrypted session :
<VirtualHost
*:4500>
ServerAdmin srvadmin@myorg.com
DocumentRoot /var/www/html/mailscanner/
ServerName mailwatch.myorg.com
ServerAlias mailwatch
ErrorLog logs/mailwatch.myorg.com-error_log
CustomLog logs/mailwatch.myorg.com-access_log common
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/mail1.crt
SSLCertificateKeyFile /etc/pki/tls/certs/mail.key
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$
RewriteRule .* - [F]
</IfModule>
<Directory /var/www/html/mailscanner/>
php_admin_flag safe_mode 0
Options -Indexes
AllowOverride All
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerAdmin srvadmin@myorg.com
DocumentRoot /var/www/html/mailscanner/
ServerName mailwatch.myorg.com
ServerAlias mailwatch
Redirect permanent /
https://mailwatch.myorg.com:4500
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$
RewriteRule .* - [F]
</IfModule>
</VirtualHost>
Create a Private CA and
Create a Self-Signed Certificate
create a private CA:
/etc/pki/tls/misc/CA -newca
copy openssl.cnf to MyOrgCA.cnf
create a certificate:
cd /etc/pki/tls/certs
openssl genrsa -out certname.key 1024
create a signing request:
openssl req -new -key certname.key -out
certname.csr
Sign the Request:
openssl ca -config ../MyOrgCA.cnf
-policy
policy_anything -out certname.crt -infiles
certname.csr
Move the key file to the appropriate directory:
mv /etc/pki/tls/certs/mail.key
/etc/pki/tls/private/
Install Additional perl
modules from CPAN
Execute perl -MCPAN -e
shell
from command line. Fill out the form for the first-time configuration
of CPAN. If there are problems with the LWP sessions , then your
firewall is not set up correctly to proxy passive ftp. Once you get a cpan> prompt
use the install
command to download and install Net::Ident
and IO::Socket::SSL.
Configuring Sendmail
These are the options that I like to use when configuring sendmail for
most situations. It is worth the time to research all of these
individual options on Sendmail's website, http://sendmail.org
- /etc/mail/sendmail.mc
configuration - Make the following changes to
the default sendmail.mc file
Add define(`confBIND_OPTS',`WorkAroundBrokenAAAA')
to the end of the define
section right after the confAUTH_OPTIONS
definition.
uncomment the TRUST_AUTH_MECH line
and add GSSAPI
so it reads like this:
TRUST_AUTH_MECH(`EXTERNAL
GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
uncomment the confAUTH_MECHANISMS
line right below TRUST_AUTH_MECH.
It should read like this:
define(`confAUTH_MECHANISMS',
`EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
uncomment the CACERT_PATH,CACERT,SERVER_CERT
and SERVER_KEY
definitions
and modify the key names and paths to
look like this:
define(`confCACERT_PATH',`/etc/pki/tls/certs')dnl
define(`confCACERT',`/etc/pki/tls/certs/ca-bundle.crt')dnl
define(`confSERVER_CERT',`/etc/pki/tls/certs/mail.crt')dnl
define(`confSERVER_KEY',`/etc/pki/tls/private/mail.key')dnl
Add the following generics lines right
above the FEATURE(redirect)
line:
FEATURE(`genericstable', `hash -o /etc/mail/genericstable')dnl
GENERICS_DOMAIN_FILE(`/etc/mail/generics-domains')dnl
Comment out the always_add_domain
feature by placing dnl
at the beginning of the line.
Remove the address section
from the DAEMON_OPTIONS
line. This allows smtp to receive mail from the other IP addresses
assigned to the box, not just from the loopback address.
The modified line should look like this:
DAEMON_OPTIONS(`Port=smtp, Name=MTA')dnl
Uncomment the following line to enable
MX-based relaying:
FEATURE(`relay_based_on_MX')dnl
Change the LOCAL_DOMAIN
definition to your domain. e.g. myorg.com.
Add the following to the very end of the
file. This tightens the security on encrypted connections:
LOCAL_CONFIG
O
CipherList=ALL:!ADH:!NULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:!LOW:+SSLv3:+TLSv1:!SSLv2:!EXP:!eNULL:!aNULL
- The CipherList feature requires FFR_TLS_1
support. FC5 and newer sendmail rpms from CentOS are compiled with this
support but historically it has not been compiled in by
default. It may also not be on other distributions. Use the
following command to check your sendmail installation:
sendmail -d0.13 < /dev/null | grep FFR should
return:
FFR Defines: _FFR_TLS_1
If it does not you will need to
recompile sendmail. http://sial.org/howto/sendmail/cipherlist/
is a great resource for additional information.
- The /etc/mail/access
file
contains IP addresses or blocks which are permitted to use the MTA.
This file should only contain the IP range for the local network and
remote servers with a secured connection to the mail server. All other
access should be permitted via the authentication mechanisms.
- The generics-domains
file
is used when you allow local users to send mail and need the outgoing
email address to be from a domain other than the default local domain.
The generics-domains
file lists the domains that this applies to. The genericstable file
is the reverse of the virtusertable,
mapping local users to desired outgoing email addresses. Even if not in
use, these files should be created with the touch command since
they are defined in sendmail.mc.
- The
local-host-names file should contain any aliases that the
local machine may have. These should include simple aliases such as mail
as well as FQDNs such as mail.myorg.com.
This file should also include additional domain names serviced by this
MTA.
- The mailertable
file is
used by secondary mail servers to queue mail for the primary in case it
is down. The mail gets to the secondary server, as it is defined with
an MX record, with a higher value in the DNS forward lookup zone. Here
is a syntax example:
foo.net
smtp:[mail1.foo.net]
bar.com smtp:[mail1.foo.net]
- The virtusertable
file
maps email addresses to local user accounts for local delivery. The
email addresses go on the left and the local user accounts go on the
right. The values should be separated by whitespace, generally the tab
key is used.
- Use the /etc/aliases
file
to create distribution lists of local user accounts. Then you can
reference the local distribution list in the virtusertable to create
email distribution lists. After editing the /etc/aliases file,
the newaliases
command must be run. Note:
on BSD systems, the aliases file is located at /etc/mail/aliases.
Where is My Sendmail
Vacation Program?!?
The redhat/CentOS rpm installation of sendmail does not install the
sendmail vacation program. I have never heard a good explanation for
this rationale. Nevertheless, for those of us building production mail
servers, the vacation program is necessary. Here is how to get it.
cd /usr/src/redhat/SOURCES/
tar xvzf sendmail.xxx.tgz
cd sendmail.xxxxx/vacation
make
make install
Configuring Squirrelmail
Squirrelmail is a web-based email program which allows your users to
browse their mail while it is still on the server. Squirrelmail
communicates with the mail server via IMAP. Since the Squirrelmail
server is running on the mail server, there are no security issues with
passing IMAP through the firewall. Additionally, through the addition
of a few plug-ins, users can securely change their local user/email
password and set a vacation message. There are many other plug-ins
available for Squirrelmail so it can be customized to suit your needs.
See their web page for more information. http://www.squirrelmail.org
- Install Squirrelmail - yum
install squirrelmail
- Download and install poppassd from http://www.netwinsite.com/poppassd/.
Run make -lcrypt
then make install
in the poppassd directory. Create /etc/xinetd.d/poppassd
and insert the following:
service
poppassd
{
disable = no
socket_type
= stream
wait
= no
user
= root
server
= /usr/sbin/poppassd
log_on_success += HOST DURATION
log_on_failure += HOST
}
- Add to /etc/services/
-->
poppassd
106/tcp
- Add a file
/etc/pam.d/poppassd :
#%PAM-1.0
auth
required
/lib/security/pam_unix.so shadow nullok
account
required
/lib/security/pam_unix.so
password
required
/lib/security/pam_cracklib.so retry=3
password
required
/lib/security/pam_unix.so use_authtok
nullok
- Add to /etc/syslog.conf
--> local4.err
/var/log/poppassd
- Install xinetd if it is not already installed (check with rpm -qa |grep xinetd
) -->
yum install xinetd
- test poppassd installation with telnet localhost 106
- Download and install squirrelmail plugins: Change Password, HTML Mail, Select Range, and Vacation_Local.
Untar the tgz files in the /usr/share/squirrelmail/plugins
directory. Run /usr/share/squirrelmail/config/conf.pl
to add the plugins to your configuration.
- The
vacation_local plugin (unlike most squirrelmail plugins)
requires some additional configuration. Switch to the vacation_local directory
created by expanding the tarball. Switch to the vacation_binary
subdirectory. Edit the config.mk
file and make the following change:
BINDIR
= /usr/local/sbin
Then, make and make install
cd ../
cp config.php.sample config.php
vim config.php
- Set the following values:
$vacation_backend = 'suid';
$mail_vacation_binary =
'/usr/local/sbin/squirrelmail_vacation_proxy';
$vacation_path = '/usr/bin/vacation';
- Modify apache configuration to add the webmail Vhost. vim /etc/httpd/conf/httpd.conf
and add NameVirtualHost
*:4501 after the other NameVirtualHost entries. vim /etc/httpd/conf.d/ssl.conf
and add Listen 4501
after the other Listen entries. Create the new vhost file using vim
/etc/httpd/sites/squirrelmail.conf and add the following:
<VirtualHost
*:4501>
ServerAdmin srvadmin@myorg.com
DocumentRoot /usr/share/squirrelmail
ServerName webmail.myorg.com
ServerAlias webmail
ErrorLog logs/webmail.myorg.com-error_log
CustomLog logs/webmail.myorg.com-access_log common
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/mail.crt
SSLCertificateKeyFile /etc/pki/tls/private/mail.key
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$
RewriteRule .* - [F]
</IfModule>
</VirtualHost>
<VirtualHost *:80>
ServerAdmin sysadmin@myorg.com
ServerName webmail.myorg.com
ServerAlias webmail
Redirect permanent
/
https://webmail.myorg.com:4501
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$
RewriteRule .* - [F]
</IfModule>
</VirtualHost>