/*
 * -----------------------------------------------------------
 *
 *   Dr.Web(R) Mail Filter for Sendmail [*]
 *
 * -----------------------------------------------------------
 */

1. Requirements
2. Providing interaction of Sendmail and drweb-smf
  2.1 The way it works 
  2.2 Modifying sendmail.mc and sendmail.cf
  2.3 Configuring drweb-smf
  2.4 About processing SIGHUP
3. Building Sendmail with Mail Filter API support
  3.1 Applying patches for Sendmail
  3.2 Building from separate source texts
  3.3 Building Sendmail from FreeBSD distribution
  3.4 Building Sendmail from FreeBSD ports
4. Known problems
5. Contacts


        1. Requirements

- Started Dr.Web Daemon (drwebd) version 4.33 or higher
- drweb-smf filter
- Sendmail sources version 8.11 or higher. The filter does not work with
  versions 8.12.0 Beta1-Beta9 because of the error in Sendmail,
  corrected in the following beta-versions. They are required only if
  Sendmail has no Milter API support, some distributors now deliver
  Sendmail with Milter API support pre-included.


        2. Providing interaction of Sendmail and drweb-smf

We suppose that your Sendmail supports Milter API already, otherwise
turn to the paragraph 3, where it is described how to re-build
Sendmail with the necessary API support.

   2.1 The way it works

So what Sendmail Mail Filter API can provide:

+----------+      +------------------------+      +--------+
| sendmail |<---->| milter-api | drweb-smf |<---->| drwebd |
+----------+    ^ +------------------------+    ^ +--------+
                1                               2

    1. Through the transport connection, that drweb-smf identifies by
its transport address __ADDRESS__ (see below), the inner Milter API
commands and the message are transferred. As for the message, it is
transferred not as a whole, but by parts, depending on the mailing
session phase: helo, mail from:, rcpt to: etc. That is why the filter
saves the message in temporary files (see the -f option). Through Milter
API drweb-smf reports what is to be done with the message. Milter API is
a multi-stream library and thus several mailing sessions can be
processed simultaneously. So, considering this interaction, Sendmail is
a client, and the mail filter performs the server function, that is why
the filter address should be specified (in sendmail.cf and in the filter
command line), and Sendmail will choose for this connection an
appropriate client's address.

    2. Through another transport connection drweb-smf by means of Dr.Web
