Integrating qmail, qmail-scanner and NAI's VirusScan for Linux on OpenBSD

For any network serving mail to users of Microsoft Windows, it in imperative in this day and age to protect the client systems from the dangerous viruses and trojans that target them. Simply advising users to be careful of what email they open is not enough; oftentimes users are not careful even after the warnings, and some commonly used email clients will automatically execute viral code when the user views it. The solution to this problem is filtering at the email server and ensuring that any mail coming to your users is first sanitized before delivery. This is an important part of a layered approach including local antivirus protection on the desktop.

1.0 Introduction

This document will help an administrator of a qmail server set up the qmail-scanner addin to facilitate scanning of incoming/outgoing SMTP traffic using uvscan (NAI's VirusScan for UNIX.) qmail-scanner supports several antivirus programs, but we will focus in this HOWTO on getting VirusScan for Linux to run under Linux emulation for our virus scanning. In order to do this on a long term basis, you will need to have in your posession a licensed copy of ViruScan for Linux - otherwise, the best you can do is an evaluation copy. For this solution to be robust and work correctly, there are some add-on packages that should be installed to facilitate translation of TNEF encoding, unpacking of compressed archives, and a patch to qmail to work with qmail-scanner.

2.0 Prerequisites

Naturally, you must have a functioning qmail installation. I won't cover installing qmail in this document, but there are a couple of resources to look to:

Assuming your qmail installation is functioning correctly, you can move on to the other neccesary software.

2.1 Install Linux compatibility

Like many commerical applications, VirusScan is distributed as a binary written for Linux. In order to run this on OpenBSD, Linux compatibility must be set up on the system. Although this is no small task, there is a port that makes this easy.

Make sure that you have the current ports tree for your system available. The port that we will be installing is /usr/ports/emulators/redhat/base. To install this system, change into the directory holding the port framework and tell it to install. Should go something like this:

cd /usr/ports/emulators/redhat/base
make install clean

At this point, Linux compatibility is installed and ready on the system. We will continue our work in the ports directory as we move on to installing uvscan, which is VirusScan for Linux.

2.2 Install uvscan

There are two ways to use uvscan on your OpenBSD system. One is to use the restricted, unlicensed trial version available in the ports tree. The other is to modify the uvscan port to build the package using your authentic, licensed version of uvscan from NAI's download section. Since we want a permanent, fully working uvscan, we will cover the building and installation of the fully licensed version. If you don't have a licensed VirusScan for UNIX, you can purchase it from NAI. If you don't have it and won't or can't buy it (it's not cheap ;) ), this HOWTO won't be of much use for you. You could try following it for the trial copy and see how it goes.

The port is located in the ports tree as /usr/ports/security/uvscan. As an example, we will follow an example scenario of building a package from a licensed version of uvscan called vlnx414l.tar.Z.

cp vlnx414l.tar.Z /usr/ports/distfiles/

NOTE: It would be a good idea to check what the name of the liblnxfv library is in your tarball. To do this, tell tar to list out the name of the files in the archive:

tar ztvf vlnx414l.tar.Z

If the library file shows up as liblnxfv.so, it will need to be renamed to liblnxfv.so.4 because this is what the port is expecting. If the name of the library file is already liblnxfv.so.4, you can skip this section. Otherwise, the following list of steps will carry you through extracting the original source, renaming the library file, and rebuilding the archive again.

mkdir ~/tmp
cd ~/tmp
tar zxvf ../vlnx414l.tar.Z
mv liblnxfv.so liblnxfv.so.4
tar zcvf vlnx414l.tar.Z *

Now you will have a new tarball with a correct filename. So, moving on...

