username@domain login name for email account with virtualmin and postfix

For IMAP and POP3 authentication, all you have to do is change the “Format for usernames that include domain” in:

Virtualmin > System Settings > Server Templates > Default Settings > Mail for Domain

to be “user@domain”.

However, Cyrus SASL, which is what handles the SMTP authentication, requires a special flag on it to handle user@domain usernames, a -r in the settings. The magical file you need to edit is /etc/sysconfig/saslauthd. At the bottom you will see the following:

Additional flags to pass to saslauthd on the command line.
See saslauthd(8) for the list of accepted flags. FLAGS=-r

Just make your FLAGS= like mine does. This will pass the -r to the sasl authentication daemon, and your user@domain authentication will work!

Let me know if you have any other questions.

Originally found at : http://blog.molski.nl/2009/10/07/virtualmin-and-userdomain-pop3smtp-login-style/

Setup dkim on postfix with amavisd-new

step by step instruction coming soon…

Setting up DKIM mail signing and verification from http://www.ijs.si/software/amavisd/

Setting up DKIM mail signing and verification

A DKIM standard (RFC 4871) states the following, which applies
to its predecessor DomainKeys (historical: RFC 4870) as well:


DomainKeys Identified Mail (DKIM)
defines a mechanism by which email
messages can be cryptographically signed, permitting a signing domain
to claim responsibility for the introduction of a message into the
mail stream. Message recipients can verify the signature by querying
the signer’s domain directly to retrieve the appropriate public key,
and thereby confirm that the message was attested to by a party in
possession of the private key for the signing domain.

The DomainKeys specification was a primary source from which the
DomainKeys Identified Mail [DKIM] specification has been derived.
The purpose in submitting the RFC 4870 document is as an historical reference
for deployed implementations written prior to the DKIM specification.

The main advantage of DKIM signing to sending domains
is that it allows recipients to reliably validate mail origin for
purposes of whitelisting on spam checks and whitelisting
reception of otherwise banned mail contents. By signing outbound
mail you give your correspondents a chance to distinguish between
your genuine mail, and fraud or spam mail which may happen to carry
your domain name as a sender address. Signing outbound mail is a
kind gesture towards recipients, making it much easier for them
to treat your mail as important or desirable if they choose so.

The main advantage of DKIM signature verification to recipients
is that it allows them to reliably distinguish genuine mail originating
from a claimed sending domain from other (possibly faked) mail. It
makes signature-based whitelisting a reliable mechanism.
It also makes it possible to recognize and automatically discard
fake mail claiming to be from domains which are known to always
sign their outbound mail and to always send mail directly. Coupled
with reputation schemes (mostly manual/static at present,
or dynamic in the future) makes it possible to assign score points
(positive or negative) based on merit and past experience
with each signing domain. A valid signature also offers
non-repudiation: a domain which signed a message can not
disclaim message origin, which offers recipient a strong argument
when reporting abuse to the signing domain.

For the impatient – signing from scratch

Here is a quick Spartanic setup of DKIM signing and DKIM/DK
verification by amavisd for the impatient, without much explanation,
assuming all originating mail comes from internal networks (not
from authenticated roaming clients), only one domain needs
signing, using default signature tags, no milters are in use
and no mailing list manager needs signing. No changes in Postfix
configuration is necessary for this simple setup. For more
information and more complex setups please see sections
further on.

Generate a signing key:

  $ amavisd genrsa /var/db/dkim/example-foo.key.pem

add to amavisd.conf:

  $enable_dkim_verification = 1;
  $enable_dkim_signing = 1;
  dkim_key('example.com', 'foo', '/var/db/dkim/example-foo.key.pem');
  @dkim_signature_options_bysender_maps = (
    { '.' => { ttl => 21*24*3600, c => 'relaxed/simple' } } );
  @mynetworks = qw(0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12
                   192.168.0.0/16);  # list your internal networks

run:

  $ amavisd showkeys

add the public key (as displayed) to your DNS zone, increment SOA
sequence number and reload DNS; then test signing and a published key:

  $ amavisd testkeys

if all went well:

  $ amavisd reload

For the impatient – replacing
signing by dkim-milter with signing by amavisd

For sites already signing their mail by dkim-milter, most work
of preparing signing keys and publishing public keys in DNS has
already been done. All it needs to be done is to declare these
signing keys in amavisd.conf and turn on $enable_dkim_signing.

To facilitate transition of DKIM signing from dkim-milter to amavisd-new,
a new command-line tool is available with amavisd-new-2.6.2 (the extra
utility code is not loaded during normal operation), taking a file name
as its argument, e.g.:

  $ amavisd convert_keysfile /var/db/dkim/keysfile.txt

and writing to stdout a set of lines that may be directly included into
amavisd.conf configurations file, matching semantics of a dkim-filter
keys file. It can be useful during transition, or for those who prefer
to specify signing keys and sender-to-key mappings as a file in a syntax
compatible with options -K -k of dkim-filter, and can live with limitations
of such syntax. See dkim-filter(8) man page for details on the
syntax.

The produced output consists of signing key declarations (calls to
a procedure dkim_key), where each call normally corresponds to exactly
one DNS resource record publishing a corresponding DKIM public key.
When necessary output also produces an assignment to a list of lookup
tables @dkim_signature_options_bysender_maps, which supplies non-default
mappings of sender domains to signing keys, e.g. when third-party
signatures are desired.

Implementation and mail flow

Signing of originating mail (or mail being redistributed by our domain),
and verifying signatures of incoming mail are two tasks that can be
performed by the same program, or they can be performed by separate entities.
Traditionally with sendmail, both tasks are performed by one milter,
which may be easier to maintain, but has certain disadvantages.

Verifying signatures should be performed early, before any local mail
transformations get a chance of invalidating a signature, e.g. by performing
MIME conversions to quote-printable, by fixing syntactically invalid mail
header section, by reformatting or reordering some header fields (some MTAs
do it frivolously), by modifying/inserting/removing certain header
fields, or by a local mailing list modifying mail text, e.g. by appending
footers.

Signing outgoing mail should be performed late, after mail sanitation,
after conversion to 7-bit characters (to avoid later uncontrollable
changes by a relaying or receiving MTA), and after editing header
section by a content filter. Similar applies to local mailing lists,
which may be rewriting messages, requiring them to be re-signed by
the domain hosting a mailing list, just before being sent out.

Starting with amavisd-new version 2.6.0, DKIM signing can be
performed directly by amavisd (using a Perl module Mail::DKIM,
which is the same module as used by DKIMproxy and by SpamAssassin).
Signing directly by amavisd reduces setup complexity using a milter
or DKIMproxy, and avoids additional data transfers. Regarding mail
flow through the system there are similarities between signing in
amavisd and signing by dkim-milter, which is why the diagram below
shows both possibilities.

For verification there are three choices: either amavisd itself
can do it by calling Mail::DKIM directly, or a SpamAssassin plugin
can do it by calling the same Perl module, or a milter in
verification-only mode can be invoked by an incoming Postfix
smtpd service.

Advantage of invoking signature verification by amavisd
is that all mail is checked for signatures, regardless of
whether SpamAssassin is called or not. Typically messages beyond
a certain size are not passed to SpamAssassin, and neither are
infected message or identified bounces. Amavisd also offers loading
of policy banks based on valid DKIM/DK signatures (e.g. allowing
some domains to send-in otherwise banned files, or whitelisting on
spam), offers to add score points based on signing domain reputation,
and adds Authentication-Results header field (like a dkim-milter
does).

Invoking signature verification by SpamAssassin has an
advantage that DKIM-based or DomainKeys-based whitelisting or scoring
can be used, but has a disadvantage that possibly not all mail is
checked (e.g. large mail and infected mail may be exempt from spam
checks). Performing the same signature validation task twice (by
amavisd and by SA) may seem wasteful, but in practice it is not
too bad: thanks to DNS server caching a network lookup for a
public signing key is only done once, and as SpamAssassin does not
receive large mail for processing, its signature verification is
very quick: few milliseconds for non-signed mail, and of the order
of a tenth of a second for signed mail.

Invoking signature verification by calling a milter from
incoming smtpd service has an advantage that it has the best chance
of seeing mail in its pristine form (before canonical and virtual
mapping or masquerading by MTA, regardless of their settings).
Because it is poorly integrated with the rest of the chain (e.g. with
SpamAssassin rules and amavisd policy banks), and because it adds
one extra data transfer, it is mainly still useful as a way to
double-check the correctness of DKIM validation by having two
independent implementations in use, each inserting its independently
derived Authentication-Results header field into passed mail.

