http:// qmail.jms1.net / clamav / daemontools.shtml

Running clamav under daemontools

I have been running ClamAV under daemontools on my server for several months now, with excellent results. This web page explains how I'm doing it.


Create the clamav user

The "clamd" and "freshclam" programs are designed to run in the background. For security reasons, we don't want these processes to run as root, so we will create a new userid called "clamav" under which these processes will run.

The procedure for doing this is usually specific to your OS and distribution, this example shows how to do it using CentOS Linux.

# useradd -M -d /nohome clamav

If you will be using clamav in conjunction with qmail-scanner, you may wish to make the clamav user a member of the qscand group. This is normally done using a command like this:

# usermod -a -G qscand clamav

If you will be using clamav in conjunction with simscan, you will need to make the clamav user a member of the simscan group. This is normally done using a command like this:

# usermod -a -G simscan clamav


Compile clamav

The next step, obviously, is to install clamav. I do this using the instructions which are included in the source code package. The process looks like this:

$ tar xzf clamav-0.91.1.tar.gz
$ cd clamav-0.91.1
$ ./configure
Lots of messages, hopefully no error messages
$ make
Lots of messages, hopefully no error messages

If you are upgrading and already have these services running, you need to shut them down before continuing.
$ sudo svc -d /service/clamd /service/freshclam
Password: You will not see the password as you type it

$ sudo make install
Lots of messages, hopefully no error messages

If you had shut these services down before, you should start them up again immediately.
$ sudo svc -u /service/clamd /service/freshclam


Configuring clamd

The normal procedure to scan a file for viruses is to run the program "clamscan" with the filename(s) on the command line. The problem with this is that when clamscan starts, it has to read the virus definitions into memory, a process which can take several seconds on some machines, and which takes a non-zero amount of time for any machine. For a mail server which is scanning every incoming message, and which may be processing hundreds or thousands of messages per hour, this overhead can seriously slow the machine down.

The "clamd" process runs in the background. When it starts, it reads the virus database into memory one time, and then it listens for commands from clients. The "clamdscan" program is such a client- it passes the filenames from its command line to clamd and has clamd do the actual virus scanning, since it already has the virus definitions in memory. This can make a HUGE difference on a server, whether it's heavily loaded or not.

As a test, I just tried "clamscan" and "clamdscan" against the same file- clamscan took 1.582 seconds, while clamdscan only took 0.187 seconds.

The "clamd" program is configured using a clamd.conf file, which by default is installed in /usr/local/etc. The changes you need to make are as follows (lines in red show the original contents, and the lines in blue show what they need to be changed to.)

You must comment out this line or clamd will not run.
# Comment or remove the line below.
Example
#Example

Log file locking is not necessary under daemontools.
# By default the log file is locked for writing - the lock protects against
# running clamd multiple times (if want to run another clamd, please
# copy the configuration file, change the LogFile variable, and run
# the daemon with --config-file option).
# This option disables log file locking.
# Default: no
#LogFileUnlock yes
LogFileUnlock yes

The multilog program (part of daemontools) takes care of this automatically.
# Maximum size of the log file.
# Value of 0 disables the limit.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 1M
#LogFileMaxSize 2M
LogFileMaxSize 0

Again, multilog takes care of this automatically.
# Log time with each message.
# Default: no
#LogTime yes
LogTime no

I like to see log messages whenever files are found to NOT contain viruses, both because it shows me that clamd is working correctly, and because it can provide a log of which files were scanned when. You may not want or need these logs on your own server- if not, then don't make this change.
# Also log clean files. Useful in debugging but drastically increases the
# log size.
# Default: no
#LogClean yes
LogClean yes

I like to see EVERYTHING that clamd is doing. You may not want or need to see this much detail on your own server- if not, then don't make this change.
# Enable verbose logging.
# Default: no
#LogVerbose yes
LogVerbose yes

I like to explicitly document where the virus definitions are stored, just to prevent confusion later on. You may not want or need to do this on your own server- if not, then don't make this change. This location, /usr/local/share/clamav, is where the default installation procedure puts the files. You will need to know this if you're going to install simscan.
# Path to the database directory.
# Default: hardcoded (depends on installation options)
#DatabaseDirectory /var/lib/clamav
DatabaseDirectory /usr/local/share/clamav

This is a GOOD thing to do.
# Remove stale socket after unclean shutdown.
# Default: no
#FixStaleSocket yes
FixStaleSocket yes

This option tells clamd what userid it should run as.
# Run as another user (clamd must be started by root to make this option
# working).
# Default: don't drop privileges
#User clamav
User clamav

This allows clamd to access files using any "group" privileges it may have. Without this, clamd will not try to use any "group" privileges, and will only access files which are readable by the entire world.
# Initialize supplementary group access (clamd must be started by root).
# Default: no
#AllowSupplementaryGroups no
AllowSupplementaryGroups yes

THIS IS ABSOLUTELY REQUIRED in order for clamd to run under daemontools!!!
# Don't fork into background.
# Default: no
#Foreground yes
Foreground yes


Configuring freshclam

The freshclam program checks for updated virus definition files and, if it finds them, downloads and installs them automatically. It then sends a message to clamd, telling it to read the new definitions into memory, and can also call another program that we specify. We will be using this "call another program" capability to inform qmail-scanner and/or simscan to update its version database, so the headers that they add to email messages will have accurate version numbers.

To configure freshclam, we will edit a file called freshclam.conf, which will be found in the same directory where we found the clamd.conf file (above.) This is a list of the changes we need to make:

You must comment out this line or freshclam will not run.
# Comment or remove the line below.
Example
#Example