First, place the appropriate (the new one, if you just rebuilt it, or the original, if you haven't rebuilt anything) compressed tarball into /usr/ports/distfiles:

mv vlnx414l.tar.Z /usr/ports/distfiles

Next, calculate the checksums for the package. Ports come listed with three different checksums which are then listed in the port skeleton structure for testing authenticity of the distfile. To calculate these checksums, the following command can be used:

cd /usr/ports/distfiles
for i in md5 rmd160 sha1; do $i vlnx414l.tar.Z; done

This should return output similar to the following:

MD5 (vlnx414l.tar.Z) = 0a7b662fdb753ececa2f2eb3bf8508ad
RMD160 (vlnx414l.tar.Z) = 0ff7df9e12c340fce3f855f72020ae07d80dd9d0
SHA1 (vlnx414l.tar.Z) = afd3c87fe7754e6c8d8eb371539d33cf3dd18386

At this point, we should have all of the information we need to reconfigure the port to build the new version of uvscan using our licensed copy. The first thing to do is edit the port's Makefile, located in the root of the port's directory. Below are listed lines that should be changed to reflect the port's new status, including comments and correct file names:

COMMENT=        Licensed version of VirusScan for Linux
VERSION=        4.14.0
DISTNAME=       vlnx414l
HOMEPAGE=       http://www.nai.com/

As seen, we change the comment line to reflect the actual description of the package we are building. The version is changed to match that which is listed in our file name (vlnx414l.tar.Z reflects that it is version 4.14, licensed.) The distname should match the name of the original package placed in distfiles, minus the suffix. And I change the homepage to reflect the base page for NAI's homepage.

The second file which must be edited is the distinfo file, also located in the root of the port's directory. This is the file that contains the three checksums for the distfile. Place the checksums we calculated above in this file so that the port building process recognizes vlnx414l.tar.Z as a valid distribution file.

The third and final file that should be edited is the file DESCR in the port's pkg/ directory. Although this file is not crucial, I usually edit it to be reminded that this port is now set up for my licensed copy. Placing something like the following text in it should be good:

uvscan is my licensed VirusScan version running on OpenBSD under Linux emulation.

Please see ${PREFIX}/share/doc/uvscan/license.txt for more information!


At this point, the port structure should be set up and ready to go for building a new package for our licensed uvscan. Issue the following commands in the root of the ports tree to configure and build the new uvscan package:

make package clean

The preceding command will build the port into a package and place that package under the packages directory of the ports tree. If you receive no errors and the package builds fine, issue the following command to query the package information (for verification) and install the package onto your system:

pkg_info /usr/ports/packages/i386/All/uvscan-4.14.0.tgz
pkg_add /usr/ports/packages/i386/All/uvscan-4.14.0.tgz

The first command will of course show you the information about your package version, comments, and other minor details. Make sure everything matches what you have entered in for new port information. The package contains everything to lay your custom-made VirusScan installation down into OpenBSD. The second command does just that; after executing it, VirusScan for Linux is now installed on your OpenBSD system. ;)

2.3 Install QMAILQUEUE patch

In order for antivirus software to properly work in scanning mail coming through your SMTP host, it needs to have a means by which all SMTP messages can be gatewayed through it. The most logical way to do this is to place it inline with the component that queues the message; after all, every message has to go through the queue at some point; either queued for immediate delivery, queued on route to another SMTP host, or queued to end up in /dev/null.  qmail-scanner facilitates this by becoming the replacement for qmail-queue, the component that qmail uses to send messages into the queue. qmail must be patched to cause it to recognize something besides qmail-queue as its queuing agent. The patch used for that is the QMAILQUEUE patch written by Bruce Guenter.

To install the patch, your qmail source tree must be available. You still have it, right? If you don't, and you haven't made any customizations to the original source, you can download it and reextract it. The patch must be downloaded, applied to the source, and the source recompiled and reinstalled. qmail will then have support for the QMAILQUEUE functionality, which we will see in a minute. For now:

[root@molodetz:~/src]# ls -ld qmail-1.03
total 29034
drwxr-xr-x   4 root  wheel      512 May 15 15:37 qmail-1.03

As seen, we are located in a directory that contains the qmail-1.03 source directory. The patch should be applied from the directory that we are in (the directory one above the qmail source directory, if you are thinking in terms of filesystem heirarchy.)

wget http://qmail.deliver3.com/qmailqueue-patch

This will download the file "qmailqueue-patch" from the site. It is actually an email message that also contains the patch. I usually download the file, and then edit it to remove the text above the first line that says:

diff -u qmail-1.03-orig/Makefile qmail-1.03/Makefile

