Archive for the Virus Control Category

Set Up Virus and Spam Scanning on Ubuntu 8.10

Posted by Filed Under Virus Control with Comments Off

Install of Amavisd-New on Ubuntu 8.10

One of the most frustrating problems with setting up any mail server is the configuration required for anti-virus protection and Spam checking.  Amavisd-new provides an excellent tool to help in setting that up.  This is a step-by-step process in providing your mail server, the example is Ubuntu 8.10, with the ability to scan all incoming mail for viruses and Spam.

apt-get install amavisd-new

Starting Amavisd-New
In order to get amavisd-new running, execute the command below to view content in debug mode so you can see what it is doing.  One thing you will notice is that by default there is no virus program attached nor any scanning for Spam as it is disabled by default.  The point to note here is the modules that it is using, the ports, and the general look and fell of the program.

/etc/init.d/amavis debug
Trying to run amavisd-new in debug mode…

Jan  9 12:46:47.927 /usr/sbin/amavisd-new[4384]: starting.  /usr/sbin/amavisd-new at amavisd-new-2.6.1 (20080629), Unicode aware, LANG=”en_US.UTF-8″
Jan  9 12:46:47.928 /usr/sbin/amavisd-new[4384]: user=, EUID: 112 (112);  group=, EGID: 123 123 (123 123)
Jan  9 12:46:47.928 /usr/sbin/amavisd-new[4384]: Perl version               5.010000
Jan  9 12:46:47.980 /usr/sbin/amavisd-new[4384]: INFO: no optional modules: IO::Socket::INET6
Jan  9 12:46:47.982 /usr/sbin/amavisd-new[4384]: Net::Server: 2009/01/09-12:46:47 Amavis (type Net::Server::PreForkSimple) starting! pid(4384)
Jan  9 12:46:47.987 /usr/sbin/amavisd-new[4384]: Net::Server: Binding to UNIX socket file /var/lib/amavis/amavisd.sock using SOCK_STREAM
Jan  9 12:46:47.988 /usr/sbin/amavisd-new[4384]: Net::Server: Binding to TCP port 10024 on host
Jan  9 12:46:47.989 /usr/sbin/amavisd-new[4384]: Net::Server: Group Not Defined.  Defaulting to EGID ’123 123′
Jan  9 12:46:47.989 /usr/sbin/amavisd-new[4384]: Net::Server: User Not Defined.  Defaulting to EUID ’112′
Jan  9 12:46:47.989 /usr/sbin/amavisd-new[4384]: Net::Server: Setting up serialization via flock
Jan  9 12:46:47.990 /usr/sbin/amavisd-new[4384]: after_chroot_init: EUID: 112 (112);  EGID: 123 123 (123 123)
Jan  9 12:46:47.990 /usr/sbin/amavisd-new[4384]: config files read: /usr/share/amavis/conf.d/10-debian_scripts, /usr/share/amavis/conf.d/20-package, /etc/amavis/conf.d/01-debian, /etc/amavis/conf.d/05-domain_id,  for       .tar  tried: pax
Jan  9 12:46:48.037 /usr/sbin/amavisd-new[4384]: Found decoder for    .tar  at /bin/cpio
Jan  9 12:46:48.038 /usr/sbin/amavisd-new[4384]: Found decoder for    .deb  at /usr/bin/ar

Enable Virus Checks and Spam Checks

Verify that clamav is running .

sudo /etc/init.d/clamav-daemon start

Modify this line in /etc/default/spamassassin


It is 0 by default so you must enable Spamassassin to be able to run, now start it.

sudo /etc/init.d/spamassassin start

To enable amavisd-new to work with Spamassassin and clamav you need to modify the /etc/amavis/conf.d/15-content_filter_mode.  Uncomment the lines as the root user so they now look like the example and restart amavisd-new in debug mode to view the activity.  Now you will see that clamav and Spamassassin are now working with amavisd-new.


