Installing and Configuring clamav-milter from FreeBSD Ports

Installing clamav-milter for FreeBSD

Introduction

The open-source ClamAV (Clam Anti-Virus) virus scanner can be invoked in a variety of ways. This document describes my experience in installing it as a sendmail milter from the FreeBSD ports. The setup I describe doesn't require the MIMEDefang (or other milter) wrapper.

FreeBSD's sendmail executable is compiled to support milters by default. There should be no need to recompile sendmail to support milters unless you are using a non-standard executable for some reason.

To verify that your sendmail supports MILTERS, issue the following command as root:

# sendmail -d0.1 -bt < /dev/null | grep MILTER

You should see a line of output that includes the word "MILTER".

Before you begin, make sure that your FreeBSD ports tree is up-to-date.

I update my ports as follows (as root, of course):

# cd
# cvsup -L2 -g portsupfile
where my /root/portsupfile looks like:
*default tag=.
*default release=cvs
*default host=cvsup3.freebsd.org
*default base=/usr/local/etc/cvsup
*default prefix=/usr
*default delete
*default use-rel-suffix
*default compress

ports-all

You might consider upgrading your ports before starting. Especially the expat port. If you are not familiar with this tool, then consider reading the wonderful guide done by the folks at FreeBSDDiary.

Step-by-Step Instructions

1. Install clamav from ports

Issue the following commands as root:

# cd /usr/ports/security/clamav
# make WITH_MILTER=yes install

Be sure to use the "WITH_MILTER=yes" option. Otherwise clamav won't run as a stand-alone sendmail milter. Also, don't do a make clean here because you will need the test files later in this guide.

If you are installing on FreeBSD 5.2 and are running into problems, then read the following. When the clamav-milter.c file attempts to include the header malloc.h, the malloc.h header now displays the error:

#error "<malloc.h> has been replaced by <stdlib.h>"

I edited the file /usr/ports/security/clamav/work/clamav-0.67-1/clamav-milter/clamav-milter.c and went to line 384, where I found the lines:

#ifndef HAVE_MALLOC_H
#include <malloc.h>
#endif

I commented them out by changing them to read:

#if 0                           /* ww */
#ifndef HAVE_MALLOC_H
#include <malloc.h>
#endif
#endif /* ww */

then reinvoked make -D WITH_MILTER. It worked.

As part of the installation, the above should add a user and group named clamav. You can verify that this happened by examining /etc/passwd and /etc/group after the installation completes.

The make install should install these executables:

/usr/local/bin/clamdscan
/usr/local/bin/clamscan
/usr/local/bin/freshclam
/usr/local/bin/sigtool
/usr/local/sbin/clamav-milter
/usr/local/sbin/clamd

If your shell is csh or tcsh, you might need to type "rehash" to let "which" find them.

Additionally, make install will install the following (duplicate) configuration files:

/usr/local/etc/clamav.conf
/usr/local/etc/clamav.conf.default

2. Edit the configuration file

Open /usr/local/etc/clamav.conf in your favorite editor. Uncomment the line that reads:

#StreamSaveToDisk

by deleting the leading '#'

The clamav-milter daemon won't start if you forget to uncomment the line.

You may (optionally) want to make the DatabaseDirectory explicit by finding the DatabaseDirectory line and making it read:

DatabaseDirectory /usr/local/share/clamav
The DatabaseDirectory line was formerly named DataDirectory and contained the database mirror servers list (mirrors.txt). (It no longer (3/10/2004) appears to contain mirrors.txt.) It still contains the daily.cvd and main.cvd files (databases).

3. Verify that the installation downloaded the virus database using freshclam

One of ClamAV's strengths is the freshclam facility, which (with the help of cron) can be configured to periodically update the ClamAV virus signatures. The ports installation should have automatically installed an initial set of virus signatures.

To verify the installation of initial virus signatures:

# cd /usr/ports/security/clamav/work/clamav-0.67-1/test
Your clamav version number in the above directory name will most likely be more recent than the one above.
# clamscan test1

The test should produce output something like the following:

test1: ClamAV-Test-Signature FOUND

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

4. Start the clamd daemon

The setup described in this document requires at least two daemons: The first--clamd--scans the mail, communicating with a second daemon--clamav-milter--via a unix-domain socket. The clamav-milter daemon also communicates with sendmail. (These instructions use a second unix-domain socket for the communications between sendmail and clamav-milter, but sendmail supports TCP/IP sockets as well.)

To start the clamd daemon, issue the command:

# clamd

When clamd starts, it creates the unix-domain socket /var/run/clamav/clamd.

If you prefer another socket name, edit /usr/local/etc/clamav.conf by modifying the line:

LocalSocket /var/run/clamav/clamd

5. Start the clamav-milter daemon

Issue the command:

# clamav-milter -lo /var/run/clamav/clmilter.sock