That should leave you with just the patch file. This file can be be applied to the source by using the patch program, as follows:

patch -p0 < queue-patch

The resulting text, if this succeeds, should indicate that all of the hunks of the patch succeeded, with no errors.

Before recompiling and reinstalling qmail, it is important to shut qmail down so that queue corruption does not occur. All deliveries will be temporarily deferred, so this will be OK. To do so, use qmailctl:

qmailctl stop

Now with the patch applied and qmail safely shut down, change into the qmail source directory and issue the commands to reinstall qmail on your system:

cd qmail-1.03
make setup check

At this point, qmail will be recompiled and reinstalled on the system. Once this is done, restart qmail-send and qmail-smtpd:

qmailctl start
sleep 5
qmailctl stat

Notice that after we start the qmail daemons using qmailctl, we pause for a few seconds so that supervise can record the process "uptime". We run qmailctl stat to verify that qmail-smtpd and qmail-send start properly and continue to run.

3.0 qmail-scanner Installation

With the QMAILQUEUE patch applied, qmail is ready to accept any substitutions we give it as replacements for qmail-queue. The program that will intercept messages destined for the queue, analyze them, pass them along to the virus scanner, and then hand them off to qmail-queue is qmail-scanner.

Before we jump into installing qmail-scanner, let's step back and look at some additional software that should be on your system to help it do its job. For instance, it would probably be helpful to have the ability to extract zipped files to scan their contents. Or to decode the garbage format that MS Exchange uses for mail. Here is a (non-exhaustive) list of programs you may want to install on the system.

http://sourceforge.net/projects/tnef/. Note from qmail-scanner author: "Can decode those annoying MS-TNEF MIME attachments that Microsoft mail servers just love to use. If you don't have this, there are several classes of Email that you basically won't be able to detect viruses in."
Maildrop is not the actual package needed, however one of the included tools is very much required - reformime.
unzip is needed to... unzip zipped attachments. It can also be installed from the ports tree.
SpamAssassin will not be covered in this HOWTO, but know that prior to the installation of qmail-scanner, any addons that it will use must first be installed and running. Should you want to utilize SA in the future, you will want to have it installed right now. Besides, the defaults as set up per the qmail-scanner FAQ are quite reasonable for most sites. If you do want the anti-spam coverage of SpamAssassin, refer to the SA site and the qmail-scanner web page for directions on configuring SA. In order for qmail-scanner to properly detect it during installation, you must have spamd running.

Installing TNEF

The home page of the TNEF project is http://tnef.sourceforge.net/. Download the latest tarball from thier site and unpack it. Change into the new extracted directory. The installation is pretty basic. Assuming that the latest version is tnef-1.2.1.tar.gz, it should go something like this:

tar zxvf tnef-1.2.1.tar.gz
cd tnef-1.2.1
make install

If you'd like to test the installation to ensure that it was problem-free, try the following command:

tnef -V

The text returned should be information about the program version and author.

Installing Maildrop

Thanks to the ports tree, installation of Maildrop is pretty straightforward. Change into the port's directory and issue the commands to make and install the package.

cd /usr/ports/mail/maildrop
make install clean

You can test to make sure the installation was successful by testing for the version of the reformime binary. Something like this:

reformime -v

The text returned should be a revision tag similar to the following:

$Id: reformime.c,v 1.40 2002/03/19 01:29:18 mrsam Exp $

Installing unzip

If you don't already have it installed, you'll want to install the unzip package. This can also be done from the ports tree:

cd /usr/ports/archivers/unzip
make install clean

In order to test the installation, check the version of unzip with the -v switch:

unzip -v

The output should give version and diagnostic information and will start something like this:

UnZip 5.50 of 17 February 2002, by Info-ZIP.  Maintained by C. Spieler.  Send
bug reports to the authors at Zip-Bugs@lists.wku.edu; see README for details.

Installing SpamAssassin

SpamAssassin is also available through the ports tree. Install it the same way that you installed previous ports.

cd /usr/ports/mail/p5-Mail-SpamAssassin
make install clean

