#####################################################################
 $Id: README 280 2005-05-10 17:50:26Z crosser $
#####################################################################

	WHAT IS IT:
		modularized contentfilter for Zmailer and Sendmail
	COPYRIGHT:
		(c) 2003-2005 Eugene G. Crosser <crosser@average.org>
	LICENSE:
		The same set as apply to Zmailer code
	NOTE:
		distribution contains third party source code
		with possibly different copyright:
		- strlcpy implementation from OpenBSD
		- lhash implementation from SSLeay/OpenSSL
		- getopt implementation from FSF
	HOMEPAGE:
		http://www.average.org/zmscanner/

#####################################################################

The goal of this project is to get a reasonable tradeoff between speed
and features.  It sould be easy to add or exclude modules, to write
new modules and distribute them independently from the core package.
The program makes use of the `new' (as of this writing) contentfilter
interface of Zmailer (http://www.zmailer.org/) where communication takes
place over unix domain socket.  When it gets a path to Zmailer message
file, the program starts a thread or forks, the thread/child mmaps
the file(readonly) (or pulls into memory if you don't have mmap()),
and invokes plugins that claimed the initial `stage' (by default,
"zmsg").  Each plugin may fill in the `ans' buffer and must return
either ZMSCAN_CONTINUE or ZMSCAN_STOP.  In the latter case, no further
plugins are called and the `ans' buffer is passed over to smtpserver.
Each plugin can also invoke other `stages' or even the same `stage', in
which case it will be called resursively.  It should check the return
code of stage invocation and return immediately if it gets anything
other than ZMSCAN_CONTINUE.

Starting from version 2, there is a Milter frontend binary, named
smscanner.  It aims at providing Sendmail interface to the same plugin
modules as zmscanner, but there is a number of differences.  First of all,
milter does not provide the whole received RFC822 message, so it is not
possible to use a module that wants the whole message on input.  Second,
milter passes control in the course of reception, so it is possible
to reject a message before it's body (or even headers) are received.
This is unlike zmailer filter that passes control after the whole message
is received and written to disk (but before reception is acknowledged
to the peer).  Third, because milter approach assumes passing the whole
message over a socket, milter version may be much more resource hungry,
both cpu-wise and memory-wise, than Zmailer version which mmaps the
message and tries to avoid data copying.

Because milter does not allow scanning the whole message, smscanner
cannot use a "single point of entry" stage 'initstage'.  Rather,
it calls separately 'peerdata', 'helo', 'envfrom', 'envrcpt', 'rfc822hdr'
and 'body' stages.

Plugin scanning function must me thread-safe and reentrant.
Initialization function does not need to be.

Plugin functions may be compiled in or dynamically loadable (if your OS
supports dynamic objects).  To compile in a plugin, put the source into
`plugins' subdirectory and run ./configure --with-plugins="blank separated
list"; include the name of your source file (without ".c" suffix).

Dynamically loadbale plugins may be built independantly; but they
need access to "zmscanner.h" and "libzmscanner.a"; these are normally
installed at default locations, /usr/local/include and /usr/local/lib.
Plugin source must include a ZMS_MODULE() macro which specifies what
`stage' to claim, internal name of the module, and three functions -
plugin initialization (may do configuration parsing etc.), plugin
termination, and data scanning.  See the source for examples.

The daemon itself is designed in such a way that when you kill the parent
process with SIGUSR1, it forks and execs its own binary (which could
have been upgraded in the meanwhile) without closing the control socket.
When the child initializes and is ready to process requests, it signals
the parent with SIGUSR2 which causes graceful shudown of the process
after all active processing threads terminate.

There are several useful external plugins available, e.g. zms_clamav
that doe virus scanning on non-text body parts, zms_dehtml that strips
HTML tags off text/html parts, and zms_pcre that scans text body parts
for regular expresstions using pcre library (http://www.pcre.org/).

#####################################################################

Appendix: building from Subversion:

$ svn co svn://svn.average.org/zmscanner/zmscanner/trunk zmscanner
$ cd zmscanner
$ aclocal -I m4
$ autoheader
$ libtoolize
$ automake -a
$ autoconf
$ ./configure --various-options 

Plugin modules are in svn://svn.average.org:/zmscanner/<module>/trunk