Daemon API interface transfers commands (and the message, if the local
mode is not enabled by the -l option) to the daemon and waits for an
answer. A positive answer received (the message is "clean"), the
temporary file is deleted and Sendmail gets the permission to receive
this letter. A virus found, the message is transferred to the infected
messages archive (see the -a option), the message itself gets changed by
the notification sent to the addressees and (optionally) to the sender
(the -x option) and to the administrator (the -g option). In case of
errors during the message processing the -b option is activated.
Regarding the given interaction the filter is a client, whereas the
daemon operates as a server, the daemons address is specified (in
daemon's ini file and in the filter command line).

Thus drweb-smf is just an agent (or a converter) between Sendmail
interface and drwebd. All the three programs can be run on different
computers, but the optimal variant will be to run the filter and the
daemon on one and the same computer, that will allow to (with the -l
option enabled) transfer the message only once, as the daemon will scan
it as local disc file.

   2.2 Modifying sendmail.mc and sendmail.cf

If you would like not to re-build sendmail.cf, you can just insert or
add (if the corresponding definitions already exist) into sendmail.cf:

For Sendmail version 8.11:
-------------------- cut ------------------
############################
# Input mail filters
############################
O InputMailFilters=drweb-filter
############################
#      Xfilters
############################
Xdrweb-filter,  S=__ADDRESS__, F=T, T=S:5m;R:5m;E:1h
-------------------- cut ------------------

For Sendmail version 8.12 and greater:
If you want using virus checking for locally submitted messages (thru
calling mail or sendmail utility) you should duplicate all changes to
submit.cf (and submit.mc) too. Also you should add to "O PrivacyOptions
option" "nobodyreturn" value. For example:
-------------------- cut ------------------
# privacy flags
O PrivacyOptions=goaway,noetrn,nobodyreturn
-------------------- cut ------------------

or in {sendmail_src}/cf/cf/feature/msp.m4:

-------------------- cut ------------------
define(`confPRIVACY_FLAGS' `goaway,noetrn,nobodyreturn,restrictqrun')dnl
-------------------- cut ------------------

Now come to changing sendmail.cf:

-------------------- cut ------------------
############################
# Input mail filters
############################
O InputMailFilters=drweb-filter
O Milter.LogLevel=6
############################
#      Xfilters
############################
Xdrweb-filter,  S=__ADDRESS__, F=T, T=C:1m;S:5m;R:5m;E:1h
-------------------- cut ------------------

Now we can set the following flags (F=) for the case when the filter is
inaccessible:

        R               Delivery failed
        T               Delivery temporary blocked
(if neither F=R, nor F=T are not specified, the message will be delivered
without checking)

or add into sendmail.mc (additional options described in README in the
directory with the libmilter library source texts):

for Sendmail versions under 8.11:
------------------- cut ---------------------
define(`_FFR_MILTER',1)
INPUT_MAIL_FILTER(`drweb-filter', `S=__ADDRESS__, F=T, T=S:5m;R:5m;E:1h')
------------------- cut ---------------------

and for Sendmail versions 8.12 and greater:
------------------- cut ---------------------
INPUT_MAIL_FILTER(`drweb-filter', `S=__ADDRESS__, F=T, T=C:1m;S:5m;R:5m;E:1h')
define(`confMILTER_LOG_LEVEL',`6')
------------------- cut ---------------------

Note. Timeout value should correspond to Sendmail timeout values
"O Timeout.datablock=XX" (it is 1hr by default, XX=>1h)

And then you should recompile sendmail.cf.

Note.
__ADDRESS__ - is a line setting filter connecting transport. Its format
and value is identical to that used in the filter configuration file
(parameter MilterAddress). It may be for TCP/IP socket family:

inet:__PORT__@__HOST__

(__PORT__ and __HOST__ must have concrete values, e.g., inet:3001@localhost)

or for UNIX-DOMAIN sockets:

local:__SOCKPATH__

(similarly __SOCKPATH__ must specify the path accessible with
the rights the filter will be run with, e.g. local:/var/run/drweb-smf.sock)

For details on setting up the filter see the Sendmail documentation
(starting with {sendmaildir}/libmilter/README).

Restart Sendmail.

!!! The optimal way is to run daemon and filter (but not necessarily
Sendmail) on one and the same computer because it will allow to perform
local files scanning without transferring the message through the
sockets. For this the daemon's and the filter's rights should be
sufficient to access the general directory and enough to read temporary
 files created by the filter.

To enable the filter to display sendmails message ID (message
identification number for Sendmail) in the log file when outputting the
message, make sure the following line is present in sendmail.cf:

------------------- cut ---------------------
O Milter.macros.envfrom=i, ... 
------------------- cut ---------------------

(dots stand for other parameters - their values are not important).

To enable writing last relay IP address into the Received: header, make
sure that there is the following line in sendmail.cf:

------------------- cut ---------------------
O Milter.macros.connect=_, ...
------------------- cut ---------------------

(dots stand for other parameters - their values are not important).

To suppress output into syslog of the alike messages:

------------------- cut ---------------------
X-Authentication-Warning: some.domain.com: drweb set sender to DrWeb-DAEMON@some.domain.com using -f
------------------- cut ---------------------

include drweb user (or the one who is running drweb-smf) into the
trusted-users list in submit.cf file

------------------- cut ---------------------
#####################
#   Trusted users   #
#####################
Tdrweb
------------------- cut ---------------------

or add to submit.mc

------------------- cut ---------------------
define(`confTRUSTED_USERS', `drweb')"
------------------- cut ---------------------

   2.3 Configuring drweb-smf 

Filter parameters are set up in the configuration file. If started with
no parameters the filter is trying to find the configuration file in
standard (for the filter) directories which you can easily find out by
starting the filter from the console:

$ drweb-smf --help

If the given location of the configuration file does not suit you, by
any reason, you can explicitly set up configuration file name by
specifying in Content Filtering not only the path to the filter, but
also setting up the parameter:

{path/to}/drweb-smf --conf={path/to/conf/file}

Attention: {path/to/conf/file} should contain filename too

After that you should edit the configuration file and set up
notification templates. When started, the filter is trying to check its
operability in the given configuration by creating and checking a test
file in the spool.

For the description of the filter configuration file, notification
templates and the trusted users list see conf_file.txt, notify.txt and
users_list.txt correspondingly.

To get filter version you can run filter:

$ drweb-smf --version

To test correctness of filter configuration file you can run filter:

$ drweb-smf --check_only

or

$ drweb-smf --check_only --check_user={USER}

The filter will starts (drop privilegies to {USER} if --check_user=
specified), reads configuration file and test options. Filter will
reports into standard output stream (stdout) about actions.


   2.4 About processing SIGHUP

Correct processing of SIGHUP is possible only in two cases:

- used precompiled version of filter (built by DrWEB authors)
- or applying patch to sendmail-8.12.9 (sendmail-8.12.9.patch).

In all other cases the filter will be aborted by SIGHUP.

Currently, the filter makes the following actions then receives HUP
signal:

- reloads DenyList file (see the [Scanning] section in the
  configuration file)
- reloads UnnotificableVirusesList and UnnotificableAddressesList files
  (see the [Actions] section)

    
        3. Building Sendmail with Mail Filter API support
    
You need to build Sendmail with Mail Filter API support. If it is
already done do not doubt to pass to the paragraph 4, but do not forget
to copy libmilter.a and libsmutil.a for version 8.11.x (Linux) or
libsm.a for version 8.12.x (libsmutil or libsm needed for Linux, not
needed for FreeBSD) into /usr/local/lib, and mfapi.h into
/usr/local/include.

   3.1 Applying patches for Sendmail

Applying patches is not obligatory. There available three patches:

listener-8.11.1 - fixes the bug with filter core dumping on exit. Fixed
in next versions of Sendmail

listener-8.12.0 - fixes the bug when filter use unix-socket and
socket-file has not deleted at exit. Fixed in version 8.12.2

$ cp listener-8.1X.Y.patch /place/where/source/texts/are/libmilter
$ cd /place/where/source/texts/are/libmilter
$ patch < listener-8.1X.Y.patch

sendmail-8.12.2 - fixes the bug when message size is growed up to
double, if filter used with demo key. Will be fixed in version 8.12.3

$ cp sendmail-8.12.2.patch /place/where/sendmail/source/tree/are/located
$ cd /place/where/sendmail/source/tree/are/located
$ patch < sendmail-8.12.2.patch

   3.2 Building from separate source texts

From now on {sendmaildir} stands for the directory where Sendmail has
been unpacked (e.g. /usr/local/src/sendmail-8.xx.x):

$ cd {sendmaildir}

Step A)
We should indicate that we'd like to build with the support of libmilter,
for this:

$ cd {sendmaildir}/devtools/Site/

If the site.config.m4 file does not exist, create it, and if it does,
add into it the following lines:

for Sendmail versions under 8.12.x:
--- cut ---
dnl Milter
APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER')
APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER')
--- cut ---

for Sendmail versions from 8.12.0 to 8.12.8 or if your system does not
support poll system call:
--- cut ---
dnl Milter
APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
APPENDDEF(`conf_libmilter_ENVDEF', `- D_FFR_MILTER')
--- cut ---

for Sendmail versions from 8.12.9 and later:
--- cut ---
dnl Milter
APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_USE_POLL')
--- cut ---

If there occur any errors when building Sendmail then you should
probably add the following lines:
--- cut ---
APPENDDEF(`confLIBSEARCH', `db db2 bind resolv 44bsd')
APPENDDEF(`confINCDIRS', `-I/usr/include/db2/ -I/usr/include/db1/')
APPENDDEF(`confMAPDEF', `-DNEWDB ')
--- cut ---

Step B)
Now building libmilter library:

$ cd {sendmaildir}/libmilter
$ ./Build -c

It is only left to build and install Sendmail itself:

$ cd {sendmaildir}
$ ./Build -c

Now let's install Sendmail the way it is described in {sendmaildir}/INSTALL
file.

   3.3 Building Sendmail from FreeBSD distribution (/usr/src/contrib)

If you have FreeBSD, the first thing to do is to add into make.conf
(located by default in /etc/defaults/) the following line:

for Sendmail versions under 8.12.x:
SENDMAIL_CFLAGS=-D_FFR_MILTER

for Sendmail versions from 8.12.x:
SENDMAIL_CFLAGS=-DMILTER

It is assumed that your directory arrangement is standard for FreeBSD
4.x. Otherwise, you will need to perform a few minimal and quite
clear changes (from now on $ stands for shell prompt):

$ cd /usr/src/lib/libsmutil
$ make clean all
$ cd /usr/src/lib
$ mkdir libmilter
$ cd libmilter

Creating in this directory Makefile containing the following:

-------------------- cut --------------------------
SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
.PATH:  ${SENDMAIL_DIR}/libmilter

CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include
CFLAGS+=-DNEWDB -DNIS -DMAP_REGEX -DNOT_SENDMAIL

# User customizations to the sendmail build environment
CFLAGS+=${SENDMAIL_CFLAGS}

LIB=    milter

SRCS+=  comm.c engine.c handler.c listener.c main.c signal.c sm_gethost.c smfi.c

INTERNALLIB=        true
NOPIC=              true
INTERNALSTATICLIB=  true

.include <bsd.lib.mk>
--------------------- cut --------------------------

Then:

$ make clean all

Rebuilding Sendmail itself:

$ cd /usr/src/usr.sbin/sendmail
$ make clean all install

   3.4 Building Sendmail from FreeBSD ports

If you are building Sendmail (version 8.11.5 or higher, but might be
lower) from FreeBSD ports collection, you can just edit /etc/make.conf
and set the following option:

SENDMAIL_WITH_MILTER=Yes

and go on with the usual Sendmail building process.


        4. Known problems

Description: When using Unix socket to provide communication between
the filter and Sendmail Milter API supporting library (delivered
together with Sendmail) did not remove (up to the version 8.12.2) the
socket-file.

Solution: For the version 8.12.x you can find the
listener-8.12.0-1.patch. The installation process is similar (but for
the file name) the one described in the paragraph 3.1. For versions 8.11
you will have to remove the file or from the script managing the filter.
Or upgrade to version 8.12.2 or above

Description: When using "LocalScan" mode and evaluation key, the message
size value, that reported to next mail server, doubled (really message
stay as is or increased at length of short banner)

Solution: Upgrade sendmail to version 8.12.3 or above

Description: When using on heavy loaded systems, you can see in mail
logs similar records:
"... Milter (drweb-filter): select(read): interrupted system call"

Solution: Upgrade sendmail to version 8.12.3 or above

Description: When using on heavy loaded systems, you can see in mail
logs similar records:
"... Milter (drweb-filter): select(read): timeout before data write"
"... Milter (drweb-filter): to error state"

Solution: Sendmail cannot establish connection with the filter for the
specified timeout. In versions 8.11 it equals to 5 seconds and cannot
be changed, in versions 8.12 this timeout can be changed in the filter
description (with the C: value)
Xdrweb-filter, S=__ADDRESS__, F=T, T=C:1m;S:5m;R:5m;E:1h


        5. Contacts

Dr.Web program gets constantly developed, for fresh updating
information and news please visit our site:
  http://www.drweb.com

Marketing dept.:
  http://buy.drweb.com
  E-mail: sales@drweb.com

Support:
  http://support.drweb.com
  E-Mail: support@drweb.com

Please include following information in your problem report: 

- full name and version of your unix distribution
- Dr.Web version that is logged during program start
- versions of applications and filters which use Dr.Web Daemon.
- configuration files: daemon's (drweb32.ini), drweb_smf.conf
- logs: daemon and mail (usually maillog)
- fragment of sendmail.cf with data on the filter
  (all the lines containing "drweb-filter")

-----
* - Sendmail is a trademark of Sendmail, Inc.