To sign as late as possible with a dkim-milter, the signing
milter can be invoked by a Postfix smtpd service which is receiving
content-checked mail from a content filter such as amavisd-new.
As this second-stage smtpd service does not reliably know how a
given message came into a mail system and whether it is supposed
to be signed or not, a clean solution is to provide two (or more)
parallel paths through MTA and through a content filter, one used
for mail that is eligible for being signed (originating mail),
the other for all the rest. This same dual path approach through
amavisd is beneficial for signing by amavisd too, for the same
reason of providing a reliable source of information on mail
origin to a signature choosing code:

              +------+
              |verify|          (verify)
              +--+---+              | (by amavisd and/or SA)
                ^^^ milter          |
incoming:       |||             +---v-------+
  MX ---->  25 smtpd ---> 10024 >           >---> 10025 smtpd -->
                 ||             |           |
  SASL -->  25 smtpd \          |  amavisd  | (notifications)
submission        |   +->       |           >--->_
  mynets->  25 smtpd ---> 10026 >ORIGINATING>---> 10027 smtpd -->
submission            +->       +-------^---+            |
       --> 587 smtpd /  :               |                v milter
                       (convert         |             +------+
                       to 7-bit)      (sign)          | sign |
                                                      +------+

There are other benefits to providing two parallel paths: a content
filter may be configured to apply different rules and settings to mail
that is known to be originating from our users. Some suggestions: apply
less strict banning rules, enable spam administrator notifications for
internally originating spam and viruses, letting SpamAssassin rules be
conditionalized based on amavisd-new policy banks loaded, etc.

Configuring multiple mail paths
in Postfix

Here is one way of configuring Postfix for providing two paths
through a content filter. Locally submitted or authenticated mail
will go to a content filter to its port 10026 and will be signed on
its way out (either by amavisd or by a signing milter). All other
mail (incoming) will be diverted to port 10024 for normal content
filtering, and will not be eligible for signing.

main.cf:

  # on re-queueing of a message smtpd_*_restrictions do not apply,
  # so we'd better provide a safe default for a content_filter,
  # even at an expense of later flipping the choice twice
  # (which adds a bit to log clutter, but never mind)
  #
  content_filter = amavisfeed:[127.0.0.1]:10024

  # each triggered FILTER deposits its argument into a
  # content_filter setting, the last deposited value applies
  #
  smtpd_sender_restrictions =
    check_sender_access regexp:/etc/postfix/tag_as_originating.re
    permit_mynetworks
    permit_sasl_authenticated
    permit_tls_clientcerts
    check_sender_access regexp:/etc/postfix/tag_as_foreign.re

  # Make sure to assign FILTER tags in restrictions which
  # are only invoked once per message, e.g. client or sender
  # restrictions, but NOT on smtpd_recipient_restrictions,
  # as a message may have multiple recipients, so multiple
  # passes through FILTER tag assignments can yield a
  # surprising (and incorrect) result.

/etc/postfix/tag_as_originating.re:

  /^/  FILTER amavisfeed:[127.0.0.1]:10026

/etc/postfix/tag_as_foreign.re:

  /^/  FILTER amavisfeed:[127.0.0.1]:10024

In master.cf set up two listening smtpd services for receiving
filtered mail from amavisd (as per README.postfix), one on tcp
port 10025 (for inbound mail) and the other on port 10027 (for
originating mail). If a signing milter is in use it will be
attached to a smtpd service on 10027 only. If no milters are
in use and signing is done by amavisd, both smtpd services can
have exactly the same settings, and in fact only one suffices,
in which case redirecting $forward_method and $notify_method to
‘smtp:[127.0.0.1]:10027’ in later example can be disregarded.

Configuring multiple mail paths
in amavisd

In amavisd.conf two parallel paths need to be provided,
one receiving on port 10024 and forwarding to 10025,
the other receiving on port 10026 and forwarding to 10027.

  $inet_socket_port = [10024,10026];  # listen on two ports

The 10024>10025 path will be controlled by a default policy bank,
the other (10026>10027), dedicated to mail intended to be signed,
will use a policy bank (arbitrarily) named ORIGINATING:

  $forward_method = 'smtp:[127.0.0.1]:10025';  # MTA with non-signing service
  $notify_method  = 'smtp:[127.0.0.1]:10027';  # MTA with signing service

  # switch policy bank to 'ORIGINATING' for mail received on port 10026:
  $interface_policy{'10026'} = 'ORIGINATING';

  $policy_bank{'ORIGINATING'} = {  # mail originating from our users
    originating => 1,  # indicates client is ours, allows signing
    #
    # force MTA to convert mail to 7-bit before DKIM signing
    # to avoid later conversions which could destroy signature:
    smtpd_discard_ehlo_keywords => ['8BITMIME'],
    #
    # forward to a smtpd service providing DKIM signing service
    # (if using a signing milter instead of signing by amavisd):
    forward_method => 'smtp:[127.0.0.1]:10027',
    #
    # other special treatment of locally originating mail,
    # just some suggestions here:
    spam_admin_maps  => ["spamalert\@$mydomain"],  # warn of spam from us
    virus_admin_maps => ["virusalert\@$mydomain"],
    banned_filename_maps => ['ALT-RULES'],         # more relaxed rules
    spam_quarantine_cutoff_level_maps => undef,    # quarantine all spam
    spam_dsn_cutoff_level_maps => undef,
    spam_dsn_cutoff_level_bysender_maps => # bounce to local senders only
      [ { lc(".$mydomain") => undef,  '.' => 15 } ],
  };

The smtpd_discard_ehlo_keywords=>['8BITMIME'] serves
to persuade Postfix to convert mail to 7-bit quoted-printable before
submitting it to content filtering and signing. Avoiding 8-bit characters
in mail body makes signatures less susceptible to breaking by some
relaying or receiving MTA over which we have no control.
The same effect (making Postfix convert outgoing mail to 7-bits
before DKIM signing) could be achieved by a Postfix setting
smtp_discard_ehlo_keywords=8bitmime on a smtp service
feeding mail-to-be-signed to amavisd, but this would require setting
up two such services, one with the option and one without.

Note that 8-bit to 7-bit conversion may break a S/MIME or PGP signature,
so if mail signing is in use, it may not be desirable to let Postfix
do the conversion, and it may be acceptable to take a risk that a remote
MTA will clobber signatures if it decides the mail text is to be converted
to 7-bits QP. The only reliable solution in this case is to configure
MUA clients to stick to 7-bit characters/encodings before generating
S/MIME or PGP signatures.

The following text from the Postfix documentation file MILTER_README
should be disregarded — amavisd is 8-bit clean,
and we do want Postfix to convert to 7-bits on the signing path
but not on the other path:
Content
filters may break domain key etc. signatures. If you use an SMTP-based
content filter, then you should add a line to master.cf with
“-o disable_mime_output_conversion=yes”, as described in the
advanced content filter example.

While testing how the configured system plays with some mailing lists
(such as postfix-users or SpamAssassin users list), one has
to keep in mind that amavisd-new caches spam checking results of recently
seen message bodies: a mail going out to a mailing list is not yet signed
as it reaches a content filter, but the SpamAssassin verdict is remembered
at that point (claiming the message is not signed). When this message
with unchanged body comes back from a mailing list, this time signed
in the header section by our domain, the signature should prove correct,
yet the cached result from a minute ago still claims the message is not
signed. If this is of concern, one can turn off caching of spam checking
results for ham by setting: $spam_check_negative_ttl = 0;