If you wish for qmail-scanner to be able to find SpamAssassin and build support for it, you will have to set it up and start the spamd daemon. For more details on setting this up, consult the qmail-scanner FAQ which can be found at this location: http://qmail-scanner.sourceforge.net/FAQ.php#cs.

At this point, all of the supporting and helper applications should be installed and we are ready for the installation of qmail-scanner.

Installing qmail-scanner

First things first - grab the latest qmail-scanner package from the qmail-scanner page on Sourceforge. The URL is http://qmail-scanner.sourceforge.net/, under the download section.

The installation of qmail-scanner is easy, since it is little more that a few lines of script. To do so, read the output of the ./configure --help command.

At a minimum, the following configure command should take care of everything:

./configure --admin $ADMIN --domain $DOMAIN

As you can read from the help option, this configure string will set everything to default except for the email address of the administrator that will receive antivirus notifications; replace $ADMIN with the part of the administrator's email address before the "@" sign, and $DOMAIN with the domain part of the email address.

qmail-scanner at this point should now prompt you to continue. It will detect the various programs on your system, including any virus scanners that you may have, and the spamd daemon from SpamAssassin. If the run is successful, you should see output similar to the following:

/usr/bin/uudecode works as expected on system...

Found tnef on your system! That means we'll be able to decode stupid
M$ attachments :-)

The following binaries and scanners were found on your system:


Content/Virus Scanners installed on your System


Qmail-Scanner details.


If that looks correct, I will now generate qmail-scanner-queue.pl
for your system...

Continue? ([Y]/N)

The important items to look for are as follows: first, ensure that uvscan is listed under "Content/Virus Scanners installed on your System. If you have set up SpamAssassin, you will also see it listed here. Next, be sure that the following applications are mentioned as being found: uuencode, tnef, reformime, and unzip. If everything looks normal, good. We are ready to move on to installing the results into our system. The way to do this is to repeat the configure command and add the option --install to the end of it; not only will the neccesary files be created, but the directory structure used by qmail-scanner will also be created. The final configure command will look something like this, assuming that our admin email address is admin@domain.tld:

./configure --admin admin --domain domain.tld --install

4.0 Testing and additional configuration

Now, qmail-scanner should be installed on the system, and all that is left should be some minor configuration items. The first is to adjust the softlimit settings for our qmail-smtpd daemon. The softlimit will need to be higher because of how qmail-scanner will increase the memory requirements as it scans the mail messages. OpenBSD seems to require a higher softlimit setting than some other Unix systems, and I find that a setting of 8000000 (8 MB) is sufficient. Set this in the run script for qmail-smtpd, usually /service/qmail-smtpd/run.

The second item is to define which mail hosts will have thier mail inspected by qmail-scanner. The purpose of the QMAILQUEUE patch was to allow the administrator to set the environment variable QMAILQUEUE for any class of user and specify and alternate queue handler for their class; in our purpose, we want to set QMAILQUEUE to /var/qmail/bin/qmail-scanner-queue.pl for hosts that we are concerned about viral transfer from. As an example, let's examine a plausible /etc/tcp.smtp file where address classes are defined:

:allow,RBLSMTPD="451 bad reverse DNS"

