[Avcheck] Installing Kaspersky's AVP, AVCheck for FreeBSD 4.x

Michael Kubecka mkubecka@swansystems.com
Tue, 13 Nov 2001 11:46:23 -0800


Hopefully this will help Len...

Please let me know about any corrections or errors...


======================================

Version 1.0, installation instructions for FreeBSD 4.x.

PURPOSE OF THIS DOCUMENT
Michael Tokarev indicates that the AVCheck HOWTO is out of date.  The
manual which comes with Kaspersky's anti-virus software for *BSD is
poorly written, out of date and contains many errors.  Consequently, I
have gleaned information from these sources as well as the README.AVP
and README.POSTFIX in the AVCheck archive and organized it in order to
install AVCheck and Kaspersky's AVP software under FreeBSD.  This
document borrows heavily from those documents; credit should be given to
Michael Tokarev and Ralf Hildebrandt for the information contained in
this document.


INSTALLING KASPERSKY'S ANTI-VIRUS SOFTWARE AND AVCHECK
Avcheck (http://www.corpit.ru/avcheck/) is a simple program that allows
you to call antivirus software in order to check mail messages for
viruses before actual delivery from within a Mail Transfer Agent, or
MTA. 

Avcheck itself isn't a virus scanner, nor it is an MTA. It sits between
the MTA and real antivirus software. Most MTAs available today can call
an external program for every mail message in order to perform various
tasks, including virus scanning and content filtering. Avcheck can be
used as that external program. 

Avcheck will receive a mail message from a mail system, pass it to an
antivirus software, and, depending on the presence of a virus in that
message, will either allow the message to be delivered or take
appropriate actions to handle infected mail. 

Avcheck does nothing with a mail message contents -- its task is to
prepare file with a mail message and feed it to an antivirus program. 
It's an antivirus task to decode MIME structure, handle embedded
archives and so on. Many but not all antivirus products today have this
ability. 

Initially, Avcheck was written as a little hack that allows to use an
excellent MTA -- Postfix -- together with AVP antivirus daemon.  Later,
it was developed into a more general system that can be used with
different antivirus engines and different MTAs, with flexible
configurable actions to infected mails, while still remaining very
simple. 

Amavis, "A Mail Virus Scanner", by Lars Hecking, is a similar project.
The main difference between Amavis and Avcheck is that Amavis decodes
MIME structure of a mail message and extracts attached archives etc.
itself, using perl modules and various external programs, and feeds only
plain files to the virus scanner. This way, it doesn't depend on ability
of an antivirus software to handle archives and MIME. 


INSTALLING AVCHECK
First we're going to install Michael Tokarev's AVCheck
(http://innominate.org/~hildeb/postfix/avpcheck.HOWTO,
http://www.corpit.ru/avcheck/).  The software was originally called
AVPCheck, but has since been renamed AVCheck because it interoperates
with multiple anti-virus packages.  For consistency, I will refer to it
as AVCheck.

AVCHECK documentation also assumes installation in /var/spool/avp.  For
the purposes of this document, I have standardized on installing
chroot'd applications in /var/chroot.  Thus, we will be installing
AVCHECK in /var/chroot/AVP.  

AVCheck runs in a chroot'd environment.  Create low-privileged user
accounts for use with AVCheck: 

# pw groupadd -n avgroup
# pw useradd -n avdaemon -g avgroup -s /sbin/nologin -d /nonexistent \
-c "AVP Daemon"
# pw useradd -n avclient -g avgroup -s /sbin/nologin -d /nonexistent \
-c "AVP Client"

Now download the latest AVCheck software:

# cd /var/tmp
# fetch http://www.corpit.ru/ftp/avcheck/avcheck-0.5.tar.gz
# tar zvxf avcheck*
# cd avcheck*

Compile it and install the man page.  Make sure you are running sh or
bash, not csh.  Otherwise, perform the make command as "make
SHELL=/bin/sh".  FYI, you probably shouldn't build this software as
root...

# bash
# make
# mv avcheck.1 /usr/local/man/man1

Now we'll create the chroot'd environment for AVCheck to run in.

# mkdir -p /var/chroot/AVP
# chown root:wheel /var/chroot/AVP
# chmod 755 /var/chroot/AVP

# cd /var/chroot/AVP
# mkdir Bases ctl tst tmp dev proc
# chown avdaemon:avgroup ctl
# chown avclient:avgroup tst
# chown avdaemon:wheel tmp
# chmod 750 tst ctl
# chmod 700 tmp
# cp -pR /dev/null /dev/console dev/

(The proc directory above is probably not needed, but it's indicated in
the Linux-slanted README.  Some documentation has suggested changing
group ownership of dev/console to avgroup.  That does not seem to be
necessary for FreeBSD.)

Now move the appropriate AVCheck files into the chroot:

# mv /var/tmp/avcheck*/uchroot /usr/local/sbin
# mv /var/tmp/avcheck*/avcheck .
# mv /var/tmp/avcheck*/infected.ex1 .
# mv /var/tmp/avcheck*/infected.ex2.en .
# mv /var/tmp/avcheck*/eicar* .
# chown root:wheel /usr/local/sbin/uchroot avcheck infected*

Per Michael Tokarev: You don't need to copy infected and avcheck into
the chroot jail.  We are doing so here only to make this simpler.  

avcheck runs a helper script in the same path as avcheck called
"infected".  The helper is separated from avcheck itself to allow you to
customize the infected message's handling more easily.  You need only
one helper, though two examples are provided.

infected.ex2.en is the best choice to use.  Rename it to "infected":

# mv infected.ex2.en infected

Examine the script.  You may want to customize it.

INSTALLING KASPERSKY'S FREEBSD ANTI-VIRUS SOFTWARE
Now, download the Kaspersky FreeBSD trial software from: 

ftp://ftp.kaspersky.com/AvpTest/AvpFreeBSD/4X
http://http.kaspersky.ru/AvpTest/AvpFreeBSD

You'll need a login and password, which you can get from Kaspersky.

Download kav-ServerSuit-3.0.136-FreeBSD-4.x.tgz which, when
uncompressed, contains:

kav-WorkStationSuit-3.0.136-FreeBSD-4.x.tgz
kav-exim-3.0.136-FreeBSD-4.x.tgz
kav-postfix-3.0.136-FreeBSD-4.x.tgz
kav-qmail-3.0.136-FreeBSD-4.x.tgz
kav-sendmail-3.0.136-FreeBSD-4.x.tgz

Store it in /var/tmp.  Then:

# pkg_add -vp /var/chroot kav-WorkStationSuit-3.0.136-FreeBSD-4.x.tgz
# pkg_add -vp /var/chroot kav-postfix-3.0.136-FreeBSD-4.x.tgz

The software would ordinarily be installed in /usr/local/share/AVP. 
However, we've just forced it to be installed in our chroot'd
directory.  If you don't already have wget, you should install that as
well. 

# pkg_add -r wget

Unfortunately, the PDF manual for the FreeBSD version of the software
has not been updated and contains several omissions and errors. 
Similarly, some of the scripts that come with software are buggy and
require modifications.

Change directory into /var/chroot/AVP and edit kavupdater.sh and change:

	/usr/bin/wget

to

	/usr/local/bin/wget

from (notice the typo in the pathname)

	if [ -r /usr/local/share/AVP/AvpUnix.ini ]; then
        INIFILE=/usr/local/shar/AVP/AvpUnix.ini	

to

	if [ -r /var/chroot/AVP/AvpUnix.ini ]; then
        INIFILE=/var/chroot/AVP/AvpUnix.ini

from

	./checkurl -u=$DPARMS -t=5 -d	

to

	./Tools/checkurl -u=$DPARMS -t=5 -d

from

	AVPUpdater -uik=$DPARMS -o -y

to

	./kavupdater -uik=$DPARMS -o -y

The AvpUnix.ini file contains configuration details for the software. 
For instance, it contains the path to the directory which holds the
virus definitions, /var/chroot/AVP/Bases.  Create that directory now.

# mkdir -m 755 /var/chroot/AVP/Bases

Edit AvpUnix.ini and add the following:

	UpdatePath=http://www.kaspersky-labs.com/updates/

Otherwise the kavupdater.sh file will not know where to get the latest
virus definitions.  The above URL was chosen from the Updates.1st file. 
If for some reason there are problems with the above URL, choose another
one from that file.

If you have a key file, you should copy that to /var/chroot/AVP now,
naming it AvpUnix.key.  It needs to be readable.  World-readable is
probably fine.  

NOTE: Without a key, the anti-virus software will operate in demo mode
and therefore be unable to look into MIME attachments.  It will, for
instance, fail to detect a virus in the AVCheck-included eicar.msg test
message, but will find it in the simple eicar.txt file.

You can request a trial key from Kaspersky.

Since the anti-virus software does not come loaded with virus
definitions, you must load them now.

# ./kavupdater.sh

At the end of the output, you should see "0 - Antiviral bases correctly
loaded."  That does not mean that no antivirus files were loaded. 
Rather it means that the script exited with error code 0 (no errors),
and that all the anti-virus databases were correctly loaded.

Be sure to set permissions properly after each update:

# chmod 644 Bases/*
# chmod 755 Bases

CONFIGURING AVCHECK AND THE ANTI-VIRUS SOFTWARE
Remember that kavdaemon will eventually run chrooted, so it will see
/var/chroot/AVP as / -- all paths should be modified accordingly.

There are two configuration files used by kavdaemon: defUnix.prf and
AvpUnix.ini. Those files should be in the top-level chroot directory, as
well as the kavdaemon executable.  AvpUnix.ini contains configuration
information and should be modified as follows to allow it to be
chrooted:

 KeysPath=/      # place AvpUnix.key file into /var/chroot/AVP/
 BasePath=/Bases # where virus DBs can be found

Next, edit the defUnix.prf file.  Some values should be changed,
otherwise things will not work.  Here is a list of recommended
changes/additions.  If one of these lines doesn't exist in your
defUnix.prf file, then add it.

[Location]
List=/tst # which objects will be allowed to scan;
          # note that sometimes kavdaemon wan't look into here,
          # and this list should be repeated in it's commandline too

[Object]
# Note that this section may be called "Object" -- check your
defUnix.prf
MailBases=No
# MailBases are things like MS Exchange, MS Outlook and so on mail
# storages, in internal format.  There is no need to enable scanning
# of such "files" (we will scan only plain mail messages), and according
# to avp's docs, it will run slower if MailBases will be set to yes
Warnings=No
# This is to stop avp giving warnings on false positives.  When avp
# encounters a file that *looks* like virus, it will give a warning.
# Avcheck will treat such a file as infected.  Setting this parameter
# to No prevents this.  Note that such a "false positive" may in fact
# be NOT false.
InfectedAction=0
# This one is important.  By default, kavdaemon will ask what to
# do with infected mails.  We need only to know if mail is infected
# or not.  Avcheck will complain "uexpected avp return code NN (0xXX)"
# (with numbers in place of NN and XX) if you will not change this
# parameter to 0 (to mean: do *nothing* with infected messages, only
# report that them are infected!)

[Report]
ShowOk=No
ShowPack=No
Report=No
# Obviously.  We don't need tons of messages in syslog!
UseSysLog=No
# In case /var/chroot/AVP/dev/log doesn't exists.  Note that
# this file can't be just created using mknod or something,
# at least on Linux (but on Solaris, creating conslog may
# help).  On Linux, addition `-a /var/chroot/AVP/dev/log'
# option should be specified in syslogd startup script
# in order to allow chrooted kavdaemon to do syslogging.

All other values are fine.

CREATING STARTUP AND UPDATE SCRIPTS
Create /usr/local/etc/rc.d/avp.sh:

#!/bin/sh
# Modified from Michael Tokarev's rc.avpd
# For use with *BSD.

# See also:
# http://innominate.org/pipermail/avcheck/2001-August/000098.html

root=/var/chroot/AVP
exe=/kavdaemon
uchroot=/usr/local/sbin/uchroot
pidf=$root/ctl/AvpPid

# -V enables redundant checking, which may
# result in a performance penalty.

args="-dl -MP -f=/ctl /tst"
user=avdaemon
what="AVP Daemon"

action() { echo "$1"; shift; "$@"; }
success() {  return 0;  }
failure() {  return 1;  }

[ -x $root$exe ] || exit 0

cpid() {
  if [ -f $pidf ] && read pid < $pidf && [ -d /proc/$pid ] ; then
    return 0
  else
    pid=
    return 1
  fi
}

start() {
  chmod 644 $root/Bases/*
  chmod 755 $root/Bases
  /usr/bin/env - HOME=/ \
    /usr/bin/nice \
    $uchroot -u $user $root \
      $exe $args \
   && success startup || failure startup
  rc=$?
  # chmod g+w $root/run/sock 2>/dev/null
  echo
  # [ -d $subsysdir ] && touch $subsys
  return $rc
}

restart() {
  echo "Restarting $what:"
  cpid && kill $pid && sleep 1
  start
}

rc=0

case "$1" in
  start)
    if ! cpid ; then
        echo "Starting $what:"
        start
    fi
    ;;
  stop)
    cpid && action "Stopping $what" kill $pid
    # rm -f $subsys
    ;;
  restart|reload) restart ;;
  # note: kavdaemon perfoms strangely when HUP'ed.
  # the following lines will never be executed while
  # `reload' is on above line too.
  reload)
    if cpid ; then
      action "Reloading $what" kill -1 $pid
    else
      echo "No $what running"
    fi
    ;;
  condrestart)
    cpid && restart
    ;;
  status)
    if cpid ; then
      echo "$what (pid $pid) is running..."
      rc=0
    else
      echo "$what is not running"
      rc=3
    fi
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|reload|condrestart|status}"
    rc=1
    ;;
esac

exit $rc

Then…

# chmod a+x /usr/local/etc/rc.d/avp.sh

Create avupdate.sh in /root to start the kavdaemon.  A cron job will
eventually call this script to update the anti-virus databases on a
periodic basis.

#!/bin/sh
# This script assumes Postfix is managed under
# DJ Bernstein's DaemonTools.  Modified from
# examples provided by Michael Tokarev and
# Ralf Hildebrandt.

# defer AVCheck Transport
## postconf -e "defer_transports = avcheck"
svc -d /service/postfix

# kill kavdaemon
cd /var/chroot/AVP
/var/chroot/AVP/kavdaemon -ka && sleep 2

# Get updates
/var/chroot/AVP/kavupdater -y -kb -b=/var/chroot/AVP/Bases \
-ui=http://downloads1.kaspersky-labs.com/updates

# damn permissions!
chmod 644 /var/chroot/AVP/Bases/* > /dev/null
chmod 755 /var/chroot/AVP/Bases > /dev/null

# start kavdaemon as chroot()'ed as unprivileged user avdaemon
# The "echo no" line is needed only for the evaluation version,
# otherwise comment it out.
# echo no | \   # only needed for the evaluation version!
/usr/bin/env - HOME=/ \
/usr/bin/nice \
/usr/local/sbin/uchroot -u avdaemon /var/chroot/AVP \
./kavdaemon -dl -MP -f=/ctl /tst > /dev/null

# un-defer avcheck Transport
## postconf -e "defer_transports ="
svc -u /service/postfix

and…

# chmod u+x /root/avupdate.sh

Use crontab -e to create a cron job to update the anti-virus databases
twice a day.  Since Kaspersky is in Russia, I suggest updating the
databases at 9 AM and 5 PM Moscow time.


COPYING SHARED LIBRARIES INTO THE CHROOT JAIL
The kavdaemon executable is linked dynamically (check with the ldd
command).  So we need to create a lib directory inside /var/chroot/AVP
and copy some system libraries to it.  ldd will show what libraries are
needed.  For example:

# ldd kavdaemon
kavdaemon:
        libintl.so.1 => /usr/local/lib/libintl.so.1 (0x28096000)
        libm.so.2 => /usr/lib/libm.so.2 (0x2809b000)
        libc.so.4 => /usr/lib/libc.so.4 (0x280b7000)

kavdaemon requires the above 3 libraries.  Copy those into the chroot.

# mkdir -p /var/chroot/AVP/usr/libexec/
# mkdir /var/chroot/AVP/usr/lib

# cp /usr/local/lib/libintl.so.1 /var/chroot/AVP/usr/lib
# cp /usr/lib/libm.so.2 /var/chroot/AVP/usr/lib
# cp /usr/lib/libc.so.4 /var/chroot/AVP/usr/lib

Don't forget to copy the dynamic linker itself:

# cp /usr/libexec/ld-elf.so.1* /var/chroot/AVP/usr/libexec


STARTING KAVDAEMON AND TESTING THE SOFTWARE
Now you can start the kavdaemon:

The following command line is needed to properly setup the environment.  

# /usr/bin/env - HOME=/ \
  /usr/bin/nice \
  /usr/local/sbin/uchroot -u avdaemon /var/chroot/AVP \
  /kavdaemon -dl -MP -f=/ctl /tst

Some resource limits can be specified here as well.

A few words about kavdaemon options (you can execute `kavdaemon -?' to
show descriptions) invoked above:

-dl - disable logging.  If not given, kavdaemon will create another
separate process for logging
-MP - check plain mail.
-f=/ctl - where to place AvpSocket and AvpPid files
/tst - directory where it is ok to check files for viruses
(Location.List option in defUnix.prf)

Now, after kavdaemon is ready, you can test the installation. First:

# cd /var/chroot/AVP
# mv infected infected.orig

In order to ensure that anti-virus detection actually works, you can
temporary substitute the infected script with the following one.


#! /bin/sh
MAIL=$1 MSG="$2" FROM="$3"; shift 3
echo "$MAIL (from $FROM, to $*) is infected:"
echo "$MSG"
rm -f $MAIL
exit 0

# chmod a+x infected

Now test the anti-virus software against an EICAR test message:

# cd /var/chroot/AVP
# /usr/local/sbin/uchroot -u avclient / \
  /var/chroot/AVP/avcheck -n -f root -d /var/chroot/AVP/./tst \
  -s avp:/var/chroot/AVP/ctl/AvpCtl root < eicar.msg

(Note that uchroot above is used just like `su' command.)  Your infected
script should run.  In case of any trouble, avcheck will print an error
message to stderr and exit with EX_TEMPFAIL code, so you will be able to
correct the problem.

Running the above line with this script should produce output like the
following:

  /var/chroot/AVP/./tst/123.tmp (from root, to root) is infected:
  infected by EICAR-Test-File

If it doesn't, then try testing the anti-virus software against
eicar.txt:

# /usr/local/sbin/uchroot -u avclient / \
  /var/chroot/AVP/avcheck -n -f root -d /var/chroot/AVP/./tst \
  -s avp:/var/chroot/AVP/ctl/AvpCtl root < eicar.txt

If EICAR-Test-File is successfully detected here, then you probably
don't have a valid license key, or the path to the license key,
specified in AvpUnix.ini is incorrect.  In demo mode, AVP will not scan
MIME attachments (like the one in eicar.msg).

Now:

# mv infected infected.test
# mv infected.orig infected

After you know that your AVP setup works, you can configure your
mail-system.  


CONFIGURING AVP FOR POSTFIX
Read the README.postfix file included in the AVCheck distribution for
more details.

Recent versions of Postfix include the content_filter feature, which
allows you to subject incoming mail to an external program and afterward
re-inject it back into Postfix for delivery.

Add the following line to your /etc/postfix/master.cf file (comments are
as already in master.cf):

#
=======================================================================
# service       type private unpriv chroot wakeup  maxproc command +
args
#                    (yes)   (yes)  (yes)  (never) (50)
#
=======================================================================
localhost:1025  inet  n      -      n      -      -  smtpd -o
content_filter=

(Yes, last character should be an equals sign).

You can add a -o option using smtpd_*_restrictions to stop Postfix from
doing unnecessary checks, e.g. 

-o smtpd_recipient_restrictions=permit_mynetworks,reject

Now add a transport called avcheck into the master.cf file:

# ==================================================================
# service  type private unpriv chroot wakeup  maxproc command + args
#               (yes)   (yes)  (yes)  (never) (50)
# ==================================================================
avcheck        unix    -       n       n       -       5       pipe
        user=avclient argv=/var/chroot/AVP/avcheck
        -d /var/chroot/AVP/./tst -s avp:/var/chroot/AVP/ctl/AvpCtl
        -f ${sender} -S :1025 -- ${recipient}

(The last 3 lines should start with leading whitespace: all 4 lines are
one logical line!)
NOTE: The -S :1025 option tells Postfix the "non-filtering" path to
inject mail should use port 1025 on local host, where the non-filtering
smtp daemon listens (set up above).

You may also want to add `-t timeout' option here as well (specifies a
timeout in seconds for anti-virus operations).  Note that it is useless
to specify a timeout greater than Postfix's command_time_limit (or
avcheck_time_limit if set) parameter (the default is 1000 seconds).  

Now add the following lines to your /etc/postfix/main.cf file:

soft_bounce = yes
content_filter = avcheck

This will scan all mail - even locally-submitted mail - for viruses.  If
you wish to scan only SMTP-submitted mail, see the example in the
AVCheck README.postfix file.

The soft_bounce command is useful for testing to prevent mail from
bouncing in case of an error in your AVCheck setup.  Verify that
everything works as expected, then remove that option from main.cf.

You will now need to reload Postfix (assuming Postfix is supervised by
DaemonTools):

# svc -d /service/postfix
# svc -u /service/postfix

Try sending yourself a clean test message and an infected test message. 
If you view /var/log/maillog, you should see Postfix handing off your
mail to AVCheck, for instance:

Oct 30 12:04:26 frapis postfix/qmgr[82206]: 7E2125D01E:
from=<user@example.com>, size=535, nrcpt=1 (queue active)
Oct 30 12:04:26 frapis postfix/smtpd[82212]: disconnect from
localhost[127.0.0.1]
Oct 30 12:04:26 frapis postfix/pipe[82208]: 510175D01D:
to=<user@yahoo.com>, relay=avcheck, delay=0, status=sent
(frapis.example.com)
Oct 30 12:04:27 frapis postfix/smtp[82225]: 7E2125D01E:
to=<user@yahoo.com>, relay=merkin.mail.yahoo.com[64.157.4.82], delay=1,
status=sent (250 ok dirdel)

AVCheck sends mail with a FROM of "Antivirus-Daemon".  You may want to
add an entry in /etc/aliases or /etc/mail/aliases to drop mail sent to
this automated account:

antivirus-daemon:               /dev/null

Then…

# /usr/bin/newaliases


OTHER WORK LEFT TO BE DONE

* Supervise kavdaemon under DJ Bernstein's DaemonTools and the fghack.
* Make sure that kavdaemon starts first under DaemonTools before Postfix
starts.

...if anybody can supply instructions for the above, that would be
great.  I haven't gotten around to it, yet.