While on the topic of providing multiple paths through amavisd,
when one has to deal with a mailing list manager (e.g. Mailman) in the
same setup, and re-signing of its fan-out mail is desired, it may be
useful to add a third path through amavisd, this one stripped down to
bare bones, providing only DKIM signing and nothing else (no virus or
spam checks, no decoding), as these checks were already done once on
mail before it reached a mailing list manager. Here is one possibility,
accepting mail on port 10028 and sending it to 10025:

  $inet_socket_port = [10024,10026,10028];

  $interface_policy{'10028'} = 'NOCHECKS';

  $policy_bank{'NOCHECKS'} = {  # no checks, just DKIM signing
    originating => 1,  # allows signing
    forward_method => 'smtp:[127.0.0.1]:10025',
    smtpd_greeting_banner =>
      '${helo-name} ${protocol} ${product} NOCHECKS service ready',
    mynetworks_maps => [],  # avoids loading MYNETS policy unnecessarily
    os_fingerprint_method => undef,
    penpals_bonus_score => undef,
    bounce_killer_score => 0,
    bypass_decode_parts => 1,
    bypass_header_checks_maps => [1],
    bypass_virus_checks_maps  => [1],
    bypass_spam_checks_maps   => [1],
    bypass_banned_checks_maps => [1],
    spam_lovers_maps          => [1],
    banned_files_lovers_maps  => [1],
    archive_quarantine_to_maps => [],
    remove_existing_x_scanned_headers => undef,
    remove_existing_spam_headers => undef,
    signed_header_fields => { 'Sender' => 1 },
  };

amavisd.conf example

use strict;

# a minimalistic configuration file for amavisd-new with all necessary settings
#
# see amavisd.conf-default for a list of all variables with their defaults;
# see amavisd.conf-sample for a traditional-style commented file;
# for more details see documentation in INSTALL, README_FILES/*
# and at http://www.ijs.si/software/amavisd/amavisd-new-docs.html

# HEADER
$allowed_added_header_fields{lc(‘X-Spam-Checker-Version’)} = 0;

# COMMONLY ADJUSTED SETTINGS:

# @bypass_virus_checks_maps = (1); # controls running of anti-virus code
# @bypass_spam_checks_maps = (1); # controls running of anti-spam code
# $bypass_decode_parts = 1; # controls running of decoders&dearchivers

$max_servers = 2; # num of pre-forked children (2..30 is common), -m
$daemon_user = "amavis"; # (no default; customary: vscan or amavis), -u
$daemon_group = "amavis"; # (no default; customary: vscan or amavis), -g

$mydomain = ‘mail.example.com’; # a convenient default for other settings

# $MYHOME = ‘/var/amavis’; # a convenient default for other settings, -H
$TEMPBASE = "$MYHOME/tmp"; # working directory, needs to exist, -T
$ENV{TMPDIR} = $TEMPBASE; # environment variable TMPDIR, used by SA, etc.
#$QUARANTINEDIR = "/var/virusmails";
# $quarantine_subdir_levels = 1; # add level of subdirs to disperse quarantine
# $release_format = ‘resend’; # ‘attach’, ‘plain’, ‘resend’
# $report_format = ‘arf’; # ‘attach’, ‘plain’, ‘resend’, ‘arf’

# $daemon_chroot_dir = $MYHOME; # chroot directory or undef, -R

$db_home = "$MYHOME/db"; # dir for bdb nanny/cache/snmp databases, -D
# $helpers_home = "$MYHOME/var"; # working directory for SpamAssassin, -S
# $lock_file = "$MYHOME/var/amavisd.lock"; # -L
# $pid_file = "$MYHOME/var/amavisd.pid"; # -P
#NOTE: create directories $MYHOME/tmp, $MYHOME/var, $MYHOME/db manually

$log_level = 0; # verbosity 0..5, -d
$log_recip_templ = undef; # disable by-recipient level-0 log entries
$DO_SYSLOG = 1; # log via syslogd (preferred)
$syslog_facility = ‘mail’; # Syslog facility as a string
# e.g.: mail, daemon, user, local0, … local7
$syslog_priority = ‘debug’; # Syslog base (minimal) priority as a string,
# choose from: emerg, alert, crit, err, warning, notice, info, debug

$enable_db = 1; # enable use of BerkeleyDB/libdb (SNMP and nanny)
$enable_global_cache = 1; # enable use of libdb-based cache if $enable_db=1
$nanny_details_level = 2; # nanny verbosity: 1: traditional, 2: detailed
$enable_dkim_verification = 1; # enable DKIM signatures verification
$enable_dkim_signing = 1; # load DKIM signing code, keys defined by dkim_key

dkim_key(‘example.com’, ‘dkim’, ‘/etc/dkim/example.com.key.pem’);
@dkim_signature_options_bysender_maps = ( { ‘.’ => { ttl => 21*24*3600, c => ‘relaxed/simple’ } } );
@mynetworks = qw(127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10
); # list your internal networks

#@local_domains_maps = ( [".$mydomain"] ); # list of all local domains
@local_domains_maps = ( 1 );
#@local_domains_maps = ( ["."] ); # list of all local domains

#@mynetworks = qw( 127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10
# 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 );

$unix_socketname = "$MYHOME/amavisd.sock"; # amavisd-release or amavis-milter
# option(s) -p overrides $inet_socket_port and $unix_socketname

# $inet_socket_port = 10024; # listen on this local TCP port(s)
$inet_socket_port = [10024,10026]; # listen on multiple TCP ports

$policy_bank{‘MYNETS’} = { # mail originating from @mynetworks
originating => 1, # is true in MYNETS by default, but let’s make it explicit
os_fingerprint_method => undef, # don’t query p0f for internal clients
};

# it is up to MTA to re-route mail from authenticated roaming users or
# from internal hosts to a dedicated TCP port (such as 10026) for filtering
$interface_policy{‘10026’} = ‘ORIGINATING’;

$policy_bank{‘ORIGINATING’} = { # mail supposedly originating from our users
originating => 1, # declare that mail was submitted by our smtp client
allow_disclaimers => 1, # enables disclaimer insertion if available
# notify administrator of locally originating malware
virus_admin_maps => ["virusalert\@$mydomain"],
spam_admin_maps => ["virusalert\@$mydomain"],
warnbadhsender => 1,
# forward to a smtpd service providing DKIM signing service
forward_method => ‘smtp:[127.0.0.1]:10027’,
# force MTA conversion to 7-bit (e.g. before DKIM signing)
smtpd_discard_ehlo_keywords => [‘8BITMIME’],
bypass_banned_checks_maps => [1], # allow sending any file names and types
terminate_dsn_on_notify_success => 0, # don’t remove NOTIFY=SUCCESS option
};

$interface_policy{‘SOCK’} = ‘AM.PDP-SOCK’; # only applies with $unix_socketname

# Use with amavis-release over a socket or with Petr Rehor’s amavis-milter.c
# (with amavis-milter.c from this package or old amavis.c client use ‘AM.CL’):
$policy_bank{‘AM.PDP-SOCK’} = {
protocol => ‘AM.PDP’,
auth_required_release => 0, # do not require secret_id for amavisd-release
};

$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 14; # add ‘spam detected’ headers at that level
$sa_kill_level_deflt = 11.9; # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 13; # spam level beyond which a DSN is not sent
$sa_crediblefrom_dsn_cutoff_level = 18; # likewise, but for a likely valid From
# $sa_quarantine_cutoff_level = 25; # spam level beyond which quarantine is off
$penpals_bonus_score = 8; # (no effect without a @storage_sql_dsn database)
$penpals_threshold_high = $sa_kill_level_deflt; # don’t waste time on hi spam
$bounce_killer_score = 100; # spam score points to add for joe-jobbed bounces

$sa_mail_body_size_limit = 400*1024; # don’t waste time on SA if mail is larger
$sa_local_tests_only = 0; # only tests which do not require internet access?

# @lookup_sql_dsn =
# ( [‘DBI:mysql:database=mail;host=127.0.0.1;port=3306’, ‘user1’, ‘passwd1’],
# [‘DBI:mysql:database=mail;host=host2’, ‘username2’, ‘password2’],
# ["DBI:SQLite:dbname=$MYHOME/sql/mail_prefs.sqlite", ”, ”] );
# @storage_sql_dsn = @lookup_sql_dsn; # none, same, or separate database

# $timestamp_fmt_mysql = 1; # if using MySQL *and* msgs.time_iso is TIMESTAMP;
# defaults to 0, which is good for non-MySQL or if msgs.time_iso is CHAR(16)

$virus_admin = "virusalert\@$mydomain"; # notifications recip.

$mailfrom_notify_admin = "virusalert\@$mydomain"; # notifications sender
$mailfrom_notify_recip = "virusalert\@$mydomain"; # notifications sender
$mailfrom_notify_spamadmin = "spam.police\@$mydomain"; # notifications sender
$mailfrom_to_quarantine = ”; # null return path; uses original sender if undef