According to the clamav-milter man page, the -lo options tell clamav-milter to 1) scan local messages sent from the LAN and 2) scan outgoing messages from this machine. (Hmmm... I guess this is in addition to "normal" incoming messages?)

Many example pages include the -b ("bounce") option, to send a failure message to the sender. I tried that for a day, then deleted the -b option. During a busy virus epidemic, this can flood unsuspecting users with bogus bounce messages.

With both daemons running, you should see two sockets in the data directory:

# pwd
/var/run/clamav
# ls -l
total 2
srwxrwxrwx  1 clamav  clamav  0 Mar 10 13:39 clamd
-rw-rw----  1 clamav  clamav  5 Mar 10 13:39 clamd.pid
srwxr-xr-x  1 clamav  clamav  0 Mar 10 13:39 clmilter.sock
#

The "s" at the beginning of the lines for clamd and clmilter.sock shows that those as local sockets.

6. Configure clamav-milter in the sendmail.cf

Edit your sendmail macro configuration (mc) file and insert the following line at the end of the sendmail file or immediately before LOCAL_CONFIG:

INPUT_MAIL_FILTER(`clmilter',`S=local:/var/run/clamav/clmilter.sock, F=, T=S:4m;R:4m')

Then rebuild and install your sendmail.cf, and restart sendmail by typing the following:

make
make install
make restart

7. Test ClamAV

Issue the following commands:

# cd /usr/ports/security/clamav/work/clamav-0.67-1/test
# cat test1 | mail root -s "Testing"

You might need to adjust the first command to reference a more recent version of clamav.

Look in /var/log/maillog (near the bottom) for a report that ClamAV detected a virus and handled it.

You will also want to make sure that sendmail can still send and receive e-mail on your server.

8. Modify server startup files

The ports installation should copy three startup files to the /usr/local/etc/rc.d directory: clamav-clamd.sh, clamav-milter.sh and fresh-freshclam.sh.

The third startup file, clamav-freshclam.sh, was added to the ports install between 30 January 2004 and 10 March 2004, with the name clamav_freshclam.sh. It has since been renamed to freshclam.sh. When I ran the ports install on 10 March, all three startup files were copied to /usr/local/etc/rc.d.

See step 9 below for more on freshclam.sh.

You can modify the behavior of the startup files by setting variables in the file /etc/rc.conf

Thanks to Mike Lambert for pointing out to me that all the variables used by the clamav startup scripts can be set in rc.conf--it isn't necessary to modify the scripts themselves.

The clamav startup files check values set in the /etc/rc.conf file. Add the following lines to that file:

clamav_clamd_enable="YES"
clamav_milter_enable="YES"
clamav_milter_flags="--local --outgoing --max-children=50 --quarantine-dir=/var/
quarantine --dont-log-clean --headers --timeout=0 --postmaster-only"
freshclam_flags="--daemon --checks=12"
freshclam_enable="YES"

The freshclam_enable keyword just changed from clamav_freshclam_enable. If you are using the latest clamav and followed these instructions previously, you should change what appears in rc.conf to the new freshclam_enable.

Miraculously enough, clamav will create the /var/quarantine directory for you with proper permissions.

9. Freshclam

The clamav ports package includes freshclam, a program that regularly updates the virus signatures that clamav compares with incoming e-mail. In the past, it was necessary to add a crontab entry to periodically invoke freshclam. Recent versions of the clamav port have begun to start freshclam as a daemon that checks for updates without using cron.

Method a: Run freshclam as a daemon

Follow these steps to fun freshclam as a daemon:

  1. Add the following lines to the file /etc/rc.conf:
    
    freshclam_enable="YES"
    freshclam_flags="--daemon --checks=12"
    

    In the second line above, adjust the value that follows the --checks option to the number of checks per day that you want.

    At the time of this writing, the "shipped" default is 1; according to the freshclam man page, the maximum value for --checks is 50.

  2. Make sure the daemon is running by issuing commands something like:
    
    # sh /usr/local/etc/rc.d/freshclam.sh stop
    # sh /usr/local/etc/rc.d/freshclam.sh start
    

Method b: Run freshclam from crontab

If you want to have cron run freshclam:

  1. Verify that the file /etc/rc.conf does not have a line that reads:
    
    freshclam_enable="YES"
    
  2. Add a crontab entry to call freshclam periodically. Issue the following command (as root):
    
    # crontab -e
    
    (which should open your default editor), and add a line something like:
    
    0 2,8,14,20 * * * /usr/local/bin/freshclam --quiet -l /var/log/clam-update.log
    --daemon-notify=/usr/local/etc/clamav.conf
    
  3. Save the file and exit the editor.
  4. Verify that your edit took effect with the command:
    
    # crontab -l
    

Whichever method you choose for running freshclam, you should make sure that the log file specified with the freshclam command is writable by the user clamav:


# touch /var/log/clam-update.log
# chown clamav:clamav /var/log/clam-update.log