
				.:. QSCAN .:.
                        Documentation for version 1.0
                        
                        
                        
           ------------------------ BLURB ------------------------


  The Qmail virus scanner (QScan) is a mail filter for Qmail that scans
incoming messages using the Sophos Antivirus engine, immediately rejecting
infected content.

  It is designed to be minimalistic, yet extremely fast and secure, and uses
multiple pipes instead of the traditional temporary files and privilege
separation.

  It works with non-native versions of the virus scanner (such as under OpenBSD
with Linux or FreeBSD emulation). 


       ------------------------ REQUIREMENTS ------------------------
           

  QScan requires three properly installed helpers :

 - ripmime, available from http://www.pldaniels.com/ripmime/
 
 - sweep, part of the Sophos Antivirus - http://www.sophos.com/
 
 - Qmail :)


       ------------------------ INSTALLATION ------------------------
       

  You must create a temporary directory to extract MIME attachments,
and replace Qmail's original qmail-queue program with Qscan. Quick way to
achieve this for the impatients :

mkdir /var/qmail/qscan
chmod 700 /var/qmail/qscan
chown qmaild:qmail /var/qmail/qscan
ln /var/qmail/bin/qmail-queue /var/qmail/bin/qmail-queue-old

  Now, let's compile and install Qscan :

./configure --help

./configure [your beloved flags]

make install-strip

  The last step is to replace the original qmail-queue program with our
filter :

rm /var/qmail/bin/qmail-queue
ln -s /usr/local/sbin/qscan /var/qmail/bin/qmail-queue

  Depending on your local configuration, it may be needed or not, but start
with doing it :

chown qmaild:qmail /usr/local/sbin/qscan
chmod 6711 /usr/local/sbin/qscan

  After testing, if everything's ok for you, remove the setuid bit :
  
chown 0:0 /usr/local/sbin/qscan
chmod 711 /usr/local/sbin/qscan

Nota :

  To compile under Irix, you have to issue this before typing ./configure :

export CC=cc
export CFLAGS=-I/usr/freeware/include
export LDFLAGS=-L/usr/freeware/lib32

  To compile under Solaris 8, use GNU Make, not Solaris basic make. Then do :

export PATH=/usr/ccs/bin:$PATH
export MAKE=gmake


     ------------------------ CONCURRENCY LIMITS ------------------------


  As virus scanning is a CPU-intensive operation, QScan tries to be smart and
enforces a concurrency limit. By default, only 10 mails are scanned for
virus at the same time. It doesn't mean that you can't receive more
simultanous mails, though. You can receive an unlimited number of mails
coming from the local network, and an unlimited number of mails without
attachments from the network. But mails coming from a remote source with
suspect attachments will be a bit delayed if already 10 scanners are currently
running. It's a preventive mesure against unwanted CPU hogs.

  If your system is fast enough, you can raise the limit with the
--with-concurrency switch passed to the 'configure' script. For instance :

./configure --with-concurrency=10

  On the other hand, on low-end personal machines, you can lower that limit
down to 1.  


           ------------------------ USAGE ------------------------
           
           
  Once the link from /var/qmail/bin/qmail-queue to /usr/local/sbin/qscan has
been created, the filter should be active.

  Check that everything's working by sending *FROM A REMOTE MACHINE* a mail
with random content. The delivered mail should have a Received: header line
with 'qscan' in its content.

  Then, check the virus scanner by sending the traditional EICAR fake virus.
Your mail should be blocked, and additional info should be logged in
/var/log/maillog (or wherever your syslog messages with the 'mail' facility
are going to) .

  To avoid useless MIME extraction and analys, Qscan will bypass all filters
and directly replace itself with qmail-queue-old if :

 - the mail was locally injected. Local redirections through .qmail files
and fastforward are smartly handled, scanning only occurs once.

 - the QS_BYPASS environment variable is defined. Feel free to define it the
same way you define RELAYHOST to allow relaying to your internal network.


       ------------------------ ARCHITECTURE ------------------------


  qmail-smtpd a,d qmail-qmtpd feed qscan with two streams as data is received
from a remote client :

 - descriptor 0 contains the body of the incoming message,
 - descriptor 1 is the envelope data.
 
  After sanity checks, qscan spawns ripmime and qmail-queue-old. The message
is read from qmail-smtpd and asynchronously dispatched to ripmime and
qmail-queue-old.

                                     +------> qmail-queue-old (0)
                                     |
                                     |
         qmail-smtpd (0) -------> qscan
                                     |
                                     |
                                     +------> ripmime (0)

  ripmime fills /var/qmail/qscan/<uid>/ with found attachments, and
qmail-queue-old stores the original data in a temporary queue.

  ripmime is then killed, while qmail-queue-old stays on hold, waiting for
envelope data.  

  If /var/qmail/scan/<uid>/ is not empty, the current concurrency is
evaluated by reading the number of directories in /var/qmail/scan/ . If the
concurrency is above the max one, the client is placed on hold until the
number decreases. If the number is still high after one minute, a 99 error
code (temporary error) is returned, so that the remote client will retry
later. Please note that there's a little race, as no locking is made when
evaluating the number of active scanners. In a real world, it's not harmful,
and it keeps the code simple.
  
  As soon as possible, the sweep virus scanned is spawned to walk into the
/var/qmail/scan/<uid> directory. qscan read the output of the sweep command
to check for alerts.

                                     +------> qmail-queue-old (0)
                                     |
                                     |
         qmail-smtpd (0) -------> qscan
                                     ^
                                     |
                                     +------- sweep (1)

  If a system call fails, or if a child unexpectedly dies, qscan removes the
MIME extraction folder and exits with error code 99.

  If a virus is reported, qscan send the report to syslog, removes the MIME
extraction folder and exits with error code 39 (reported as a permanent
error by qmail-smtpd) .

  In both cases, an early closed pipe causes qmail-queue-old to clean its
own queue.

  If the message can safely be delivered, qscan transparently bridges the
envelope from qmail-smtpd to qmail-queue-old :

         qmail-smtpd (1) -------> qscan -------> qmail-queue-old (1)
         
  Once the envelope has been fed, qmail-send is triggered and injects it in
the Qmail's todo queue.


  ------------------------ SECURITY CONSIDERATIONS ------------------------


  qscan needs read and write access to the /var/qmail/qscan directory.
  ripmime needs only write access to the /var/qmail/qscan directory.
  sweep needs only read access to the /var/qmail/qscan directory.

  ripmime and sweep can be chroot()ed and/or systraced.
  
  No shell is ever spawned.
  
  




                        -Frank DENIS "Jedi/Sector One" <j@pureftpd.org> .