In this example file, classes are defined as being: 1, localhost; 2, the local LAN (; 3 and 4, all other hosts (one set for hosts that we can accomplish reverse DNS lookup on, one that we cannot.). For our purpose, let's say that we wish to pass mail incoming from the Internet and mail outgoing from our LAN through qmail-scanner and leave mail originating from the mail server alone. To accomplish this, define the variable QMAILQUEUE for the target address classes, and point it to the full path to qmail-scanner-queue.pl as shown below:

:allow,RBLSMTPD="451 bad reverse DNS",QMAILQUEUE="/var/qmail/bin/qmail-scanner-queue.pl"

Make sure after changing this file that changes are passed on to the cdb file. To accomplish this, you can run qmailctl cdb to compile the list to binary.

At this point, the setup should be complete. To facilitate testing of your new configuration, you should run the installation test script from the contrib directory of the qmail-scanner source code:

./contrib/test_installation.sh -doit

The resulting output should look like this (note that this will probably have to be ran as root; even sudo'ing the command as a non-root user failed for me...):

setting QMAILQUEUE to /var/qmail/bin/qmail-scanner-queue.pl for this test...
setting QMAILQUEUE to /var/qmail/bin/qmail-scanner-queue.pl for this test...

Sending standard test message - no viruses...

Sending eicar test virus - should be caught by perlscanner module...

Sending eicar test virus with altered filename - should only be caught by commercial anti-virus modules (if you have any)...

Sending bad spam message for anti-spam testing - In case you are using SpamAssassin...

Finished test. Now go and check Email for $ADMIN@domain.tld

As told at the end, check your admin mailbox. You should have 4 new mail messages in your inbox, send from qmail-scanner. Each of them will help you ensure that different parts of the system function properly. Below is a brief description of the messages:

Message 1 of 4
This is a normal message. It is intended to allow you to verify that no undue tampering of uninfected mail occurred. There should e no virus message and no misformatting, etc.
Message 2 of 4
This is a message that contains an attachment called Eicar.com. The attachment is 69 bytes in size. The internal "perlscanner" of qmail-scanner can pick this up; it knows a set virus characteristic and flags it based on this characteristic. The message should come through tagged as infected. Focus on the bottom of the message; it should contain a section with details from the perlscanner.
Message 3 of 4
This message contains the Eicar virus, and is named differently to trick the internal perlscanner. The purpose of this message is to test that your virus scanner (uvscan) can detect the virus in the message. Focus on the bottom of the message, where there should be a section under uvscan results giving you details on the infection it found. If this test succeeds, uvscan is working correctly with qmail-scanner.
Message 4 of 4
This message is not viral. It is a message that has a high number of characteristics of SPAM and its purpose is to test whether SpamAssassin is working properly. If you have SpamAssassin set up, look for the presence of the X-Spam-Status header. If it has "Yes" in this header, then SA has flagged it as SPAM. If you don't have SA set up, ignore this message.

Given that the first 3 tests work out, your installation and configuration are complete! It is important to note some important file and directory locations for future configuration and usage.

5.0 Updating uvscan

NAI releases DAT file updates weekly for new virus signatures as viruses come out. It is important to keep uvscan updated to stay protected.

NOTE: Sometimes a virus will come out between regularly scheduled updates. Although most of the time once a week is enough, keep up to date with notifications of new virus threats.

To update uvscan, download the latest DAT tarball from NAI's FTP site, ftp.nai.com. The current location of the DAT package is at ftp://ftp.nai.com/pub/datfiles/english/. The DAT file package is named like datXXXX.tar, where XXXX is the weekly version number identifying the DATs.

After downloading the tarball, extract it (preferably to a temporary directory, since the contents are dumped to your current directory) and copy the DAT files to the uvscan installation directory:

mkdir tmp
cd tmp
tar xvf ../datXXXX.tar
cp -f *.dat /usr/local/libexec/uvscan

You can check and verify that the version of DATs is updated by running uvscan with the --version switch:

$ uvscan --version
Virus Scan for Linux v4.24.0
Copyright (c) 1992-2003 Networks Associates Technology Inc. All rights reserved.
(408) 988-3832  LICENSED COPY - Jan 27 2003

Scan engine v4.2.40 for Linux.
Virus data file v4284 created Aug 11 2003
Scanning for 77928 viruses, trojans and variants.

As is shown here, this system was just updated to DAT version 4284, released on August 11, 2003.

6.0 Prologue

Now that everything has been installed and tested, your setup should be complete. qmail-scanner works very well and coupled with uvscan's excellent functionality and punctual DAT updates, securing your incoming and outgoing email traffic should be pretty easy. Remember that every week a new DAT rollup is released from NAI; to update your DAT files, simply copy the new DATs from the tarball into the directory /usr/local/libexec/uvscan, where they will overwrite the old DATs. To test and make sure that the new DATs have gone in correctly, check the version of uvscan using the command uvscan --version. The output you see should reflect when DAT version and release date you are running.

This concludes this HOWTO. If you would like to recommend any improvements to this document, please let me know. If you found this document useful, I'd like to hear about that also.

Submitted by: [ sancho <at> sancho2k <dot>net ]