This must match the DatabaseDirectory line in the clamd.conf file.
# Path to the database directory.
# WARNING: It must match clamd.conf's directive!
# Default: hardcoded (depends on installation options)
DatabaseDirectory /var/lib/clamav
DatabaseDirectory /usr/local/share/clamav

This tells freshclam what userid it should run as. I normally un-comment this line, just to make it obvious that it runs as the clamav user.
# By default when started freshclam drops privileges and switches to the
# "clamav" user. This directive allows you to change the database owner.
# Default: clamav (may depend on installation options)
#DatabaseOwner clamav
DatabaseOwner clamav

This tells freshclam to send the notification to clamd whenever new virus definitions are downloaded. THIS IS REQUIRED for clamd to start using the new virus definitions as soon as they are available, otherwise clamd will only check the files once every 30 minutes to see if they have been updated. This directive actually points to the clamd.conf file which configured the running clamd process- freshclam reads the "LocalSocket" (or "TCPSocket") line in this file in order to contact the clamd process.
# Send the RELOAD command to clamd.
# Default: no
#NotifyClamd /path/to/clamd.conf
NotifyClamd /usr/local/etc/clamd.conf

This tells freshclam to run an external program whenever new virus definitions are downloaded. We will be using this to update the qmail-scanner and simscan version databases.
# Run command after successful database update.
# Default: disabled
#OnUpdateExecute command
OnUpdateExecute /usr/local/sbin/freshclam-good

This tells freshclam to run an external program whenever it tries to download new virus definitions and encounters an error. I use this to email myself a notification, so that I can check on things and make sure any problems are taken care of.
# Run command when database update process fails.
# Default: disabled
#OnErrorExecute command
OnErrorExecute /usr/local/sbin/freshclam-bad

THIS IS ABSOLUTELY REQUIRED in order for freshclam to run under daemontools!!!
# Don't fork into background.
# Default: no
#Foreground yes
Foreground yes

As you can see, whenever freshclam downloads new virus definitions, or whenever it runs into a problem with the process, it calls a script whose name you specifiy in the freshclam.conf file. I use two scripts, which I call "freshclam-good" and "freshclam-bad", for this purpose.

Below are examples of what my own scripts look like, however you should really write your own scripts because your needs may not be the same as mine (in fact, I'm pretty sure they are not the same as mine.)

My "freshclam-good" script looks something like this: My "freshclam-bad" script looks something like this:
(the email addresses have been changed, of course)
#!/bin/sh # # freshclam-good # # if you want to be notified whenever the virus # definitions are updated, add some code here to # send yourself an email or whatever. # update qmail-scanner and simscan version files. if [ -e /var/qmail/bin/qmail-scanner-queue.pl ] then /var/qmail/bin/qmail-scanner-queue.pl -z fi if [ -e /usr/local/sbin/update-simscan ] then /usr/local/sbin/update-simscan fi exit 0 #!/bin/sh # # freshclam-good # # if you want to be notified whenever there is a # problem updating the virus definitions, add some # code here to send yourself an email or whatever. # email notification to phone PATH="/usr/bin:/bin:/var/qmail/bin" cat <<EOF | qmail-inject From: System <postmaster@domain.xyz> To: Phone <1234567890@cell.carrier.xyz> Subject: freshclam error The freshclam program has encountered an error. EOF exit 0

And as you can tell from the sample freshclam.conf file, these scripts are in the /usr/local/sbin directory. They are owned by root and have permissions "0755".

The "update-simscan" program you see mentioned is available on my simscan page. It's basically a setuid wrapper which runs the "simscanmk -g" command as root, and is necessary because the scripts you see here will be running as the "clamav" user, which doesn't have write permission to the /var/qmail/control/simversions.cdb file.


Building the service directories

We will be setting up two different services- one for clamd and one for freshclam.

I keep the daemontools services on my servers organized with the physical service directories all under /var/service.

# cd /var/service
# mkdir -m 1755 clamd
# mkdir -m 0755 clamd/log
# cd clamd
# wget -O run http://qmail.jms1.net/clamav/service-clamd-run
...
# chmod 755 run
# cd log
# wget -O run http://qmail.jms1.net/scripts/service-any-log-run
...
# chmod 755 run

# cd /var/service
# mkdir -m 1755 freshclam
# mkdir -m 0755 freshclam/log
# cd freshclam
# wget -O run http://qmail.jms1.net/clamav/service-freshclam-run
...
# chmod 755 run
# cd log
# wget -O run http://qmail.jms1.net/scripts/service-any-log-run
...
# chmod 755 run

Here are the download links for the run scripts.

File: service-clamd-run
Size: 902 bytes
MD5: 33d53c07d4b156c09ba8ede35af92e3c
SHA-1: 681945dc77b94800e2a3fae4de6b629dfba4bf98
RIPEMD-160: 56f1c050a684d399485729ca90500e567fb1bf0c
PGP Signature: service-clamd-run.asc
File: service-freshclam-run
Size: 921 bytes
MD5: 40c089b19883b6d7a9fe60c374c9998b
SHA-1: b96bb58b046cee6af28de929a732a587671d4b98
RIPEMD-160: b6c80e24ad189ffed09bdf8b7d0f29bfd0af7f2a
PGP Signature: service-freshclam-run.asc

Starting the services

Starting the services is just like starting any other daemontools services- simply create a symbolic link from the "/service" directory to wherever the physical service directory is.

# cd /service
# ln -s /var/service/clamd .
# ln -s /var/service/freshclam .

Wait a few seconds, and then use svscan to make sure the services are running correctly. You should see up-times of two or more seconds.

# svstat /service/clamd /service/freshclam
/service/clamd: up (pid 7172) 7 seconds
/service/freshclam: up (pid 7190) 7 seconds