Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

Using Open Source Tools to Filter Email on Mac OS X Server

If you are a systems administrator, you know that mail servers worldwide are saturated by virus traffic. There are simple, powerful ways to add virus filtering to a Mac OS X Server-based mail server, in order to block, remove, or disable harmful content in incoming and outgoing email. Because Mac OS X Server is a UNIX-based system, there is a wealth of freely-available open-source software that you can download and use, including virus-filtering tools. Keeping your email clean of viruses is always a good idea, especially if you have a heterogeneous network—infected email can be passed through your server to infect machines running other operating systems. With the tools discussed in this article, keeping your email virus-free is easy, free and customizable.

This article steps you through the installation and setup of some widely-used tools: Perl-based Amasvisd-new, Spam Assassin, and ClamAV. There are other, similar open-source tools available, but completing this exercise shows you one way to keep your mail server clean of viruses; you can try other solutions, as well.

Installing Amavisd-new

Amavisd-new is an interface that runs between Postfix, the mail server software that comes with Mac OS X Server, and the virus filtering software that we will download and install. Amavisd-new accepts messages from Postfix and passes them along securely to any of several available virus filters. Here, we will configure Amavisd-new to work with the ClamAV scanner (also available for download at no cost); but the technique discussed in this article can be used with other virus-scanning tools as well.

To get Amavisd-new, which is Perl-based, running on Mac OS X Server, the first step is to download a bunch of Perl modules that it requires. This is most easily done from the command line, via CPAN:

sudo zsh
cpan

NOTE: These instructions have you switch to the z shell, you can choose to use another shell if you prefer.

Then, all on one line:

install Archive::Tar Archive::Zip Compress::Zlib Convert::UUlib Digest::MD5 Digest:
:SHA1 Net::Server Net::SMTP Time::HiRes Unicode::Map Unicode::String Unix::Syslog Mail::SpamAssassin

This takes a fair while to process. We watch the terminal to monitor progress and to watch for any errors. One package needs extra encouragement:

force install Convert::TNEF

And finally, when everything is downloaded and installed:

quit

Note: If CPAN hasn't previously been configured, it will ask for setup details at the beginning of the session. You can either agree to follow and install any prerequisites that may be requested, or you can type o conf prerequisites_policy follow at the beginning of the session to do so automatically.

Then we download another prerequisite package, MIME-Tools 6.2, which as of this writing isn't available through CPAN. We untar, build, and install it:

sudo zsh
tar xzvf MIME-tools-6.200_02.tar.gz
cd MIME-tools-6.200_02
perl Makefile.PL
make
make install

Next, we need to install the Berkeley DB. Mac OS X Panther ships with the Berkeley DB version 1.8, but for this process, we need a newer version, 2.0 or later. If you don't install version 2.x or newer, you will get an error message later on when you are installing the Perl modules.

Download the newest version 4.2.52 source (or whichever version you choose, 2.x or later), from Sleepycat Software.

Copy the tar file to your working directory and untar:

# cp db-4.2.52.NC.tar.gz /usr/local/src
# cd /usr/local/src
# tar -zxvf db-4.2.52.NC.tar.gz

Go to the build directory and perform the standard build ritual:

# cd db-4.2.52.NC/build_unix
# ../dist/configure --prefix=/usr
# make
# make install

This should install BerkeleyDB, including the libraries needed for the BerkeleyDB.pm Perl module.

All the prerequisites are now in place. We now use Workgroup Manager to create a user and group, with the former in the latter, both named amavisd. Amavisd-new will run as this user, because running it as root is unsafe and best avoided. We assign the user a home directory of /private/var/amavisd, and adjust that directory's permissions from the command line:

chown amavisd:amavisd /private/var/amavis
chmod 750 /private/var/amavisd

Amavisd-new also wants a directory in which it can quarantine infected email:

mkdir /private/var/virusmails
chown amavisd:amavisd /private/var/virusmails
chmod 750 /private/var/virusmails
mkdir ~amavisd/tmp ~amavisd/db