@bypass_virus_checks_maps = (
\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

Jan  9 12:54:47.978 /usr/sbin/amavisd-new[4563]: Found secondary av scanner ClamAV-clamscan at /usr/bin/clamscan
Jan  9 12:54:47.979 /usr/sbin/amavisd-new[4563]: No secondary av scanner: FRISK F-Prot Antivirus
Jan  9 12:54:47.979 /usr/sbin/amavisd-new[4563]: No secondary av scanner: Trend Micro FileScanner
Jan  9 12:54:47.979 /usr/sbin/amavisd-new[4563]: No secondary av scanner: drweb – DrWeb Antivirus
Jan  9 12:54:47.980 /usr/sbin/amavisd-new[4563]: No secondary av scanner: KasperskyLab kavscanner

Jan  9 12:54:48.003 /usr/sbin/amavisd-new[4563]: SpamControl: initializing Mail::SpamAssassin
Jan  9 12:54:48.004 /usr/sbin/amavisd-new[4563]: SpamAssassin debug facilities: info
Jan  9 12:54:49.559 /usr/sbin/amavisd-new[4563]: SpamControl: init_pre_fork on SpamAssassin done

Jan  9 12:54:49.576 /usr/sbin/amavisd-new[4573]: SpamControl: init_child on SpamAssassin done

Finish the Amavisd-New Configuration

Create Necessary users and folders as root.
# useradd vscan

# mkdir /var/vscan
# mkdir /var/vscan/tmp
# mkdir /var/vscan/var
# mkdir /var/vscan/db
# mkdir /var/vscan/home
# chown -R vscan:vscan /var/vscan
# chmod -R 750 /var/vscan

Creating a Reinjection Port
The process that you see below shows how mail arrives at the server and is then sent to a content_filter on port 10024, on to the qmgr and then to amavisd-new which then executes the scanning with both Spamassassin and clamav.  When the scanning is complete you do not want to send the scanned mail back to port 10024 because you will create a loop.  So you need to create a reinjection port so that the mail that has been scanned will be recognized as complete.   The reinjection port that is used is port 10025.  This section will now show you how to set up those two ports and activate Spamassassin and clamav.

Edit and Add Content Filter

#Amavisd SetUp

Edit and Add Reinjection

amavisd-new  unix  -    -       n       -       2       smtp
-o smtp_data_done_timeout=1200s
-o disable_dns_lookups=yes inet n  -       n       -       -       smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=
-o strict_rfc821_envelopes=yes

Add clamav to the group amavis


Send an email and watch the system as it runs in debug mode.

sendmail -f </etc/postfix/

Review File Contents for Amavisd-New
cd /etc/amavis/conf.d

Once you have install amavisd-new you will find a number of files that make up the configuration for amaavisd-new and how it interacts with Spamassassin and clamav.  These files, at least the important parts, are listed here with a brief description.

These are the various ways of compressing files.  Do not modify.


$ENV{PATH} = $path = ‘/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin’;
$file   = ‘file’;
$gzip   = ‘gzip’;
$bzip2  = ‘bzip2′;
$lzop   = ‘lzop’;
$rpm2cpio   = ['','rpm2cpio'];
$cabextract = ‘cabextract’;
$uncompress = ['uncompress', 'gzip -d', 'zcat'];
#$unfreeze   = ['unfreeze', 'freeze -d', 'melt', 'fcat']; #disabled (non-free, no security support)
$unfreeze = undef;
$arc        = ['nomarch', 'arc'];
$unarj      = ['arj', 'unarj'];
#$unrar      = ['rar', 'unrar']; #disabled (non-free, no security support)
$unrar  = ['unrar-free'];
$zoo    = ‘zoo’;
#$lha    = ‘lha’; #disabled (non-free, no security support)
$lha    = undef;
$pax    = ‘pax’;
$cpio   = ‘cpio’;
$ar     = ‘ar’;
$ripole = ‘ripole’;
$dspam  = ‘dspam’;

1;  # ensure a defined return

# amavisd-new needs to know which email domains are to be considered local
# to the administrative domain.  Only emails to “local” domains are subject
# to certain functionality, such as the addition of spam tags.
# Default local domains to $mydomain and all subdomains.  Remember to
# override or redefine this if $mydomain is changed later in the config
# sequence.

@local_domains_acl = ( “.$mydomain” );

1;  # ensure a defined return

If you have problems with your FQDN you can alter that manually here.

# $myhostname is used by amavisd-new for node identification, and it is
# important to get it right (e.g. for ESMTP EHLO, loop detection, and so on).

chomp($myhostname = `hostname –fqdn`);

This file holds the information required for amavisd to locate the virus scanners you may have installed on your box.

This file turns off by default the ability of amavisd-new to scan for virus activity or check for spam.
use strict;

# You can modify this file to re-enable SPAM checking through spamassassin
# and to re-enable antivirus checking.

# Default antivirus checking mode
# Uncomment the two lines below to enable it back

#@bypass_virus_checks_maps = (
#   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

# Default SPAM checking mode
# Uncomment the two lines below to enable it back

#@bypass_spam_checks_maps = (
#   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

1;  # ensure a defined return

There are settings here that you can modify to determine the action your machine should take when it discovers either a virus email or spam.

use strict;

# These are Ubuntu specific defaults for amavisd-new configuration
$enable_dkim_verification = 1;
# Don’t be verbose about sending mail:
@whitelist_sender_acl = qw( .$mydomain );
$final_virus_destiny      = D_DISCARD; # (defaults to D_BOUNCE)
$final_banned_destiny     = D_BOUNCE;  # (defaults to D_BOUNCE)
$final_spam_destiny       = D_DISCARD;  # (defaults to D_REJECT)
$final_bad_header_destiny = D_PASS;  # (defaults to D_PASS), D_BOUNCE suggested

$warnbannedsender = 1;
$warnbadhsender = 1;
$virus_admin = undef;
$spam_admin = undef;

Functionality required for amavis helpers like  amavis-release.

read_l10n_templates(‘en_US’, ‘/etc/amavis’);


# DKIM signing domain whitelist. The domain to use is the domain after
# d= in the DKIM header.

@author_to_policy_bank_maps = ( {
‘’               => ‘WHITELIST’,
‘’             => ‘WHITELIST’,
‘’                 => ‘WHITELIST’,
‘’                 => ‘WHITELIST’,
‘’                 => ‘WHITELIST’,
‘’                 => ‘WHITELIST’,
‘’           => ‘WHITELIST’,
‘’             => ‘WHITELIST’,  # author signatures
‘./’           => ‘WHITELIST’,  # 3rd-party sign. by
‘’ => ‘WHITELIST’,
‘’              => ‘WHITELIST’,
‘’               => ‘WHITELIST’,
‘’                => ‘WHITELIST’,
‘’               => ‘WHITELIST’,
‘’       => ‘WHITELIST’,
‘’        => ‘WHITELIST’,
‘’ => ‘WHITELIST’,
# ‘’              => ‘MILD_WHITELIST’,
# ‘’          => ‘MILD_WHITELIST’,
# ‘./’     => ‘MILD_WHITELIST’,
# ‘./’      => ‘MILD_WHITELIST’,
# ‘./’    => ‘MILD_WHITELIST’,
# ‘./’      => ‘MILD_WHITELIST’,
# ‘’           => ‘MILD_WHITELIST’,
# ‘’              => ‘MILD_WHITELIST’,
} );

# Place your configuration directives here.  They will override those in
# earlier files.
# See /usr/share/doc/amavisd-new/ for documentation and examples of
# the directives you can use in this file

Update Virus Signatures for Postfix

Posted by Filed Under Virus Control with Comments Off

It is important to understand how to manually update virus signatures in case you do not have access to an update automatically from the Internet using Freshclam.

Manually Update Signatures

The signatures are kept in /var/clamav and they are owned by clamav, so it is important to make sure the permissions are correct once you have updated.
Download the main.cvd and daily.cvd, which make up the signatures.  Securely copy them to the /var/clamav directory on your server.

scp *.cvd root@server_ipaddress:/var/clamav

Once the files are copied to the server you should still see these permissions:

ls -la /var/clamav
total 7192
drwxr-xr-x  2 clamav clamav   4096 Nov  5 23:16 .
drwxr-xr-x  19 root    root         4096 Nov 18 12:56 ..
-rw-r—r–   1 clamav clamav     409929 Nov 18 14:32 daily.cvd
-rw-r—r–  1 clamav clamav      6924820 Nov 18 14:35 main.cvd

Freshclam Updates

Edit your /etc/crontab file to add an entry so that freshclam will look for updates every 39 minutes after each hour.  The unusual time just helps freshclam to look for updates when the load is less on the ClamAv servers.

Here is the /etc/crontab file:

# run-parts
37 * * * * root run-parts /etc/cron.hourly
19 0 * * * root run-parts /etc/cron.daily
22 5 * * 0 root run-parts /etc/cron.weekly
12 5 13 * * root run-parts /etc/cron.monthly

# Run CLamAv Updates with Freshclam
39 * * * * root /usr/bin/freshclam

Comment out example!
This file is found in /etc/freshclam.conf
## Example config file for freshclam
## Please read the freshclam.conf(5) manual before editing this file.
## This file may be optionally merged with clamd.conf.

# Comment or remove the line below.

# Path to the database directory.
# WARNING: It must match clamd.conf’s directive!
# Default: hardcoded (depends on installation options)
DatabaseDirectory /var/clamav

# Path to the log file (make sure it has proper permissions)
# Default: disabled
UpdateLogFile /var/log/clamav/freshclam.log

# Enable verbose logging.
# Default: disabled

# Use system logger (can work together with UpdateLogFile).
# Default: disabled

# Specify the type of syslog messages – please refer to ‘man syslog’
# for facility names.
# Default: LOG_LOCAL6
#LogFacility LOG_MAIL

# This option allows you to save the process identifier of the daemon
# Default: disabled
PidFile /var/run/clamav/

# 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

# Initialize supplementary group access (freshclam must be started by root).
# Default: disabled

# Use DNS to verify virus database version. Freshclam uses DNS TXT records
# to verify database and software versions. With this directive you can change
# the database verification domain.
# Default: enabled, pointing to

# Uncomment the following line and replace XY with your country
# code. See for the full list.
# Default: There is no default, which results in an error when running freshclam”/etc/freshclam.conf”

# is a round-robin record which points to our most
# reliable mirrors. It’s used as a fall back in case is
# not working. DO NOT TOUCH the following line unless you know what you
# are doing.

# How many attempts to make before giving up.
# Default: 3 (per mirror)
#MaxAttempts 5

# Number of database checks per day.
# Default: 12 (every two hours)
#Checks 24

# Proxy settings
# Default: disabled
#HTTPProxyPort 1234
#HTTPProxyUsername myusername
#HTTPProxyPassword mypass

# Use aaa.bbb.ccc.ddd as client address for downloading databases. Useful for
# multi-homed systems.
# Default: Use OS’es default outgoing IP address.
#LocalIPAddress aaa.bbb.ccc.ddd

# Send the RELOAD command to clamd.
# Default: disabled
# By default it uses the hardcoded configuration file but you can force an
# another one.
NotifyClamd /etc/clamd.conf

# Run command after successful database update.
# Default: disabled
#OnUpdateExecute command

# Run command when database update process fails.
# Default: disabled
#OnErrorExecute command

# Run command when freshclam reports outdated version.
# In the command string %v will be replaced by the new version number.
# Default: disabled
#OnOutdatedExecute command

# Don’t fork into background.
# Default: disabled

# Enable debug messages in libclamav.
# Default: disabled

# Timeout in seconds when connecting to the database server.
# Default: 30
#ConnectTimeout 60

# Timeout in seconds when reading from the database server.
# Default: 30
#ReceiveTimeout 60

Freshclam Log Creation
One of the most important aspects of any antivirus program is that the signatures are current.  Freshclam provides that service.  It is important to set up the log file correctly so that you may verify that freshclam is working.

The default location for the log file is here:

Check that log file for verification that the signatures are being updated.

Manually Scanning for Viruses

Posted by Filed Under Virus Control with Comments Off

Using Clamscan to Manually Scan Directories
Typically you would allow amavisd-new to control the scanning process.  However, there may come a time when you want to manually scan a directory or file that is suspicious.
1. Scan a File
clamscan filename

2. Scan Current Working Directory

3. Recurrsive Scan of Directory
This command will scan and only report infected files.
clamscan -r – -infected  /home

4. Scan Data Stream
cat file | clamscan-

5. Scan Mail Directory
clamscan -r /var/spool/mail

Configure ClamAv for Postfix

Posted by Filed Under Virus Control with Comments Off

Create a user and group called clamav with this command:

groupadd clamav
useradd -g clamav -s /bin/false clamav

The -s /bin/false creates the user without a login, no shell.

Start the clamav
LibClamAV Warning: **************************************************
LibClamAV Warning: ***  The virus database is older than 7 days.  ***
LibClamAV Warning: ***        Please update it IMMEDIATELY!       ***
LibClamAV Warning: **************************************************


Be sure to comment out the example line!

## Example config file for the Clam AV daemon
## Please read the clamd.conf(5) manual before editing this file.

# Comment or remove the line below.

# Uncomment this option to enable logging.
# LogFile must be writable for the user running daemon.
# A full path is required.
# Default: disabled
LogFile /var/log/clamav/clamd.log

# By default the log file is locked for writing – the lock protects against
# running clamd multiple times (if you want to run another clamd instance,
# please # copy the configuration file, change the LogFile variable, and run
# the daemon with the –config-file option).
# This option disables log file locking.
# Default: disabled

# Maximal 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 0

# Log time with each message.
# Default: disabled

# Also log clean files. Useful in debugging but drastically increases the
# log size.
# Default: disabled

# Use system logger (can work together with LogFile).
# Default: disabled

# Specify the type of syslog messages – please refer to ‘man syslog’
# for facility names.
# Default: LOG_LOCAL6
#LogFacility LOG_MAIL

# Enable verbose logging.
# Default: disabled

# This option allows you to save a process identifier of the listening
# daemon (main thread).
# Default: disabled
PidFile /var/run/clamav/

# Optional path to the global temporary directory.
# Default: system specific (usually /tmp or /var/tmp).
TemporaryDirectory /var/tmp

# Path to the database directory.
# Default: hardcoded (depends on installation options)
DatabaseDirectory /var/clamav

# The daemon works in a local OR a network mode. Due to security reasons we
# recommend the local mode.

# Path to a local socket file the daemon will listen on.
# Default: disabled
#LocalSocket /var/run/clamav/clamd.sock

# Remove stale socket after unclean shutdown.
# Default: disabled

# TCP port address.
# Default: disabled
TCPSocket 3310

# TCP address.
# By default we bind to INADDR_ANY, probably not wise.
# Enable the following to provide some degree of protection
# from the outside world.
# Default: disabled

# Maximum length the queue of pending connections may grow to.
# Default: 15
MaxConnectionQueueLength 30

# Clamd uses FTP-like protocol to receive data from remote clients.
# If you are using clamav-milter to balance load between remote clamd daemons
# on firewall servers you may need to tune the options below.

# Close the connection when the data size limit is exceeded.
# The value should match your MTA’s limit for a maximal attachment size.
# Default: 10M
#StreamMaxLength 20M

# Limit port range.
# Default: 1024
#StreamMinPort 30000
# Default: 2048
#StreamMaxPort 32000
# Maximal number of threads running at the same time.
# Default: 10
#MaxThreads 20

# Waiting for data from a client socket will timeout after this time (seconds).
# Value of 0 disables the timeout.
# Default: 120
ReadTimeout 300

# Waiting for a new job will timeout after this time (seconds).
# Default: 30
#IdleTimeout 60

# Maximal depth directories are scanned at.
# Default: 15
#MaxDirectoryRecursion 20

# Follow directory symlinks.
# Default: disabled

# Follow regular file symlinks.
# Default: disabled

# Perform internal sanity check (database integrity and freshness).
# Default: 1800 (30 min)
#SelfCheck 600

# Execute a command when virus is found. In the command string %v will
# be replaced by a virus name.
# Default: disabled
#VirusEvent /usr/local/bin/send_sms 123456789 “VIRUS ALERT: %v”

# Run as a selected user (clamd must be started by root).
# Default: disabled
User clamav

# Initialize supplementary group access (clamd must be started by root).
# Default: disabled

# Stop daemon when libclamav reports out of memory condition.

# Don’t fork into background.
# Default: disabled

# Enable debug messages in libclamav.
# Default: disabled
# Do not remove temporary files (for debug purposes).
# Default: disabled

# By default clamd uses scan options recommended by libclamav. This option
# disables recommended options and allows you to enable selected ones below.
# DO NOT TOUCH IT unless you know what you are doing.
# Default: disabled

## Executable files

# PE stands for Portable Executable – it’s an executable file format used
# in all 32-bit versions of Windows operating systems. This option allows
# ClamAV to perform a deeper analysis of executable files and it’s also
# required for decompression of popular executable packers such as UPX, FSG,
# and Petite.
# Default: enabled

# With this option clamav will try to detect broken executables and mark
# them as Broken.Executable
# Default: disabled

## Documents

# This option enables scanning of Microsoft Office document macros.
# Default: enabled

## Mail files

# Enable internal e-mail scanner.
# Default: enabled

# If an email contains URLs ClamAV can download and scan them.
# WARNING: This option may open your system to a DoS attack.
#       Never use it on loaded servers.
# Default: disabled

# Perform HTML normalisation and decryption of MS Script Encoder code.
# Default: enabled

## Archives

# ClamAV can scan within archives and compressed files.
# Default: enabled

# Due to license issues libclamav does not support RAR 3.0 archives (only the
# old 2.0 format is supported). Because some users report stability problems
# with unrarlib it’s disabled by default and you must uncomment the directive
# below to enable RAR 2.0 support.
# Default: disabled

# The options below protect your system against Denial of Service attacks
# using archive bombs.

# Files in archives larger than this limit won’t be scanned.
# Value of 0 disables the limit.
# Default: 10M
#ArchiveMaxFileSize 15M

# Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR
# file, all files within it will also be scanned. This options specifies how
# deep the process should be continued.
# Value of 0 disables the limit.
# Default: 8
#ArchiveMaxRecursion 9

# Number of files to be scanned within an archive.
# Value of 0 disables the limit.
# Default: 1000
#ArchiveMaxFiles 1500

# If a file in an archive is compressed more than ArchiveMaxCompressionRatio
# times it will be marked as a virus (Oversized.ArchiveType, e.g. Oversized.Zip)# Value of 0 disables the limit.
# Default: 250
ArchiveMaxCompressionRatio 300

# Use slower but memory efficient decompression algorithm.
# only affects the bzip2 decompressor.
# Default: disabled

# Mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR).
# Default: disabled

# Mark archives as viruses (e.g. RAR.ExceededFileSize, Zip.ExceededFilesLimit)
# if ArchiveMaxFiles, ArchiveMaxFileSize, or ArchiveMaxRecursion limit is
# reached.
# Default: disabled

## Clamuko settings
## WARNING: This is experimental software. It is very likely it will hang
##   up your system!!!

# Enable Clamuko. Dazuko (/dev/dazuko) must be configured and running.
# Default: disabled

# Set access mask for Clamuko.
# Default: disabled

# Set the include paths (all files in them will be scanned). You can have
# multiple ClamukoIncludePath directives but each directory must be added
# in a seperate line.
# Default: disabled
#ClamukoIncludePath /home
#ClamukoIncludePath /students

# Set the exclude paths. All subdirectories are also excluded.
# Default: disabled
#ClamukoExcludePath /home/guru

# Don’t scan files larger than ClamukoMaxFileSize
# Value of 0 disables the limit.
# Default: 5M
#ClamukoMaxFileSize 10M

Amavisd-new Installation

Posted by Filed Under Virus Control with Comments Off

This program is used to tie the scanning programs ClamAv and SpamAssassin to Postfix.  Download the program from  Place the download in a location where you want to run the program from for example /usr/local.  Be sure you have perl version 5.8.2 or later for amavisd-new as it is a perl script.
Unpack the program in /usr/local with:

tar zxvf amavisd-new-2.6.1.tar.gz

Move into the directory.
cd amavisd-new-2.6.1

The file to execute is amavisd.  Once installed you will be able to move the executable to the desired location.
cp amavisd /usr/sbin/
chown root /usr/sbin/amavisd
chmod 755  /usr/sbin/amavisd

You also need to move the copy of amavisd.conf to the /etc directory.
cp  avmavisd.conf /etc/
chown root:vscan /etc/amavisd.conf
chmod 640 /etc/amavisd.conf

To start the program it is best to start it with the debug mode.

./amavisd debug

You will then be able to determine what kind of issues you need to resolve.  Before you can actually get the program to work you need to do the following:

1. Create a user and group
2. Create necessary directories and change permissions
3. Add the required Perl modules
4. Edit the /etc/amavisd.conf file

Amavisd-new Update Version 2.6.1

Posted by Filed Under Virus Control with Comments Off

                  amavisd-new-2.6.1 release notes  


- avoid a bounce-killer’s false positive when a message is multipart/mixed

with an attached message/rfc822 (looking like a qmail or a MSN bounce)

and having attached a message with a foreign Message-ID – by restricting

the check to messages with an empty sender address or a ‘postmaster’ or

‘MAILER-DAEMON’ author address;

- privileges were dropped too early when chrooting, causing chroot to fail

(a workaround was to specify a jail directory through a command line

option -R); reported by Helmut Schneider;

- fix unwarranted ‘run_av error: Exceeded allowed time’ error when using

a virus scanned Mail::ClamAV; reported by Chaminda Indrajith;

- fix a bug in helper-progs/amavis-milter.c where atoi could be reading

from a non-null terminated string which could result in wrong milter

return status, or even cause a read-access violation;

reported by Shin-ichi Nagamura;

- dsn_cutoff_level was ignored if SpamAssassin was not invoked (e.g. on

large messages) even if recip_score_boost was nonzero, causing a DSN

not to be suppressed for internally generated large score values;

reported by Bernd Probst;

- add back the ‘Ok, id=…, from MTA(…):’ prefix to a MTA status responses

on forwarded mail when generating own SMTP status response (it was lost

in code transition from 2.5.4 to 2.6.0); reported by Thomas Gelf;

- replaced ‘-ErrFile=>*STDOUT’ with ‘-ErrFile=>\*STDOUT’ in a call to

BerkeleyDB::Env::new in amavisd-nanny and amavisd-agent; seems it

was failing in some setups (even though it was in accordance with

a BerkeleyDB module documentation); reported by Leo Baltus;

- README.sql-mysql: fixed a SQL data type mismatch between (used as

a foreign key) and msgs.sid & msgrcpt.rid; they all should be of the same

type, either integer unsigned or bigint unsigned; a schema as published

in README.sql-mysql could not be built because of a conflict in a data

type; reported by Leonardo Rodrigues Magalhães and Zhang Huangbin;


- recognize an additional place-holder %P in a template used to build

a file name in file-based quarantining, for example:

$spam_quarantine_method = ‘local:Week%P/spam/%m.gz’;

A %P is replaced by a current partition tag, which makes it easier to

better organize a file-based quarantine by including a partition tag

(e.g. an ISO week number) in a file name or a file path.

For the record, here is a complete list of place-holders currently

recognized in filename templates:

%P => $msginfo->partition_tag

%b => $msginfo->body_digest

%m => $msginfo->mail_id

%n => $msginfo->log_id

%i => iso8601 timestamp of a message reception time by amavisd

%% => %

The following example organizes spam quarantine into weekly subdirectories:

cd /var/virusmails

mkdir -p W23/spam W24/spam W25/spam … (weeks 01..53)

chown -R vscan:vscan W23 W24 W25 … (weeks 01..53)


$spam_quarantine_method = ‘local:W%P/spam/%m.gz’;

$sql_partition_tag =

sub { my($msginfo)=@_; sprintf(“%02d”,iso8601_week($msginfo->rx_time)) };

- add a macro %P as a synonym for a macro ‘partition_tag’, mainly for

completeness with the added place-holder %P in a file name template;


- disabled a do_ascii decoder in the default @decoders list:

# ['asc', \&Amavis::Unpackers::do_ascii],

# ['uue', \&Amavis::Unpackers::do_ascii],

# ['hqx', \&Amavis::Unpackers::do_ascii],

# ['ync', \&Amavis::Unpackers::do_ascii],

The do_ascii is invoking a module Convert::UUlib which in turn calls

a troublesome library uulib, which has a history of security problems

and on occasion misinterprets a text file as some encoded text, causing

false positives (e.g. making it look like an executable);

recent false positive on base64-decoding reported by Jeffrey Arbuckle;

recent DoS (looping in uulib) reported by Thomas Ritterbach;

- added a rule into $map_full_type_to_short_type_re to cope with another

example of misclassification by a file(1) utility, where a plain text

file is considered a DOS executable:

[qr/^DOS executable \(COM\)/ => 'asc'], # misclassified?

An example was provided by Leonardo Rodrigues Magalhães;

- until the issue is better understood, revert the use of ‘my_require’

and go back to the standard but less informative ‘require’; some people

were reporting problems with my_require (loading of some Perl modules can

fail, apparently depending on a current directory where amavisd is started

from); reports by Tuomo Soini, Max Matslofva, Bill Landry;

- use the $myproduct_name value in generated Received header field

instead of a hard-wired ‘amavisd-new’; suggested by Thomas Gelf;

- added missing required header fields to some test mail messages in a

directory test-messages to quench down a complaint about a bad header;

- changed SQL default clauses in %sql_clause (upd_msg, sel_quar, sel_penpals)

to always join tables using both the partition_tag and the mail_id fields,

previously just the mail_id field was used in a join. The change has no

particular effect (and is not really necessary) on existing 2.6.0 databases

where a primary key is mail_id (it is just a redundant extra condition),

but saves a day when a primary key is a composite: (partition_tag,mail_id),

which may be a requirement of a SQL partitioning mechanism.

Thanks to Thomas Gelf for his testing of MySQL partitioning, reporting

deficiency in amavisd SQL schema (primary keys) which did not meet MySQL

requirements for partitioning, and suggestions;

- an AM.PDP release request can specify an additional optional attribute:


where a requester can supply a partition_tag value of a message to be

released. This helps to uniquely identify a message in case where an SQL

database did not enforce a mail_id field to be unique (as may be necessary

with some partitioning schemes).

If a partition_tag information is readily available to a requester, it

is advised that the attribute is included in a request even if mail_id

is known to be unique. This may expedite a search and provide a double

check to a validity of a request. For backwards compatibility amavisd

performs a query on msgs.mail_id for a partition_tag value if it is

missing form a request, the query uses an SQL clause in a new entry

$sql_clause{‘sel_msg’}. If exactly one record matches, then everything

is fine, and releasing may proceed. If multiple records with the same

mail_id exist the release request is aborted with a message asking user

to supply a disambiguating partition_tag=xx attribute;

- a quarantine id for an SQL-quarantined message as logged in a main

log entry is changed from:

quarantine: aX3C4f6btXgX


quarantine: aX3C4f6btXgX[25]

i.e. a partition_tag in brackets is appended to mail_id.

Correspondingly the amavisd-release is also changed to be able to parse

‘aX3C4f6btXgX[25]‘, splitting it into mail_id and partition_tag, and

providing each as a separate attribute in an AM.PDP release request;

- README.sql-mysql: changed SQL datatype VARCHAR into VARBINARY for

data fields mail_id, secret_id and quar_loc, and CHAR into BINARY for

msgs.content and msgs.quar_type to preserve case sensitivity on string

comparison operators; suggested by Thomas Gelf;

The same change should eventually be done on README.sql-pg too, but as

PostgreSQL is more picky than MySQL on matching a field data type to a

supplied data value, the change of a data type would need to be reflected

in SQL calls in amavisd. This will have to wait until some future version

of amavisd-new, having to undergo more testing than I have available

before the 2.6.1 release.

Background information on UNIQUE constraint in table SQL msgs

Amavisd does not know and need not be aware of what is a primary

key or what are UNIQUE constraints in SQL table msgs. When generating

a mail_id for a message being processed, amavisd tries to INSERT

a record with a randomly generated mail_id into table msgs (using

SQL clause in $sql_clause{‘ins_msg’}). If the operation fails,

another mail_id is generated and attempt repeated, until it eventually

succeeds. Thus it depends entirely on SQL’s decision whether a

particular record is allowed or would break some UNIQUE constraint.

So, by only changing a declaration on table msgs (PRIMARY KEY or

adding a CONSTRAINT), it changes what keys amavisd will be allowed

to insert and what kind of duplicates would be allowed.

Classically the msgs.mail_id is a PRIMARY KEY and as such it is unique.

This was a requirement for versions of amavisd up to and including 2.6.0.

Starting with 2.6.1 the JOINs have been tightened to include a

partition_tag besides mail_id in a relation, which makes it possible

to loosen a unique requirement on msgs.mail_id and only require a

pair (partition_tag,mail_id) to be unique. In other words, this way

the mail_id is only needed to be unique within each partition tag value.

This change allows a partitioning scheme to meet requirements on

MySQL partitioning. For non-partitioned databases the change shouldn’t

make any difference, and one is free to choose between having mail_id

unique across the entire table or just within each partition_tag value.

Changing a primary key to (partition_tag,mail_id) brings consequences

to quarantining, in particular to releasing from a SQL quarantine,

where it no longer suffices to specify mail_id=xxx in AM.PDP request,

but may be necessary to specify also a partition_tag=xx to distinguish

between SQL-quarantined messages which happen to have the same mail_id.


April 23, 2008

amavisd-new-2.6.0 release notes


- integrated DKIM signing and verification; see section

A QUICK START TO DKIM SIGNING by the end of this release note;

- loading of policy banks based on valid DKIM-signed author’s address

can be used for reliable whitelisting, for bypassing banned checks, etc.

- bounce killer feature: uses a pen pals SQL lookup to check inbound DSN;

- SQL logging and quarantining tables have a new field ‘partition_tag’;

- captures SpamAssassin logging, more flexibility specifying SA log areas;

- collects and logs SpamAssassin timing breakdown report (requires SA 3.3);

- releasing from a quarantine can push a released message to an attachment;

- new experimental code for abuse reporting using formats: ARF/attach/plain;

- TLS support on the SMTP client and server side;

- connection caching by a SMTP client;

- amavisd-nanny and amavisd-agent now re-open a database on amavisd restarts;

- amavisd-nanny and amavisd-agent new command line option: -c count;

- updated to support source port number in queries;

- amavisd can send queries either to or directly to p0f;


- when using SQL for logging (e.g. for a pen pals feature) or for

quarantining, SQL tables tables maddr, msgs, msgrcpt and quarantine need

to be extended by a new field ‘partition_tag’; see below for details;

- when SQL logging (pen pals) or SQL lookups are used, one can choose a

binary or a character data type for fields,,

and; now may be a good opportunity to change a data type

to binary (string of bytes); see below for details;

- when using SQL for logging, a default for $sql_clause{‘upd_msg’}

has changed, so if a configuration file replaces this SQL clause

by a non-default setting, it needs to be updated;

- perl module Mail::DKIM is now required when DKIM verification or signing

is enabled or when spam checking by SpamAssassin is used and a DKIM plugin

is enabled; a required version of this module is 0.31 (or later);

- because privileges are now dropped sooner, pid and lock files as

generated by Net::Server can no longer be located in a directory which

is not writable by UID under which amavisd is running (e.g. /var/run).

A location of these files is controlled by $pid_file and $lock_file

settings, and by default are placed in $MYHOME, which still satisfies

the new requirement;

- white and blacklisting now takes into account both the SMTP envelope

sender address, as well as the author address from a header section

(address(es) in a ‘From:’ header field). Note that whitelisting

based only on a sender-specified address is mostly useless nowadays.

For a reliable whitelisting see @author_to_policy_bank_maps below,

as well as a set of whitelisting possibilities in SpamAssassin (based

on DKIM, SPF, or on Received header fields);

- if using custom hooks, some of the internal functions have changed,

in particular the semantics of a method orig_header_fields – use new

functions get_header_field() or get_header_field_body() instead;

see updated sample code amavisd-custom.conf, and see entries labeled

‘internal’ below;

- a configuration variable $append_header_fields_to_bottom is now obsolete;

the variable is still declared for compatibility with old configuration

files, but its value is ignored: new header fields are always prepended,

i.e. added to the top of a header section;

- semantics of a command line option ‘debug-sa’ has changed due to a merge

of SpamAssassin logging with a mainstream amavisd logging mechanism.

A command ‘amavisd debug-sa’ is now equivalent to ‘amavisd -d all’ with

an implied redirection of all logging to stderr. Previously it only rerouted

SpamAssassin logging to stderr but did not affect normal amavisd logging,

which still followed the usual $DO_SYSLOG and $LOGFILE settings.

Also, a SpamAssassin log level ‘info’ is now turned on by default (as was

previously achievable by a command line option ‘-d info’), and shows merged

with a normal amavisd logging at level 1 or higher.

The following table shows mapping of SpamAssassin log levels to amavisd

log levels, and for completeness also shows mapping of amavisd log levels

to syslog priorities (which has not changed since previous version):

SA amavisd syslog

—– ——- ———–



error -1 LOG_WARNING


info 1 LOG_INFO





- an additional requirement for loading a policy bank ‘MYUSERS’ is that

‘originating’ flag must be on, which typically means that mail must

be coming from internal networks or from authenticated roaming users

to be able to load a policy bank ‘MYUSERS’;


- run_av: limit the number of filenames given as arguments to a command

line scanner to stay within a safe (POSIX) program argument space limit,

run a command line scanner multiple times if necessary. This required

a larger change in the program (run_av, ask_av) which is why the fix

was listed for a long time on a TODO list and not implemented so far.

The problem affected command line virus scanners which are unable to

traverse a directory by themselves and need a list of filenames as

arguments (such as KasperskyLab’s aveclient and kavscanner, MkS_Vir mks,

and CyberSoft VFind). Actual problem reported by Danny Richter;


- DKIM signing and verification – see below: A QUICK START TO DKIM SIGNING.

Not to forget upgrading Mail::DKIM to 0.31 (or later) and adding the

following to amavisd.conf;

$enable_dkim_verification = 1;

$enable_dkim_signing = 1;

- SQL tables tables maddr, msgs, msgrcpt and quarantine are extended by

a new field ‘partition_tag’. When amavisd creates new records in these

tables, a current value of a configuration variable $sql_partition_tag

(or its value from policy banks) is written into ‘partition_tag’ fields.

An undefined value translates to 0. The ‘partition_tag’ field is usually

declared in a schema as an integer, but in principle could be any data

type, such as a string.

A value of ‘partition_tag’ field may be used to speed up purging of

old records by using partitioned tables (MySQL 5.1 +, PostgreSQL 8.1 +).

A sensible value is a week number of a year, or some other slowly changing

value, allowing to quickly drop old table partitions without wasting

time on deleting individual records. Records in all tables carrying the

‘partition_tag’ field are self-contained within each value of a field.

In other words, foreign keys never reference a record in a subordinate

table with a value of a ‘partition_tag’ field different from the referencing

record. Consequently, mail addresses in table maddr are also self-contained

within a partition tag, implying that the same mail address may appear in

more than one maddr partition (using different ‘id’s), and that tables

msgs and msgrcpt are guaranteed to reference a within their own

partition tag. Too fine a granularity of partition tags (e.g. changing a

value daily) wastes space in table maddr by storing multiple copies of

the same mail address.

The $sql_partition_tag may be a scalar (usually an integer or a string),

or a reference to a subroutine, which will be called with an object of

type Amavis::In::Message as argument (giving access to information about

a message being processed), and its result will be used as a partition

tag value. Possible/typical usage (in amavisd.conf):

$sql_partition_tag =

sub { my($msginfo)=@_; iso8601_week($msginfo->rx_time) };

yields an ISO 8601 week number (1..53) corresponding to a mail reception

timestamp in a local time zone.

Another possible use of ‘partition_tag’ field is to let a policy bank set

its specific value (a fixed value or a subroutine) for $sql_partition_tag.

This would allow for example labeling of SQL records for mail originating

from inside with a different partition_tag value, compared to entries for

incoming mail, and consequently let them be stored in a separate partition

if desired.

Amavisd process itself does not use the ‘partition_tag’ field for its

own purposes, all records regardless of their ‘partition_tag’ value

are available for example to pen pals lookups, as before. The field is

provided only as a convenience to SQL database maintenance, and can be

ignored by smaller sites where current practice of database maintenance

is fast enough. If SQL partitioning is not in use (or not intended to

be used in a near future), it is more economical to use a fixed value

(such as 0, which is a default) for the $sql_partition_tag. Using week

numbers as partition tags adds about 50 % to the number of records in

table maddr, the exact number depends on retention period and a ratio

of regular vs. infrequent mail addresses observed.

To convert tables of an existing database, please use ALTER command.

Here is a conversion example (MySQL or PostgreSQL, probably others):

ALTER TABLE maddr ADD partition_tag integer DEFAULT 0;

ALTER TABLE msgs ADD partition_tag integer DEFAULT 0;

ALTER TABLE msgrcpt ADD partition_tag integer DEFAULT 0;

ALTER TABLE quarantine ADD partition_tag integer DEFAULT 0;

As the is no longer guaranteed to be unique, but a pair

of (maddr.partition_tag, is unique, the constraint and

an associated index needs to be changed:

=> PostgreSQL:


DROP CONSTRAINT maddr_email_key,

ADD CONSTRAINT maddr_email_key UNIQUE (partition_tag,email);

=> MySQL:


DROP KEY email,

ADD UNIQUE KEY part_email (partition_tag,email);

Should a need arise to revert to amavisd-new-2.5.4 while keeping the new

partition_tag field, the ‘SELECT id FROM maddr …’ may become slow due to

dropped index on a field, which is replaced by an index on a

pair (maddr.partition_tag, The following change to amavisd

2.5.4 solves the problem:

@@ -901,2 +901,2 @@

‘sel_adr’ =>

- ‘SELECT id FROM maddr WHERE email=?’,

+ ‘SELECT id FROM maddr WHERE partition_tag=0 AND email=?’,

The use of partitioned tables to speed up purging of old records was

suggested by Robert Pelletier.

- when SQL logging (pen pals) or SQL lookups are used, one can choose a

binary or a character data type for fields,,

and; now may be a good opportunity to change a data type

to binary (string of arbitrary bytes, no character set associated).

Background: values of these fields come from SMTP envelope or from a

mail header section of processed mail. Even though RFC 2821 and RFC 2822

restrict these addresses to 7-bit ASCII, there is nothing preventing

a malicious or misguided sender from supplying any 8-bit byte values.

If SQL fields are declared as VARCHAR or CHAR, a character set is

associated with data and its rules apply, e.g. control characters may

not be permitted, or UTF-8 byte sequences are validated, or a restriction

to codes below 128 apply. Depending on strictness of an SQL server on

validating data, a violation of character set rules may lead to aborting

an SQL operation and failing of mail processing. Even though new standards

for e-mail addresses are being negotiated allowing for UTF-8 encoding, an

actual e-mail address may still supply arbitrary bytes, which may violate

UTF-8 byte sequence rules.

A new configuration variable $sql_allow_8bit_address now controls how

amavisd passes e-mail addresses to SQL.

If a value is true, then it is expected that SQL tables will accept

strings of arbitrary bytes for these fields, without associating a

character set with data. No data sanitation is done by amavisd. An

appropriate SQL data type is ‘VARBINARY’ or with PostgreSQL a ‘BYTEA’.

If a value of $sql_allow_8bit_address is false (which is a default for

compatibility) then amavisd performs sanitation before passing data to SQL:

control characters and characters with codes above 127 are converted to ‘?’,

which brings strings within ASCII character set restrictions. A suitable

SQL data type is VARCHAR or CHAR. Note that some information is lost in

this case.

The following clauses can convert pre-2.6.0 tables into the now preferred

and more universal form:


ALTER TABLE users CHANGE email email varbinary(255);

ALTER TABLE mailaddr CHANGE email email varbinary(255);

ALTER TABLE maddr CHANGE email email varbinary(255);


ALTER TABLE users ALTER email TYPE bytea USING decode(email,’escape’);

ALTER TABLE mailaddr ALTER email TYPE bytea USING decode(email,’escape’);

ALTER TABLE maddr ALTER email TYPE bytea USING decode(email,’escape’);

If a binary data type is chosen for these three fields, the setting

$sql_allow_8bit_address MUST be set to true to let the amavisd program

use the appropriate data type in SQL commands, otherwise PostgreSQL will

complain with:

‘types bytea and character varying cannot be matched’

when amavisd tries to execute SQL commands. MySQL is more forgiving and

does not complain about a data type mismatch, so one may get away with a

mismatch, although it is appropriate to eventually make it right.

If a change of a data type of these fields is chosen while using some

third-party management interface to SQL data set (e.g. MailZu), make sure

the management interface supports the changed data type. This is primarily

a concern with PostgreSQL which is more strict in requiring a match

between field data types in tables and data in SQL clauses.

The need for a change was pointed out by Xavier Romero, reporting that

PostgreSQL SQL lookups with pre-2.6.0 versions of amavisd can fail when

8-bit data appears in SMTP envelope addresses:

lookup_sql: sql exec: err=7, 22021, DBD::Pg::st execute failed: ERROR:

invalid byte sequence for encoding “UTF8″

- bounce killer feature: uses a pen pals SQL lookup to check inbound DSN,

attempting to match it with a previous outbound message. If a Message-ID

found in an attachment of the inbound DSN matches a Message-ID of a

message previously sent from our system by a current recipient of the DSN,

the DSN message is spared, otherwise it receives $bounce_killer_score

spam score points (0 by default, i.e. disabled) and can be blocked as

spam (although technically it is just a misdirected bounce, not spam).

A received delivery status notifications is parsed looking for attached

header section of an original message in an attempt to find a Message-ID.

A standard DSN structure (RFC 3462, RFC 3464) is recognized, as well as

a few nonstandard but common formats. Other automatic reports and bounces

with unknown structure and no attached header section are ignored for

this purpose (are subject to other regular checks). Unfortunately there

are still many nonstandard mailers around (12+ years after DSN format

standardization) and many ad-hoc filtering solutions which do not supply

the essential information.

If a Message-ID can be found in an SQL log database matching a previous

message sent by a local user (which is now a recipient of a DSN),

using a normal pen pals lookup (no extra SQL operations are necessary),

or if domain part of the Message-ID is one of local domains, then the

DSN message is considered a genuine bounce, is unaffected by this check

and passes normally (subject to other checks).

On the other hand, if the attached DSN header does supply a Message-ID

but but it does not meet the above pen pals matching criteria, then it is

assumed that the message is a backscatter to a faked address belonging

to our local domains, and $bounce_killer_score spam score points are

added, so the message can be treated as spam (subject to spam kill level

and other spam settings).

The only user-configurable setting is $bounce_killer_score (also member

of policy banks), its default value is 0. To activate the bounce killer

feature set the $bounce_killer_score to a positive number, e.g. 100.

A pre-requisite is a working SQL logging database (pen pals).

A couple of SNMP-like counters are added to facilitate assessing

effectiveness of the feature (e.g. viewed by amavisd-agent utility):

InMsgsBounce 21310 333/h 9.9 % (InMsgs)

InMsgsBounceKilled 19967 312/h 93.7 % (InMsgsBounce)

InMsgsBounceRescuedByDomain 7 0/h 0.0 % (InMsgsBounce)

InMsgsBounceRescuedByOriginating 242 4/h 1.1 % (InMsgsBounce)

InMsgsBounceRescuedByPenPals 67 1/h 0.3 % (InMsgsBounce)

InMsgsBounceUnverifiable 1027 16/h 4.8 % (InMsgsBounce)

More information on operations can be obtained from a log, search for:


bounce killed

bounce rescued by penpals

bounce rescued by domain

bounce unverifiable

The feature was suggested by Scott F. Crosby.

See also, and

a SpamAssassin man page Mail::SpamAssassin::Plugin::VBounce

for additional ideas on fighting joe-jobbed backscatter mail.

- a new configuration variable @author_to_policy_bank_maps (also a member

of policy banks) is a list of lookup tables (typically only a hash-type

lookup table is used), which maps author addresses(es) (each address in

a ‘From:’ header field – typically only one) in a mail header section

to one or more policy bank names (a comma-separated list of names).

A match can only occur if a valid DKIM author signature or a valid

DKIM third-party signature is found, so in as much as one can trust the

signing domain, loading of arbitrary policy banks can be safe, offering

a flexibility of whitelisting against spam (absolute or just contributing

score points), bypassing of checks (banned, virus, bad-header), using

less restrictive banned rules for certain senders, by-sender routing,

turning quarantining/archiving on/off, and other tricks offered by the

existing policy bank loading mechanisms.

When a message has a valid DKIM (or DomainKeys) author signature (i.e.

when a ‘From:’ address matches a signing identity according to DKIM

(RFC 4871) or DomainKeys (RFC 4870) rules), a lookup key is an unchanged

author address and the usual lookup rules apply (README.lookups – hash


When a valid third-party signature is found, a lookup key is extended

by a ‘/@’ and a lowercased signing domain, as shown in the example below.

The semantics is very similar to a whitelist_from_dkim feature in

SpamAssassin, but is more flexible as is allows any dynamic amavisd

setting to be changed depending on author address, not just skipping

of spam checks.

A few examples of a SpamAssassin’s whitelist_from_dkim (as in

along with equivalent amavisd @author_to_policy_bank_maps entries follow.

To whitelist any From address with a domain when a message

has a valid author signature (i.e. a signature by the same domain):

SA: whitelist_from_dkim *

am: ‘’ => ‘WHITELIST’,

which is equivalent to a lengthy but redundant:

SA: whitelist_from_dkim *

am: ‘’ => ‘WHITELIST’,

Similar to above, but applies to subdomains of carrying

a valid author signature (i.e. signature BY THE SAME SUBDOMAIN):

SA: whitelist_from_dkim *@*

am: ‘’ => ‘WHITELIST’,

Note that in amavisd hash lookups a ‘’ implies a parent

domain ‘’ too, while in SpamAssassin and in Postfix maps

a parent domain needs its own entry if desired.

To whitelist From addresses from subdomains of which carry

a valid third-party signature of its parent domain:

SA: whitelist_from_dkim *@*

am: ‘’ => ‘WHITELIST’,

To whitelist any From address as long as a message has a valid DKIM

or DomainKeys signature by, i.e. a third-party signature.

Typical for mailing lists or discussion groups which sign postings.

SA: whitelist_from_dkim *@*

am: ‘./’ => ‘WHITELIST’,

Here is a complete example to be included in amavisd.conf:

@author_to_policy_bank_maps = ( {



‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’, # author signatures

‘./’ => ‘WHITELIST’, # 3rd-party sign. by

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,

‘’ => ‘WHITELIST’,










} );

$policy_bank{‘MILD_WHITELIST’} = {

score_sender_maps => [ { '.' => [-1.8] } ],


$policy_bank{‘WHITELIST’} = {

bypass_spam_checks_maps => [1],

spam_lovers_maps => [1],


$policy_bank{‘NOVIRUSCHECK’} = {

bypass_decode_parts => 1,

bypass_virus_checks_maps => [1],

virus_lovers_maps => [1],


$policy_bank{‘NOBANNEDCHECK’} = {

bypass_banned_checks_maps => [1],

banned_files_lovers_maps => [1],


- smtp client connection caching is a new feature which allows smtp client

code in amavisd to keep a SMTP session to MTA open after forwarding a

message or a notification, so that a next mail message that needs to be

sent by this child process can avoid re-establishing a session and the

initial greeting/EHLO (and TLS) handshake.

A current value of a global settings $smtp_connection_cache_enable

controls whether a session will be retained after forwarding a message

or not. Its default initial value is true.

A global setting $smtp_connection_cache_on_demand controls whether amavisd

is allowed to dynamically change the $smtp_connection_cache_enable setting

according to its estimate of the message frequency. The heuristics is

currently very simple: if time interval between a previous task completion

by this child process and the arrival of a current message is 5 seconds

or less, the $smtp_connection_cache_enable is turned on (which will affect

the next message); if the interval is 15 seconds or more, it is turned off.

The default value of the $smtp_connection_cache_on_demand is true, thus

enabling the adaptive behaviour.

On a busy server the connection caching can save some processing time.

Savings are substantial if client-side TLS is enabled, otherwise just a

few milliseconds are saved. On an idle server the feature may unnecessarily

keep sessions to MTA open (until MTA times them out), so one can disable

the feature by setting both controls to false (to 0 or undef).

To monitor the connection caching effectiveness, some SNMP-like counters

were added, so amavisd-agent may display something like:

OutConnNew 2764 319/h 98.2 % (OutMsgs)

OutConnQuit 2521 291/h 89.5 % (OutMsgs)

OutConnReuseFail 7 1/h 0.2 % (OutMsgs)

OutConnReuseRecent 21 2/h 0.7 % (OutMsgs)

OutConnReuseRefreshed 31 4/h 1.1 % (OutMsgs)

OutConnTransact 2816 325/h 100.0 % (OutMsgs)

- client-side TLS support is added, i.e. on forwarding a passed mail back

to MTA. Currently only encryption is supported, no client certificates

are offered. A $tls_security_level_out is a per-policy-bank setting which

controls client-side TLS, its value is either undefined (default), or a


undef … client-side TLS is disabled (a default setting);

‘may’ … TLS is used if MTA offers a STARTTLS capability (RFC 3207),

otherwise a plain text SMTP session is established;

‘encrypt’ TLS is used if MTA offers a STARTTLS capability, otherwise

amavisd refuses to forward a message.

The client-side TLS imposes some performance penalty on passing a message

back to MTA, although it is still reasonably fast: a benchmark indicates

a drop in transfer rate by about a factor of 2, from 22 MB/s (no TLS)

to 9 MB/s (with TLS). The smtp client connection caching (see previous item)

should preferably be left enabled (permanently or opportunistically), as

TLS negotiation adds significantly to the initial SMTP handshake time.

- server-side TLS support is added, i.e. on accepting mail from MTA.

Encryption is supported, server (i.e. amavisd) offers its certificate,

but client certificates are not verified. A $tls_security_level_in is

a per-policy-bank setting which controls server-side TLS, its value

is either undefined (default), or a string:

undef … server-side TLS is disabled, STARTTLS capability is

not offered;

‘may’ … STARTTLS capability is offered by amavisd, but client is

not required to enter TLS, plain text sessions are permitted;

‘encrypt’ STARTTLS capability is offered and enforced by amavisd,

any SMTP command other than STARTTLS, NOOP, EHLO or QUIT

is rejected.

If $tls_security_level_in is enabled (any value other than undef or ‘none’),

amavisd offers a certificate to a connecting client requesting TLS, so a

path to a certificate and to its private key must be provided through two

global settings: $smtpd_tls_cert_file and $smtpd_tls_key_file, e.g.:

$smtpd_tls_cert_file = “$MYHOME/cert/amavisd-cert.pem”;

$smtpd_tls_key_file = “$MYHOME/cert/amavisd-key.pem”;

The private key should be guarded as secret (not world-readable).

A self-signed certificate is acceptable by most mailers.

Server-side TLS imposes a significant performance penalty on accepting

a message from MTA. A benchmark indicates a drop in transfer rate by a

factor of 10, from about 10 MB/s (no TLS) to 1 MB/s (using TLS), so it

should only be enabled with a good reason or for experimentation.

- enhanced a subroutine delivery_status_notification (along with

dispatch_from_quarantine and msg_from_quarantine) to produce a message

in one of several formats (derived from a message being processed, or

from a quarantined message). Its new arguments can be strings as follows:

$request_type: dsn, release, requeue, report

$msg_format: dsn, arf, attach, plain, resend

$feedback_type: abuse, fraud, miscategorized, not-spam, opt-out,

opt-out-list, virus, other (according to ARF draft)

Per-policy settings $report_format and $release_format control the format

of a generated message. Their value can be one of the following strings,

although not all combinations make sense:

‘arf’ …. an abuse report is generated according to

draft-shafranovich-feedback-report-04: “An Extensible

Format for Email Feedback Reports”; a plain-text part

contains text from a template;

‘attach’.. generates a report message as plain text according to

a template, with an original message attached;

‘plain’… generates a simple (flat) mail with an only MIME part

containing a text from a template, followed inline by

original message (some service providers can’t handle

abuse reports with attachments, e.g. Yahoo!);

‘resend’.. original message is forwarded unchanged, except for an

addition of header fields Resent-From, Resent-Sender,

Resent-To, Resent-Date and Resent-Message-ID;

‘dsn’ …. (for internal use) a delivery status notification is

generated according to rfc3462, rfc3464 and rfc3461;

When a request_type is ‘release’ or ‘requeue’, the format of a generated

message is governed by a per-policy setting $release_format according to

the table above. Only the ‘attach’, ‘plain’ and ‘resend’ values are useful.

A default setting is:

$release_format = ‘resend’; # with alternatives: attach, plain, resend

A plain-text part (if used) is taken from a $notify_release_templ template

and a sending address is obtained from %hdrfrom_notify_release_by_ccat.

When a request_type is ‘report’, the format of a generated message is

governed by a per-policy setting $report_format according to the table

above. Only the following settings are useful: arf, attach, plain, resend.

A default setting is:

$report_format = ‘arf’; # alternatives: arf, attach, plain, resend

A plain-text part (if used) is obtained from a $notify_report_templ

template, and a sending address from %hdrfrom_notify_report_by_ccat.

It is possible to automatically generate abuse reports from custom hooks

by calling delivery_status_notification() and mail_dispatch(). Extreme

care must be taken to only produce legitimate abuse reports (about true

fraud and true spam), sent only to parties that are truly responsible for

a message being reported. Non-repudiation is a key factor here – trust

only header fields covered by a valid DKIM signature, or generated by

your own MX MTA (such as an IP address of the last hop), and only report

messages received from a network which officially belongs to the party

(according to whois). Rate-limiting should be used, and abuse reports on

the same abuser should only be sent once in a time interval of several

hours. A SQL database can be used to maintain a list of recently reported

abusers, thus preventing excessive reports.

- introduced a variation of a message release from a quarantine, allowing

a releaser to send an abuse report based on a quarantined message.

It is implemented by:

* enhancing a subroutine delivery_status_notification as described

in the previous item;

* extending AM.PDP protocol with a ‘request=report’ attribute

which can be used in place of a ‘request=release’,

* enhancing the ‘amavisd-release’ utility program to allow sending an

attribute ‘request=release’ or ‘request=requeue’ or ‘request=report’

based on its program name. By making a soft or hard link named

‘amavisd-report’ linking to ‘amavisd-release’, the utility will

send a ‘request=report’ in place of the usual ‘request=release’,


# ln -s amavisd-release amavisd-report

# ln -s amavisd-release amavisd-requeue

$ amavisd-report spam/k/kg2P0rP9Lpu3.gz ”

- releasing from a quarantine can push a released message to an attachment

(Content-Type: message/rfc822), with a configurable template for a header

section and the plain-text part; select by: $release_format=’attach’;

suggested by Patrick Ben Koetter;

- detect and save a new attribute SOURCE from an XFORWARD smtp command;

the value is also accepted as AM.PDP protocol attribute ‘client_source’.

Possible values are: ‘LOCAL’, ‘REMOTE’, or ‘[UNAVAILABLE]‘, the information

corresponds to ‘local_header_rewrite_clients’ postfix setting and is

not supposed to be used for security decisions according to Postfix

documentation (which makes it less interesting for our purposes);

- added client and server support for a PORT attribute of an XFORWARD command,

allowing MTA to pass a TCP port number of a remote client to a content

filter (and back if necessary); the PORT attribute is made available

with Postfix version 2.5 (20071004); a source port number is also

accepted as an AM.PDP protocol attribute ‘client_port’;

- updated now supports a source port number information in

queries while preserving backwards compatibility with previous versions

of amavisd-new. Version 2.6.0 of amavisd requires a new version of (supplied in the 2.6.0 distribution) if operating system

fingerprinting is enabled. A source port number information in a query

allows to locate a matching entry in its cache faster and

also more accurately when multiple connections are present from clients

behind NAT using the same IP address. The source port number is made

available to a content filter since Postfix version 2.5 (20071004);

- besides the ability to send queries to, amavisd now also

supports sending queries directly to a p0f program over a Unix socket

using a p0f query protocol. There is a bug in p0f-2.0.8 (and probably in

earlier versions) which makes it send back incorrect results at times, i.e.

results belonging to some other unrelated session, so a patch to p0f-2.0.8

MUST be applied in order to use a direct querying mechanism – author has

been notified. The patch is supplied: p0f-patch.

There are currently no advantages (and some disadvantages) in choosing

direct queries to p0f, compared to sending queries to,

so this new method is not currently recommended. Disadvantages are:

* p0f uses a linear search over its list of recent sessions, whereas uses a fast hash lookup method;

* p0f keeps a relatively small list of recent sessions which is limited

by the number of slots (size can be specified on a command line, but

is limited by a linear search time), whereas expires

old entries according to time since entered and is thus independent

of a current mail rate;

* a direct p0f query protocol uses packed binary data and its on-the-wire

representation may depend on a compiler used, so it may be incompatible

with queries sent by amavisd, whereas the queries and

replies use a more environment-independent textual representation.

To let amavisd sent queries directly to p0f, specify a p0f socket path:

$os_fingerprint_method = ‘p0f:/var/amavis/home/p0f.sock’;

and specify an IP address and a port number on which MTA is listening:

$os_fingerprint_dst_ip_and_port = ‘[]:25′;

because p0f requires this information in a query and the information

is not made available to a content filter via XFORWARD command

(the does not need this information).

To send queries to (traditional and recommended), use:

$os_fingerprint_method = ‘p0f:′;

as before. The $os_fingerprint_dst_ip_and_port in this case is not needed

and is ignored.

- usually a sending address in spam messages is faked and it is desirable

to suppress most if not all bounces by keeping $sa_dsn_cutoff_level low,

but sometimes it may be possible to be more certain of the validity of

a sending address, and when such mail is considered spam, it may still be

desirable to send a non-delivery notification, knowing that a notification

will most likely be addressed to a genuine sender.

Two new settings are provided for this purpose:

@spam_crediblefrom_dsn_cutoff_level_bysender_maps and


(with their default being $sa_crediblefrom_dsn_cutoff_level),

complementing the existing @spam_dsn_cutoff_level_bysender_maps and


It is expected that $sa_crediblefrom_dsn_cutoff_level would be set somewhat

higher than $sa_dsn_cutoff_level, allowing for more bounces to be generated

for spam from likely-to-be-genuine senders (possibly false positives).

The choice between taking a cutoff value from one or the other pair of

settings depends on an attribute $msginfo->sender_credible – when it is

true (e.g. some nonempty string) the *spam_crediblefrom_* settings will

be used instead of the baseline @spam_dsn_cutoff_level_*maps.

An initial value of a sender_credible attribute as provided by amavisd

is true if either the ‘originating’ flag is true (e.g. mail from inside),

or if dkim_envsender_sig attribute is true, e.g. a domain of a valid

DKIM signature matches envelope sender address, otherwise it is false.

A user-provided custom hook code is free to change the value of

sender_credible attribute. An exact value does not matter (it is only

interpreted as a boolean), but serves for logging purposes. Heuristics

may be based on some tests provided by SpamAssassin, on DKIM signatures,

on p0f results, on policy banks, etc.

Postfix Virus Scan – Install ClamAV

Posted by Filed Under Virus Control with Comments Off

Install the ClamAV Daemon

Of course YUM, if installed is the easiest method of installing these programs as it meets all the dependencies at one time.

If you cannot install clamav with yum the next option is to download the RPMS from Note that you want the latest version for your operating system.

Ubuntu Install
Clamav is in the repository for Ubuntu so you can use apt-get.

apt-get install clamav clamav-milter clamd

Copyright CyberMontana Inc. and
All rights reserved. Cannot be reproduced without written permission. Box 1262 Trout Creek, MT 59874