$hdr_encoding = ‘utf-8’; # header field bodies charset
$bdy_encoding = ‘utf-8’; # notification body text charset
$hdr_encoding_qb = ‘Q’; # quoted-printable (Q or B)
$warnvirussender = 1; # I want to warn people, who have got virus.
$warnbannedsender = 1;
$warnbadhsender = 1;
$warnspamsender = 1;
$warnvirusrecip = 1; # I want to warn my users about virus send to them.
$warnbannedrecip = 1;
$warnbadhrecip = 1;
$warn_offsite = 0; # I want to warn senders/recipients, that are not
#$hdrfrom_notify_sender = ‘spam.police’;
$hdrfrom_notify_sender = "\"Content-filter at mx.example.com\" <spam.police\@$myhostname>";
@addr_extension_virus_maps = (‘virus’);
@addr_extension_banned_maps = (‘banned’);
@addr_extension_spam_maps = (‘spam’);
@addr_extension_bad_header_maps = (‘badh’);
# $recipient_delimiter = ‘+’; # undef disables address extensions altogether
# when enabling addr extensions do also Postfix/main.cf: recipient_delimiter=+

$path = ‘/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin’;
# $dspam = ‘dspam’;

$MAXLEVELS = 14;
$MAXFILES = 1500;
$MIN_EXPANSION_QUOTA = 100*1024; # bytes (default undef, not enforced)
$MAX_EXPANSION_QUOTA = 300*1024*1024; # bytes (default undef, not enforced)

$sa_spam_subject_tag = ‘***SPAM*** ‘;
$defang_virus = 1; # MIME-wrap passed infected mail
$defang_banned = 1; # MIME-wrap passed mail containing banned name
# for defanging bad headers only turn on certain minor contents categories:
$defang_by_ccat{+CC_BADH.",3"} = 1; # NUL or CR character in header
$defang_by_ccat{+CC_BADH.",5"} = 1; # header line longer than 998 characters
$defang_by_ccat{+CC_BADH.",6"} = 1; # header field syntax error

# OTHER MORE COMMON SETTINGS (defaults may suffice):

$myhostname = ‘mx.example.com’; # must be a fully-qualified domain name!

$notify_method = ‘smtp:[127.0.0.1]:10027’;
$forward_method = ‘smtp:[127.0.0.1]:10025’; # set to undef with milter!

$final_virus_destiny = D_DISCARD;
$final_banned_destiny = D_BOUNCE;
$final_spam_destiny = D_PASS;
$final_bad_header_destiny = D_PASS;
# $bad_header_quarantine_method = undef;

# $os_fingerprint_method = ‘p0f:*:2345’; # to query p0f-analyzer.pl

## hierarchy by which a final setting is chosen:
## policy bank (based on port or IP address) -> *_by_ccat
## *_by_ccat (based on mail contents) -> *_maps
## *_maps (based on recipient address) -> final configuration value

# SOME OTHER VARIABLES WORTH CONSIDERING (see amavisd.conf-default for all)

# $warnbadhsender,
# $warnvirusrecip, $warnbannedrecip, $warnbadhrecip, (or @warn*recip_maps)
#
# @bypass_virus_checks_maps, @bypass_spam_checks_maps,
# @bypass_banned_checks_maps, @bypass_header_checks_maps,
#
# @virus_lovers_maps, @spam_lovers_maps,
# @banned_files_lovers_maps, @bad_header_lovers_maps,
#
# @blacklist_sender_maps, @score_sender_maps,
#
# $clean_quarantine_method, $virus_quarantine_to, $banned_quarantine_to,
# $bad_header_quarantine_to, $spam_quarantine_to,
#
# $defang_bad_header, $defang_undecipherable, $defang_spam

# REMAINING IMPORTANT VARIABLES ARE LISTED HERE BECAUSE OF LONGER ASSIGNMENTS

@keep_decoded_original_maps = (new_RE(
qr’^MAIL$’, # retain full original message for virus checking
qr’^MAIL-UNDECIPHERABLE$’, # recheck full mail if it contains undecipherables
qr’^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)’i,
# qr’^Zip archive data’, # don’t trust Archive::Zip
));

# for $banned_namepath_re (a new-style of banned table) see amavisd.conf-sample

$banned_filename_re = new_RE(

### BLOCKED ANYWHERE
# qr’^UNDECIPHERABLE$’, # is or contains any undecipherable components
# qr’^\.(exe-ms|dll)$’, # banned file(1) types, rudimentary
qr’^\.(exe|lha|tnef|cab|dll)$’, # banned file(1) types

### BLOCK THE FOLLOWING, EXCEPT WITHIN UNIX ARCHIVES:
# [ qr’^\.(gz|bz2)$’ => 0 ], # allow any in gzip or bzip2
[ qr’^\.(rpm|cpio|tar)$’ => 0 ], # allow any in Unix-type archives

qr’.\.(pif|scr)$’i, # banned extensions – rudimentary
# qr’^\.zip$’, # block zip type

### BLOCK THE FOLLOWING, EXCEPT WITHIN ARCHIVES:
# [ qr’^\.(zip|rar|arc|arj|zoo)$’=> 0 ], # allow any within these archives

qr’^application/x-msdownload$’i, # block these MIME types
qr’^application/x-msdos-program$’i,
qr’^application/hta$’i,

# qr’^message/partial$’i, # rfc2046 MIME type
# qr’^message/external-body$’i, # rfc2046 MIME type

# qr’^(application/x-msmetafile|image/x-wmf)$’i, # Windows Metafile MIME type
# qr’^\.wmf$’, # Windows Metafile file(1) type

# block certain double extensions in filenames
qr’\.[^./]*[A-Za-z][^./]*\.\s*(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)[.\s]*$’i,

# qr’\{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\}?’i, # Class ID CLSID, strict
# qr’\{[0-9a-z]{4,}(-[0-9a-z]{4,}){0,7}\}?’i, # Class ID extension CLSID, loose

qr’.\.(exe|vbs|pif|scr|cpl)$’i, # banned extension – basic
# qr’.\.(exe|vbs|pif|scr|cpl|bat|cmd|com)$’i, # banned extension – basic+cmd
# qr’.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta|
# inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|
# ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|
# wmf|wsc|wsf|wsh)$’ix, # banned ext – long
# qr’.\.(ani|cur|ico)$’i, # banned cursors and icons filename
# qr’^\.ani$’, # banned animated cursor file(1) type

# qr’.\.(mim|b64|bhx|hqx|xxe|uu|uue)$’i, # banned extension – WinZip vulnerab.
);
# See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262631
# and http://www.cknow.com/vtutor/vtextensions.htm

# ENVELOPE SENDER SOFT-WHITELISTING / SOFT-BLACKLISTING

@score_sender_maps = ({ # a by-recipient hash lookup table,
# results from all matching recipient tables are summed

# ## per-recipient personal tables (NOTE: positive: black, negative: white)
# ‘user1@example.com’ => [{‘bla-mobile.press@example.com’ => 10.0}],
# ‘user3@example.com’ => [{‘.ebay.com’ => -3.0}],
# ‘user4@example.com’ => [{‘cleargreen@cleargreen.com’ => -7.0,
# ‘.cleargreen.com’ => -5.0}],

## site-wide opinions about senders (the ‘.’ matches any recipient)
‘.’ => [ # the _first_ matching sender determines the score boost

new_RE( # regexp-type lookup table, just happens to be all soft-blacklist
[qr’^(bulkmail|offers|cheapbenefits|earnmoney|foryou)@’i => 5.0],
[qr’^(greatcasino|investments|lose_weight_today|market\.alert)@’i=> 5.0],
[qr’^(money2you|MyGreenCard|new\.tld\.registry|opt-out|opt-in)@’i=> 5.0],
[qr’^(optin|saveonlsmoking2002k|specialoffer|specialoffers)@’i => 5.0],
[qr’^(stockalert|stopsnoring|wantsome|workathome|yesitsfree)@’i => 5.0],
[qr’^(your_friend|greatoffers)@’i => 5.0],
[qr’^(inkjetplanet|marketopt|MakeMoney)\d*@’i => 5.0],
),

# read_hash("/var/amavis/sender_scores_sitewide"),

{ # a hash-type lookup table (associative array)
‘nobody@cert.org’ => -3.0,
‘cert-advisory@us-cert.gov’ => -3.0,
‘owner-alert@iss.net’ => -3.0,
‘slashdot@slashdot.org’ => -3.0,
‘securityfocus.com’ => -3.0,
‘ntbugtraq@listserv.ntbugtraq.com’ => -3.0,
‘security-alerts@linuxsecurity.com’ => -3.0,
‘mailman-announce-admin@python.org’ => -3.0,
‘amavis-user-admin@lists.sourceforge.net’=> -3.0,
‘amavis-user-bounces@lists.sourceforge.net’ => -3.0,
‘spamassassin.apache.org’ => -3.0,
‘notification-return@lists.sophos.com’ => -3.0,
‘owner-postfix-users@postfix.org’ => -3.0,
‘owner-postfix-announce@postfix.org’ => -3.0,
‘owner-sendmail-announce@lists.sendmail.org’ => -3.0,
‘sendmail-announce-request@lists.sendmail.org’ => -3.0,
‘donotreply@sendmail.org’ => -3.0,
‘ca+envelope@sendmail.org’ => -3.0,
‘noreply@freshmeat.net’ => -3.0,
‘owner-technews@postel.acm.org’ => -3.0,
‘ietf-123-owner@loki.ietf.org’ => -3.0,
‘cvs-commits-list-admin@gnome.org’ => -3.0,
‘rt-users-admin@lists.fsck.com’ => -3.0,
‘clp-request@comp.nus.edu.sg’ => -3.0,
‘surveys-errors@lists.nua.ie’ => -3.0,
’emailnews@genomeweb.com’ => -5.0,
‘yahoo-dev-null@yahoo-inc.com’ => -3.0,
‘returns.groups.yahoo.com’ => -3.0,
‘clusternews@linuxnetworx.com’ => -3.0,
lc(‘lvs-users-admin@LinuxVirtualServer.org’) => -3.0,
lc(‘owner-textbreakingnews@CNNIMAIL12.CNN.COM’) => -5.0,

# soft-blacklisting (positive score)
‘sender@example.net’ => 3.0,
‘.example.net’ => 1.0,

},
], # end of site-wide tables
});