Now we are ready to install Amavisd-new. Still as the superuser, download the latest stable version and simply untar it in my working directory. Then place the Perl executable in /usr/local/bin:

cp amavisd /usr/local/bin

and place its config file in the /etc directory:

cp amavisd.conf /etc

Next we need to edit /etc/amavisd.conf just a bit to reflect the setup of our server. We find the line defining the $myhostname variable, and set it to our server's hostname. Likewise, we set $daemon_home and $daemon_group both to 'amavisd', the name of the user and group under which the daemon Amavisd-new will run.

There are numerous other settings in this file, which it's well worth familiarizing oneself with before rolling out a production installation of Amavisd-new, but the default settings work for now.

We can briefly test that the installation has worked, by becoming the amavisd user and running it in debug mode, which displays verbose status messages:

su amavisd
/usr/local/bin/amavisd debug

It gives us a scroll of output as it loads all its Perl modules, looks for scanners, and finally says "parent ready for children." At this point we stop the running process with Control-C, and proceed.

Amavisd-new is installed, but it is just a framework for virus scanning: there is as yet no actual scanner in place to do the job. Amavisd-new can interface with any number of scanners—a complete list is given at the end of the amavisd.conf file. If a site already has a license to use a particular compatible scanner, Amavisd-new can handle it. Here, we use the free scanner ClamAV.

Installing ClamAV

The scanner ClamAV is a free antivirus package that includes several useful features, including easy integration with mail servers, and scriptable automatic updating of its virus database. Let's describe how to install and use it to detect and filter mail viruses.

Here is how to install ClamAV. It will run constantly to process the data that Amavisd-new feeds to it. Running ClamAV as root is dangerous and leaves my server open to the risk of intrusion, so instead, we run it as the user amavisd, which we created in the previous section.

In order to verify the digital signatures of updates to the virus library (and hence prevent forgeries and errors), ClamAV needs GMP, the Gnu Multiple Precision Arithmetic Library. We download, unzip, and build this package:

sudo zsh
tar xzvf gmp-4.1.2.tar.gz
cd gmp-4.1.2
./configure ; make ; make install

(If you have Fink installed on your system, you can install ClamAV even more easily with the Fink command fink install gmp).

Next, to install ClamAV, we download the latest stable source package from SourceForge. Untarring it in our working directory as the superuser, we then cd to the source directory, build, and install it, using the familiar process:

tar xzvf clamav-0.75.1.tar.gz
cd clamav-0.65
./configure --sysconfdir=/etc --with-user=amavisd --with-group=amavisd
make
make install

The special flags to ./configure set the location of the config file, and the user and group under which ClamAV will execute. After the build process is over, we test the newly created ClamAV executable on a handful of sample viruses that are handily supplied in the source directory:

/usr/local/bin/clamscan ./test/test*

It finds five viruses:

./test//test1: ClamAV-Test-Signature FOUND
./test//test1.bz2: ClamAV-Test-Signature FOUND
./test//test2.badext: ClamAV-Test-Signature FOUND
./test//test2.zip: ClamAV-Test-Signature FOUND
./test//test3.rar: ClamAV-Test-Signature FOUND

----------- SCAN SUMMARY -----------
Known viruses: 10131
Scanned directories: 1
Scanned files: 8
Infected files: 5
Data scanned: 0.00 MB
I/O buffer size: 131072 bytes
Time: 1.796 sec (0 m 1 s)

It doesn't succeed in finding the virus hidden in a RAR file—to do that, we need to install an unrar too—but since the daemonized version of ClamAV (which is what we are going to be using) can't handle RAR files regardless, that doesn't matter for our purposes.

With that done, we next test ClamAV's automatic database update tool, Freshclam, by typing:

/usr/local/bin/freshclam --verbose

Freshclam connects to the virus database and downloads any updates that may be waiting:

ClamAV update process started at Mon Sep 20 17:25:16 2004
Connected to database.clamav.net (128.121.60.235).
Reading CVD header (main.cvd): OK
Downloading main.cvd [*]
main.cvd updated (version: 12, sigs: 11867, f-level: 1, builder: tkojm)
Connected to database.clamav.net (128.121.60.235).
Reading CVD header (daily.cvd): OK
Downloading daily.cvd [*]
daily.cvd updated (version: 67, sigs: 97, f-level: 1, builder: tkojm)
Database updated (11964 signatures) from database.clamav.net (128.121.60.235).

We want Freshclam to run periodically on our system, so we are assured of always having the latest virus definitions. So we add the following line to /etc/watchdog.conf, to start Freshclam automatically. The "-c 4" tells it to run four times each day, and the -u clamav causes it to run as the clamav user rather than as root:

freshclam:respawn:/usr/local/bin/freshclam -c 4 -u clamav        # Freshclam daemon

Optionally, we can add the "-l logfile" option to Freshclam, which causes it to log all of its activity to the file specified in logfile.

Putting It Together

Now both ClamAV and Amavisd-new are installed, and ready to work together. If we once again run Amavisd-new in debug mode:

su amavisd
/usr/local/bin/amavisd debug

it now tells us "Found secondary av scanner Clam Antivirus - clamscan at /usr/local/bin/clamscan"

The team is ready to go. We will keep Amavisd-new running while we test the Postfix setup. We now need to hook our scanning setup into Postfix, so it can handle the mail for our server. We will make two manual changes to the Postfix configuration files. Note that subsequent changes to the mail setup made using Server Admin may overwrite these manual changes. First, we stop the Postfix server if it is running, using Server Admin.

Next, we open a new terminal window (leaving Amavisd-new running in the previous one) to edit /etc/postfix/master.cf, and add the following lines to the end of the file:

smtp-amavis unix -	-	n	-	2  lmtp
    -o smtp_data_done_timeout=1200

127.0.0.1:10025 inet n	-	n	-	-  smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_client_restrictions=
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o mynetworks=127.0.0.0/8
    -o strict_rfc821_envelopes=yes
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000

That creates the definition and settings for the Amavisd-new content filter in Postfix. We tell Postfix to re-read its settings:

postfix reload

and test that Postfix is listening on port 10025:

telnet localhost 10025

It should say something like:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 server.local ESMTP Postfix

We also check that Amavisd-new is listening on port 10024:

telnet localhost 10024

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 [127.0.0.1] ESMTP amavisd-new service ready

Now we want to tell Postfix to route mail to this newly defined filter. We add a line to the end of /etc/postfix/main.cf:

content_filter=smtp-amavis:[127.0.0.1]:10024
max=use=10

This instructs Postfix to send all mail to the Amavisd-new filter. Once again, we type:

postfix reload

to activate the new setting. Now Amavisd-new is filtering all our mail. We send a sample message to my user account on the server, and indeed when we receive the message it contains the header

X-Virus-Scanned: by amavisd-new at myserver.com

showing that the message has been successfully processed.

Configuration

The README.postfix file that accompanies the Amavisd-new distribution provides detailed information on fine-tuning the setup of Amavisd-new and Postfix. Settings for Amavisd-new can be adjusted in /etc/amavisd.conf—in particular, the filter's behavior when it finds a virus can be configured. The default setting places virus-infected email messages in the quarantine directory, /var/virusmails. Notification options can be changed, viral mail can be simply deleted or bounced, or all viruses can be redirected to a specified mail account.

ClamAV's settings can be tuned in ./etc/clamav.conf.

In order to start Amavisd-new running automatically when the server is started, we add the following line to /etc/watchdog.conf:

amavisd:respawn:su amavisd -c /usr/local/bin/amavisd

Then we restart watchdog with:

sudo killall -HUP watchdog

ClamAV doesn't have to be started separately, as it is triggered by Amavisd-new when needed.

The log files for any captured viruses are found in /var/log/syscan.log.

For More Information

  • See the Apple Servers page for information on Mac OS X Server, Xserve G5 and Xserve RAID.
  • For more articles on using Mac OS X Server, see the Mac OS X Server page.

Updated: 2004-11-29