@decoders = (
[‘mail’, \&do_mime_decode],
[‘asc’, \&do_ascii],
[‘uue’, \&do_ascii],
[‘hqx’, \&do_ascii],
[‘ync’, \&do_ascii],
[‘F’, \&do_uncompress, [‘unfreeze’,’freeze -d’,’melt’,’fcat’] ],
[‘Z’, \&do_uncompress, [‘uncompress’,’gzip -d’,’zcat’] ],
[‘gz’, \&do_uncompress, ‘gzip -d’],
[‘gz’, \&do_gunzip],
[‘bz2’, \&do_uncompress, ‘bzip2 -d’],
[‘lzo’, \&do_uncompress, ‘lzop -d’],
[‘rpm’, \&do_uncompress, [‘rpm2cpio.pl’,’rpm2cpio’] ],
[‘cpio’, \&do_pax_cpio, [‘pax’,’gcpio’,’cpio’] ],
[‘tar’, \&do_pax_cpio, [‘pax’,’gcpio’,’cpio’] ],
[‘deb’, \&do_ar, ‘ar’],
# [‘a’, \&do_ar, ‘ar’], # unpacking .a seems an overkill
[‘zip’, \&do_unzip],
[‘7z’, \&do_7zip, [‘7zr’,’7za’,’7z’] ],
[‘rar’, \&do_unrar, [‘rar’,’unrar’] ],
[‘arj’, \&do_unarj, [‘arj’,’unarj’] ],
[‘arc’, \&do_arc, [‘nomarch’,’arc’] ],
[‘zoo’, \&do_zoo, [‘zoo’,’unzoo’] ],
[‘lha’, \&do_lha, ‘lha’],
# [‘doc’, \&do_ole, ‘ripole’],
[‘cab’, \&do_cabextract, ‘cabextract’],
[‘tnef’, \&do_tnef_ext, ‘tnef’],
[‘tnef’, \&do_tnef],
# [‘sit’, \&do_unstuff, ‘unstuff’], # broken/unsafe decoder
[‘exe’, \&do_executable, [‘rar’,’unrar’], ‘lha’, [‘arj’,’unarj’] ],
);

@av_scanners = (

# ### http://www.clanfield.info/sophie/ (http://www.vanja.com/tools/sophie/)
# [‘Sophie’,
# \&ask_daemon, ["{}/\n", ‘/var/run/sophie’],
# qr/(?x)^ 0+ ( : | [\000\r\n]* $)/m, qr/(?x)^ 1 ( : | [\000\r\n]* $)/m,
# qr/(?x)^ [-+]? \d+ : (.*?) [\000\r\n]* $/m ],

# ### http://www.csupomona.edu/~henson/www/projects/SAVI-Perl/
# [‘Sophos SAVI’, \&sophos_savi ],

# ### http://www.clamav.net/
# [‘ClamAV-clamd’,
# \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
# qr/\bOK$/m, qr/\bFOUND$/m,
# qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# # NOTE: run clamd under the same user as amavisd, or run it under its own
# # uid such as clamav, add user clamav to the amavis group, and then add
# # AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# # this entry; when running chrooted one may prefer socket "$MYHOME/clamd".

### http://www.clamav.net/
[‘ClamAV-clamd’,
\&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock"],
qr/\bOK$/, qr/\bFOUND$/,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],

# ### http://www.clamav.net/ and CPAN (memory-hungry! clamd is preferred)
# # note that Mail::ClamAV requires perl to be build with threading!
# [‘Mail::ClamAV’, \&ask_clamav, "*", [0], [1], qr/^INFECTED: (.+)/m ],

# ### http://www.openantivirus.org/
# [‘OpenAntiVirus ScannerDaemon (OAV)’,
# \&ask_daemon, ["SCAN {}\n", ‘127.0.0.1:8127’],
# qr/^OK/m, qr/^FOUND: /m, qr/^FOUND: (.+)/m ],

# ### http://www.vanja.com/tools/trophie/
# [‘Trophie’,
# \&ask_daemon, ["{}/\n", ‘/var/run/trophie’],
# qr/(?x)^ 0+ ( : | [\000\r\n]* $)/m, qr/(?x)^ 1 ( : | [\000\r\n]* $)/m,
# qr/(?x)^ [-+]? \d+ : (.*?) [\000\r\n]* $/m ],

# ### http://www.grisoft.com/
# [‘AVG Anti-Virus’,
# \&ask_daemon, ["SCAN {}\n", ‘127.0.0.1:55555’],
# qr/^200/m, qr/^403/m, qr/^403 .*?: ([^\r\n]+)/m ],

# ### http://www.f-prot.com/
# [‘F-Prot fpscand’, # F-PROT Antivirus for BSD/Linux/Solaris, version 6
# \&ask_daemon,
# ["SCAN FILE {}/*\n", ‘127.0.0.1:10200’],
# qr/^(0|8|64) /m,
# qr/^([1235679]|1[01345]) |<[^>:]*(?i)(infected|suspicious|unwanted)/m,
# qr/(?i)<[^>:]*(?:infected|suspicious|unwanted)[^>:]*: ([^>]*)>/m ],

# ### http://www.f-prot.com/
# [‘F-Prot f-protd’, # old version
# \&ask_daemon,
# ["GET {}/*?-dumb%20-archive%20-packed HTTP/1.0\r\n\r\n",
# [‘127.0.0.1:10200’, ‘127.0.0.1:10201’, ‘127.0.0.1:10202’,
# ‘127.0.0.1:10203’, ‘127.0.0.1:10204’] ],
# qr/(?i)<summary[^>]*>clean<\/summary>/m,
# qr/(?i)<summary[^>]*>infected<\/summary>/m,
# qr/(?i)<name>(.+)<\/name>/m ],

# ### http://www.sald.com/, http://www.dials.ru/english/, http://www.drweb.ru/
# [‘DrWebD’, \&ask_daemon, # DrWebD 4.31 or later
# [pack(‘N’,1). # DRWEBD_SCAN_CMD
# pack(‘N’,0x00280001). # DONT_CHANGEMAIL, IS_MAIL, RETURN_VIRUSES
# pack(‘N’, # path length
# length("$TEMPBASE/amavis-yyyymmddTHHMMSS-xxxxx/parts/pxxx")).
# ‘{}/*’. # path
# pack(‘N’,0). # content size
# pack(‘N’,0),
# ‘/var/drweb/run/drwebd.sock’,
# # ‘/var/amavis/var/run/drwebd.sock’, # suitable for chroot
# # ‘/usr/local/drweb/run/drwebd.sock’, # FreeBSD drweb ports default
# # ‘127.0.0.1:3000’, # or over an inet socket
# ],
# qr/\A\x00[\x10\x11][\x00\x10]\x00/sm, # IS_CLEAN,EVAL_KEY; SKIPPED
# qr/\A\x00[\x00\x01][\x00\x10][\x20\x40\x80]/sm,# KNOWN_V,UNKNOWN_V,V._MODIF
# qr/\A.{12}(?:infected with )?([^\x00]+)\x00/sm,
# ],
# # NOTE: If using amavis-milter, change length to:
# # length("$TEMPBASE/amavis-milter-xxxxxxxxxxxxxx/parts/pxxx").

### http://www.kaspersky.com/ (kav4mailservers)
# [‘KasperskyLab AVP – aveclient’,
# [‘/usr/local/kav/bin/aveclient’,’/usr/local/share/kav/bin/aveclient’,
# ‘/opt/kav/5.5/kav4mailservers/bin/aveclient’,’aveclient’],
# ‘-p /var/run/aveserver -s {}/*’,
# [0,3,6,8], qr/\b(INFECTED|SUSPICION|SUSPICIOUS)\b/m,
# qr/(?:INFECTED|WARNING|SUSPICION|SUSPICIOUS) (.+)/m,
# ],
# NOTE: one may prefer [0],[2,3,4,5], depending on how suspicious,
# currupted or protected archives are to be handled

### http://www.kaspersky.com/
# [‘KasperskyLab AntiViral Toolkit Pro (AVP)’, [‘avp’],
# ‘-* -P -B -Y -O- {}’, [0,3,6,8], [2,4], # any use for -A -K ?
# qr/infected: (.+)/m,
# sub {chdir(‘/opt/AVP’) or die "Can’t chdir to AVP: $!"},
# sub {chdir($TEMPBASE) or die "Can’t chdir back to $TEMPBASE $!"},
# ],

### The kavdaemon and AVPDaemonClient have been removed from Kasperky
### products and replaced by aveserver and aveclient
# [‘KasperskyLab AVPDaemonClient’,
# [ ‘/opt/AVP/kavdaemon’, ‘kavdaemon’,
# ‘/opt/AVP/AvpDaemonClient’, ‘AvpDaemonClient’,
# ‘/opt/AVP/AvpTeamDream’, ‘AvpTeamDream’,
# ‘/opt/AVP/avpdc’, ‘avpdc’ ],
# "-f=$TEMPBASE {}", [0,8], [3,4,5,6], qr/infected: ([^\r\n]+)/m ],
# change the startup-script in /etc/init.d/kavd to:
# DPARMS="-* -Y -dl -f=/var/amavis /var/amavis"
# (or perhaps: DPARMS="-I0 -Y -* /var/amavis" )
# adjusting /var/amavis above to match your $TEMPBASE.
# The ‘-f=/var/amavis’ is needed if not running it as root, so it
# can find, read, and write its pid file, etc., see ‘man kavdaemon’.
# defUnix.prf: there must be an entry "*/var/amavis" (or whatever
# directory $TEMPBASE specifies) in the ‘Names=’ section.
# cd /opt/AVP/DaemonClients; configure; cd Sample; make
# cp AvpDaemonClient /opt/AVP/
# su – vscan -c "${PREFIX}/kavdaemon ${DPARMS}"

### http://www.centralcommand.com/
# [‘CentralCommand Vexira (new) vascan’,
# [‘vascan’,’/usr/lib/Vexira/vascan’],
# "-a s –timeout=60 –temp=$TEMPBASE -y $QUARANTINEDIR ".
# "–log=/var/log/vascan.log {}",
# [0,3], [1,2,5],
# qr/(?x)^\s* (?:virus|iworm|macro|mutant|sequence|trojan)\ found:\ ( [^\]\s’]+ )\ \.\.\.\ /m ],
# Adjust the path of the binary and the virus database as needed.
# ‘vascan’ does not allow to have the temp directory to be the same as
# the quarantine directory, and the quarantine option can not be disabled.
# If $QUARANTINEDIR is not used, then another directory must be specified
# to appease ‘vascan’. Move status 3 to the second list if password
# protected files are to be considered infected.

### http://www.avira.com/
### Avira AntiVir (formerly H+BEDV) or (old) CentralCommand Vexira Antivirus
# [‘Avira AntiVir’, [‘antivir’,’vexira’],
# ‘–allfiles -noboot -nombr -rs -s -z {}’, [0], qr/ALERT:|VIRUS:/m,
# qr/(?x)^\s* (?: ALERT: \s* (?: \[ | [^’]* ‘ ) |
# (?i) VIRUS:\ .*?\ virus\ ‘?) ( [^\]\s’]+ )/m ],
# NOTE: if you only have a demo version, remove -z and add 214, as in:
# ‘–allfiles -noboot -nombr -rs -s {}’, [0,214], qr/ALERT:|VIRUS:/,

### http://www.commandsoftware.com/
# [‘Command AntiVirus for Linux’, ‘csav’,
# ‘-all -archive -packed {}’, [50], [51,52,53],
# qr/Infection: (.+)/m ],

### http://www.symantec.com/
# [‘Symantec CarrierScan via Symantec CommandLineScanner’,
# ‘cscmdline’, ‘-a scan -i 1 -v -s 127.0.0.1:7777 {}’,
# qr/^Files Infected:\s+0$/m, qr/^Infected\b/m,
# qr/^(?:Info|Virus Name):\s+(.+)/m ],

### http://www.symantec.com/
# [‘Symantec AntiVirus Scan Engine’,
# ‘savsecls’, ‘-server 127.0.0.1:7777 -mode scanrepair -details -verbose {}’,
# [0], qr/^Infected\b/m,
# qr/^(?:Info|Virus Name):\s+(.+)/m ],
# NOTE: check options and patterns to see which entry better applies

# ### http://www.f-secure.com/products/anti-virus/ version 4.65
# [‘F-Secure Antivirus for Linux servers’,
# [‘/opt/f-secure/fsav/bin/fsav’, ‘fsav’],
# ‘–delete=no –disinf=no –rename=no –archive=yes –auto=yes ‘.
# ‘–dumb=yes –list=no –mime=yes {}’, [0], [3,6,8],
# qr/(?:infection|Infected|Suspected): (.+)/m ],

### http://www.f-secure.com/products/anti-virus/ version 5.52
# [‘F-Secure Antivirus for Linux servers’,
# [‘/opt/f-secure/fsav/bin/fsav’, ‘fsav’],
# ‘–virus-action1=report –archive=yes –auto=yes ‘.
# ‘–dumb=yes –list=no –mime=yes {}’, [0], [3,4,6,8],
# qr/(?:infection|Infected|Suspected|Riskware): (.+)/m ],
# NOTE: internal archive handling may be switched off by ‘–archive=no’
# to prevent fsav from exiting with status 9 on broken archives

# ### http://www.avast.com/
# [‘avast! Antivirus daemon’,
# \&ask_daemon, # greets with 220, terminate with QUIT
# ["SCAN {}\015\012QUIT\015\012", ‘/var/run/avast4/mailscanner.sock’],
# qr/\t\[\+\]/m, qr/\t\[L\]\t/m, qr/\t\[L\]\t([^[ \t\015\012]+)/m ],

# ### http://www.avast.com/
# [‘avast! Antivirus – Client/Server Version’, ‘avastlite’,
# ‘-a /var/run/avast4/mailscanner.sock -n {}’, [0], [1],
# qr/\t\[L\]\t([^[ \t\015\012]+)/m ],

# [‘CAI InoculateIT’, ‘inocucmd’, # retired product
# ‘-sec -nex {}’, [0], [100],
# qr/was infected by virus (.+)/m ],
# see: http://www.flatmtn.com/computer/Linux-Antivirus_CAI.html

### http://www3.ca.com/Solutions/Product.asp?ID=156 (ex InoculateIT)
# [‘CAI eTrust Antivirus’, ‘etrust-wrapper’,
# ‘-arc -nex -spm h {}’, [0], [101],
# qr/is infected by virus: (.+)/m ],
# NOTE: requires suid wrapper around inocmd32; consider flag: -mod reviewer
# see http://marc.theaimsgroup.com/?l=amavis-user&m=109229779912783

### http://mks.com.pl/english.html
# [‘MkS_Vir for Linux (beta)’, [‘mks32′,’mks’],
# ‘-s {}/*’, [0], [1,2],
# qr/–[ \t]*(.+)/m ],

### http://mks.com.pl/english.html
# [‘MkS_Vir daemon’, ‘mksscan’,
# ‘-s -q {}’, [0], [1..7],
# qr/^… (\S+)/m ],

# ### http://www.nod32.com/, version v2.52 (old)
# [‘ESET NOD32 for Linux Mail servers’,
# [‘/opt/eset/nod32/bin/nod32cli’, ‘nod32cli’],
# ‘–subdir –files -z –sfx –rtp –adware –unsafe –pattern –heur ‘.
# ‘-w -a –action-on-infected=accept –action-on-uncleanable=accept ‘.
# ‘–action-on-notscanned=accept {}’,
# [0,3], [1,2], qr/virus="([^"]+)"/m ],

# ### http://www.eset.com/, version v2.7 (old)
# [‘ESET NOD32 Linux Mail Server – command line interface’,
# [‘/usr/bin/nod32cli’, ‘/opt/eset/nod32/bin/nod32cli’, ‘nod32cli’],
# ‘–subdir {}’, [0,3], [1,2], qr/virus="([^"]+)"/m ],

# ### http://www.eset.com/, version 2.71.12
# [‘ESET Software ESETS Command Line Interface’,
# [‘/usr/bin/esets_cli’, ‘esets_cli’],
# ‘–subdir {}’, [0], [1,2,3], qr/virus="([^"]+)"/m ],

### http://www.eset.com/, version 3.0
# [‘ESET Software ESETS Command Line Interface’,
# [‘/usr/bin/esets_cli’, ‘esets_cli’],
# ‘–subdir {}’, [0], [1,2,3],
# qr/:\s*action="(?!accepted)[^"]*"\n.*:\s*virus="([^"]*)"/m ],

## http://www.nod32.com/, NOD32LFS version 2.5 and above
# [‘ESET NOD32 for Linux File servers’,
# [‘/opt/eset/nod32/sbin/nod32′,’nod32’],
# ‘–files -z –mail –sfx –rtp –adware –unsafe –pattern –heur ‘.
# ‘-w -a –action=1 -b {}’,
# [0], [1,10], qr/^object=.*, virus="(.*?)",/m ],

# Experimental, based on posting from Rado Dibarbora (Dibo) on 2002-05-31
# [‘ESET Software NOD32 Client/Server (NOD32SS)’,
# \&ask_daemon2, # greets with 200, persistent, terminate with QUIT
# ["SCAN {}/*\r\n", ‘127.0.0.1:8448’ ],
# qr/^200 File OK/m, qr/^201 /m, qr/^201 (.+)/m ],

### http://www.norman.com/products_nvc.shtml
# [‘Norman Virus Control v5 / Linux’, ‘nvcc’,
# ‘-c -l:0 -s -u -temp:$TEMPBASE {}’, [0,10,11], [1,2,14],
# qr/(?i).* virus in .* -> \'(.+)\’/m ],

### http://www.pandasoftware.com/
# [‘Panda CommandLineSecure 9 for Linux’,
# [‘/opt/pavcl/usr/bin/pavcl’,’pavcl’],
# ‘-auto -aex -heu -cmp -nbr -nor -nos -eng -nob {}’,
# qr/Number of files infected[ .]*: 0+(?!\d)/m,
# qr/Number of files infected[ .]*: 0*[1-9]/m,
# qr/Found virus :\s*(\S+)/m ],
# NOTE: for efficiency, start the Panda in resident mode with ‘pavcl -tsr’
# before starting amavisd – the bases are then loaded only once at startup.
# To reload bases in a signature update script:
# /opt/pavcl/usr/bin/pavcl -tsr -ulr; /opt/pavcl/usr/bin/pavcl -tsr
# Please review other options of pavcl, for example:
# -nomalw, -nojoke, -nodial, -nohackt, -nospyw, -nocookies

# ### http://www.pandasoftware.com/
# [‘Panda Antivirus for Linux’, [‘pavcl’],
# ‘-TSR -aut -aex -heu -cmp -nbr -nor -nso -eng {}’,
# [0], [0x10, 0x30, 0x50, 0x70, 0x90, 0xB0, 0xD0, 0xF0],
# qr/Found virus :\s*(\S+)/m ],

# GeCAD AV technology is acquired by Microsoft; RAV has been discontinued.
# Check your RAV license terms before fiddling with the following two lines!
# [‘GeCAD RAV AntiVirus 8’, ‘ravav’,
# ‘–all –archive –mail {}’, [1], [2,3,4,5], qr/Infected: (.+)/m ],
# # NOTE: the command line switches changed with scan engine 8.5 !
# # (btw, assigning stdin to /dev/null causes RAV to fail)

### http://www.nai.com/
# [‘NAI McAfee AntiVirus (uvscan)’, ‘uvscan’,
# ‘–secure -rv –mime –summary –noboot – {}’, [0], [13],
# qr/(?x) Found (?:
# \ the\ (.+)\ (?:virus|trojan) |
# \ (?:virus|trojan)\ or\ variant\ ([^ ]+) |
# :\ (.+)\ NOT\ a\ virus)/m,
# sub {$ENV{LD_PRELOAD}=’/lib/libc.so.6′},
# sub {delete $ENV{LD_PRELOAD}},
# ],
# NOTE1: with RH9: force the dynamic linker to look at /lib/libc.so.6 before
# anything else by setting environment variable LD_PRELOAD=/lib/libc.so.6
# and then clear it when finished to avoid confusing anything else.
# NOTE2: to treat encrypted files as viruses replace the [13] with:
# qr/^\s{5,}(Found|is password-protected|.*(virus|trojan))/

### http://www.virusbuster.hu/en/
# [‘VirusBuster’, [‘vbuster’, ‘vbengcl’],
# "{} -ss -i ‘*’ -log=$MYHOME/vbuster.log", [0], [1],
# qr/: ‘(.*)’ – Virus/m ],
# VirusBuster Ltd. does not support the daemon version for the workstation
# engine (vbuster-eng-1.12-linux-i386-libc6.tgz) any longer. The names of
# binaries, some parameters AND return codes have changed (from 3 to 1).
# See also the new Vexira entry ‘vascan’ which is possibly related.

# ### http://www.virusbuster.hu/en/
# [‘VirusBuster (Client + Daemon)’, ‘vbengd’,
# ‘-f -log scandir {}’, [0], [3],
# qr/Virus found = (.*);/m ],
# # HINT: for an infected file it always returns 3,
# # although the man-page tells a different story

### http://www.cyber.com/
# [‘CyberSoft VFind’, ‘vfind’,
# ‘–vexit {}/*’, [0], [23], qr/##==>>>> VIRUS ID: CVDL (.+)/m,
# sub {$ENV{VSTK_HOME}=’/usr/lib/vstk’},
# ],

### http://www.avast.com/
# [‘avast! Antivirus’, [‘/usr/bin/avastcmd’,’avastcmd’],
# ‘-a -i -n -t=A {}’, [0], [1], qr/\binfected by:\s+([^ \t\n\[\]]+)/m ],

### http://www.ikarus-software.com/
# [‘Ikarus AntiVirus for Linux’, ‘ikarus’,
# ‘{}’, [0], [40], qr/Signature (.+) found/m ],

### http://www.bitdefender.com/
# [‘BitDefender’, ‘bdscan’, # new version
# ‘–action=ignore –no-list {}’, qr/^Infected files\s*:\s*0+(?!\d)/m,
# qr/^(?:Infected files|Identified viruses|Suspect files)\s*:\s*0*[1-9]/m,
# qr/(?:suspected|infected)\s*:\s*(.*)(?:\033|$)/m ],

### http://www.bitdefender.com/
# [‘BitDefender’, ‘bdc’, # old version
# ‘–arc –mail {}’, qr/^Infected files *:0+(?!\d)/m,
# qr/^(?:Infected files|Identified viruses|Suspect files) *:0*[1-9]/m,
# qr/(?:suspected|infected): (.*)(?:\033|$)/m ],
# consider also: –all –nowarn –alev=15 –flev=15. The –all argument may
# not apply to your version of bdc, check documentation and see ‘bdc –help’

### ArcaVir for Linux and Unix http://www.arcabit.pl/
# [‘ArcaVir for Linux’, [‘arcacmd’,’arcacmd.static’],
# ‘-v 1 -summary 0 -s {}’, [0], [1,2],
# qr/(?:VIR|WIR):[ \t]*(.+)/m ],

# ### a generic SMTP-client interface to a SMTP-based virus scanner
# [‘av_smtp’, \&ask_av_smtp,
# [‘{}’, ‘smtp:[127.0.0.1]:5525’, ‘dummy@localhost’],
# qr/^2/, qr/^5/, qr/^\s*(.*?)\s*$/m ],

# [‘File::Scan’, sub {Amavis::AV::ask_av(sub{
# use File::Scan; my($fn)=@_;
# my($f)=File::Scan->new(max_txt_size=>0, max_bin_size=>0);
# my($vname) = $f->scan($fn);
# $f->error ? (2,"Error: ".$f->error)
# : ($vname ne ”) ? (1,"$vname FOUND") : (0,"Clean")}, @_) },
# ["{}/*"], [0], [1], qr/^(.*) FOUND$/m ],

# ### fully-fledged checker for JPEG marker segments of invalid length
# [‘check-jpeg’,
# sub { use JpegTester (); Amavis::AV::ask_av(\&JpegTester::test_jpeg, @_) },
# ["{}/*"], undef, [1], qr/^(bad jpeg: .*)$/m ],
# # NOTE: place file JpegTester.pm somewhere where Perl can find it,
# # for example in /usr/local/lib/perl5/site_perl

);

@av_scanners_backup = (

### http://www.clamav.net/ – backs up clamd or Mail::ClamAV
[‘ClamAV-clamscan’, ‘clamscan’,
"–stdout –no-summary -r –tempdir=$TEMPBASE {}",
[0], qr/:.*\sFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

### http://www.f-prot.com/ – backs up F-Prot Daemon, V6
# [‘F-PROT Antivirus for UNIX’, [‘fpscan’],
# ‘–report –mount –adware {}’, # consider: –applications -s 4 -u 3 -z 10
# [0,8,64], [1,2,3, 4+1,4+2,4+3, 8+1,8+2,8+3, 12+1,12+2,12+3],
# qr/^\[Found\s+[^\]]*\]\s+<([^ \t(>]*)/m ],

### http://www.f-prot.com/ – backs up F-Prot Daemon (old)
# [‘FRISK F-Prot Antivirus’, [‘f-prot’,’f-prot.sh’],
# ‘-dumb -archive -packed {}’, [0,8], [3,6], # or: [0], [3,6,8],
# qr/(?:Infection:|security risk named) (.+)|\s+contains\s+(.+)$/m ],

### http://www.trendmicro.com/ – backs up Trophie
# [‘Trend Micro FileScanner’, [‘/etc/iscan/vscan’,’vscan’],
# ‘-za -a {}’, [0], qr/Found virus/m, qr/Found virus (.+) in/m ],

### http://www.sald.com/, http://drweb.imshop.de/ – backs up DrWebD
# [‘drweb – DrWeb Antivirus’, # security LHA hole in Dr.Web 4.33 and earlier
# [‘/usr/local/drweb/drweb’, ‘/opt/drweb/drweb’, ‘drweb’],
# ‘-path={} -al -go -ot -cn -upn -ok-‘,
# [0,32], [1,9,33], qr’ infected (?:with|by)(?: virus)? (.*)$’m ],

### http://www.kaspersky.com/
# [‘Kaspersky Antivirus v5.5’,
# [‘/opt/kaspersky/kav4fs/bin/kav4fs-kavscanner’,
# ‘/opt/kav/5.5/kav4unix/bin/kavscanner’,
# ‘/opt/kav/5.5/kav4mailservers/bin/kavscanner’, ‘kavscanner’],
# ‘-i0 -xn -xp -mn -R -ePASBME {}/*’, [0,10,15], [5,20,21,25],
# qr/(?:INFECTED|WARNING|SUSPICION|SUSPICIOUS) (.*)/m,
# sub {chdir(‘/opt/kav/bin’) or die "Can’t chdir to kav: $!"},
# sub {chdir($TEMPBASE) or die "Can’t chdir back to $TEMPBASE $!"},
# ],

# Commented out because the name ‘sweep’ clashes with Debian and FreeBSD
# package/port of an audio editor. Make sure the correct ‘sweep’ is found
# in the path when enabling.
#
# ### http://www.sophos.com/ – backs up Sophie or SAVI-Perl
# [‘Sophos Anti Virus (sweep)’, ‘sweep’,
# ‘-nb -f -all -rec -ss -sc -archive -cab -mime -oe -tnef ‘.
# ‘–no-reset-atime {}’,
# [0,2], qr/Virus .*? found/m,
# qr/^>>> Virus(?: fragment)? ‘?(.*?)’? found/m,
# ],
# # other options to consider: -idedir=/usr/local/sav

# Always succeeds and considers mail clean.
# Potentially useful when all other scanners fail and it is desirable
# to let mail continue to flow with no virus checking (when uncommented).
# [‘always-clean’, sub {0}],

);

1; # insure a defined return value

Install SSL certificate on postfix and dovecot

Make key file

#openssl genrsa -des3 -out example.com.key 2048
Generating RSA private key, 1024 bit long modulus
…………..++++++
..++++++
e is 65537 (0x10001)
Enter pass phrase for example.com.key:
Verifying – Enter pass phrase for example.com.key:
# openssl req -new -key example.com.key -out example.com.csr
Enter pass phrase for example.com.key:
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:
A challenge password []:
An optional company name []:

Get CRT (GeoTrust, verisign etc)

Remove pass phrase

#openssl rsa -in example.com.key -out example.com.pem

edit /etc/postfix/main.cf

smtpd_use_tls = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_key_file = /etc/pki/tls/certs/example.com.pem
smtpd_tls_cert_file = /etc/pki/tls/certs/example.com.crt

edit /etc/dovecot.conf

ssl_disable = no
ssl_cert_file = /etc/pki/tls/certs/example.com.crt
ssl_key_file = /etc/pki/tls/certs/example.com.pem

restart postfix and dovecot

Install Postgrey on CentOS

Activate dag repository

[dag]
name=Dag RPM Repository for Red Hat Enterprise Linux
baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag
gpgcheck=1

install package

root@ns99 ~ # yum install postgrey

edit startup script /etc/init.d/postgrey

#OPTIONS=”–unix=$SOCKET”
OPTIONS=”–whitelist-clients=/etc/postfix/postgrey_whitelist_clients –whitelist
   recipients=/etc/postfix/postgrey_whitelist_recipients –inet=10023 -d –unix=$SOCKET”

startup postgrey when system is bootup

 root@ns99 ~ # chkconfig postgrey on

install filter to postfix /etc/postfix/main.cf

smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023

edit white-list as you need /etc/postfix/postgrey_whitelist_clients

Check delay from maillog

cat /var/log/maillog | postgreyreport 

Install SPF to CentOS Postfix

In computingSender Policy Framework (SPF) allows software to identify messages that are or are not authorized to use the domain name in the SMTP HELO and MAIL FROM (Return-Path) commands, based on information published in a sender policy of the domain owner. Forged return paths are common in e-mail spam and result inbackscatter. SPF is defined in RFC 4408. from wikipedia

Install require packages

root@ns99 ~ # yum install perl-Mail-SPF

Get SPF module from http://www.openspf.org/Software Newest at this time is 2.007 and Install SPF module

root@ns99 ~ # wget http://www.openspf.org/blobs/postfix-policyd-spf-perl-2.007.tar.gz root@ns99 ~ # tar zxvf postfix-policyd-spf-perl-2.007.tar.gz root@ns99 ~ # mv postfix-policyd-spf-perl-2.007/postfix-policyd-spf-perl /usr/local/lib.

add following line to /etc/postfix/master.cf

policy  unix  –       n       n       –       0       spawn
  user=nobody argv=/usr/bin/perl /usr/local/lib/policyd-spf-perl

add following line to /etc/postfix/main.cf

smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, check_policy_service,
check_policy_service unix:private/policy
policy_time_limit = 3600

Add SPF record to your DNS. SPF record can be wizardly made from  http://old.openspf.org/wizard.html?mydomain=example.com&submit=Go%21

spf01   IN TXT “v=spf1 +ip4:xxx.xxx.xxx.xxx/24 ~all”
spf02   IN TXT “v=spf1 +ip4:yyy.yyy.yyy.yyy/24  ~all”
@       IN TXT “v=spf1 include:spf01.example.com include:spf02.example.com ~all”