Установка Postfix+spamassassin+drweb на FreeBSD


Оригинал: http://alpha.sytes.net/~holdman/postfix_imap.html

В данной статье будет рассмотрена установка почтового сервера на
FreeBSD с поддержкой виртуальных доменов в связке postfix +
courier-imap + mysql с возможностью фильтрации и доставки почты через
maildrop и защитой от спама и вирусов с помощью spamassasin и dr.web.

Для начала создадим базу mysql, откуда postfix будет брать данные.
Создаем файл postfix.sql

USE mysql;
INSERT INTO user (Host, User, Password) VALUES ('localhost','postfix',password('postfix'));
INSERT INTO db (Host, Db, User, Select_priv) VALUES ('localhost','postfix','postfix','Y');
CREATE DATABASE postfix;
USE postfix;

# Транспортная таблица, подробнее о формате - man transport.
CREATE TABLE transport (
# Имя домена
domain varchar(128) NOT NULL default '',
# Используемый транспорт. Например "local:" - для локальной доставки,
# "maildrop:" - для виртуальных доменов с фильтрацией почты, "virtual:" - для
# виртуальных доменов без фильтрации.
destination varchar(128) NOT NULL default '',
UNIQUE KEY domain (domain)
) TYPE=MyISAM

CREATE TABLE alias (
address varchar(255) NOT NULL default '',
goto text NOT NULL,
domain varchar(255) NOT NULL default '',
create_date datetime NOT NULL default '0000-00-00 00:00:00',
change_date datetime NOT NULL default '0000-00-00 00:00:00',
active tinyint(4) NOT NULL default '1',
PRIMARY KEY (address)
) TYPE=MyISAM

CREATE TABLE domain (
domain varchar(255) NOT NULL default '',
description varchar(255) NOT NULL default '',
create_date datetime NOT NULL default '0000-00-00 00:00:00',
change_date datetime NOT NULL default '0000-00-00 00:00:00',
active tinyint(4) NOT NULL default '1',
PRIMARY KEY (domain)
) TYPE=MyISAM

CREATE TABLE mailbox (
# Адрес пользователя в формате "user@domain"
username varchar(255) NOT NULL default '',
# Пароль в plaintext для возможности использования courier'ом cram-md5 шифрования
password varchar(255) NOT NULL default '',
# Общая информация о пользователе.
name varchar(255) NOT NULL default '',
# Название почтового ящика в формате "user@domain/"
maildir varchar(255) NOT NULL default '',
create_date datetime NOT NULL default '0000-00-00 00:00:00',
change_date datetime NOT NULL default '0000-00-00 00:00:00',
# Квота. Может быть формата "<число>S" или "<числоC>" или "<число>S,<число>C",где S означает
# общий размер ящика, а C - кол-во писем (например "500000S" или "500000S,20000C")
quota tinytext NOT NULL default '',
# Поле активности, используется для разрешения или отказа в доступе к сервисам smtp и pop/imap
active tinyint(4) NOT NULL default '1',
PRIMARY KEY (username)
) TYPE=MyISAM

INSERT INTO transport (domain, destination) VALUES ('test.local.net', 'maildrop:');
INSERT INTO domain (domain,description) VALUES ('test.local.net','Test Domain');
INSERT INTO alias (address,goto) VALUES ('alias@test.local.net', 'user@test.local.net');
INSERT INTO mailbox (username,password,name,maildir,quota) VALUES ('user@test.local.net', 'test', 'Test user', 'test@test.local.net/', '500000S');


Перезагрузите mysql

mysqladmin reload


Установка postfix

cd /usr/ports/security/cyrus-sasl2
make WITH_MYSQL_VER=3 WITHOUT_OTP=yes WITHOUT_NTML=yes install clean


опция WITH_MYSQL_VER зависит от установленной версии mysql (в моем
случае 3.23.57)

cd /usr/ports/mail/postfix && make install clean


При установке в меню выбираем поддержку SASL2, TLS и MYSQL.

После установки

newaliases
cp /usr/local/etc/postfix/main.cf.default /usr/local/etc/postfix/main.cf
chmod 750 /usr/local/etc/postfix
chgrp postfix /usr/local/etc/postfix


Открываем main.cf и вносим туда следущие значения

disable_vrfy_command = yes
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = mysql:/usr/local/etc/postfix/mysql_sasl.cf
smtp_sasl_security_options = noanonymous, noplaintext, noactive, nodictionary
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks,
reject_invalid_hostname,
reject_unknown_hostname,
reject_non_fqdn_hostname
smtpd_recipient_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unknown_recipient_domain,
reject_non_fqdn_recipient,
reject_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sender_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unknown_sender_domain,
reject_rhsbl_sender dsn.rfc-ignorant.org
transport_maps = mysql:/usr/local/etc/postfix/mysql_transport.cf
virtual_alias_maps = mysql:/usr/local/etc/postfix/mysql_virtual_alias_maps.cf
virtual_gid_maps = static:1005
virtual_mailbox_base = /var/spool/virtual
virtual_mailbox_domains = mysql:/usr/local/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/usr/local/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_mailbox_limit = 51200000
virtual_minimum_uid = 1001
virtual_uid_maps = static:1005


Обратите внимание что virtual uid и gid имеют статическую привязку и
эти значения следует изменить на uid и gid юзера от которого будеть
работать maildrop.

В моем случае это юзер vmail с uid и gid 1005.

Транспорт virtual не поддерживает квоты, в отличии от maildrop,
поэтому если вы хотите включить поддержку квот для virtual, установите
патч http://www.oav.net/vda/

Создаем нужные конфигурационные файлы и директории.

pw useradd vmail -d /var/spool/virtual -s /sbin/nologin
mkdir -m 700 /var/spool/virtual
chown vmail:vmail /var/spool/virtual


mysql_transport.cf

user = postfix
password = postfix
hosts = localhost
dbname = postfix
table = transport
select_field = destination
where_field = domain


mysql_virtual_alias_maps.cf

user = postfix
password = postfix
hosts = localhost
dbname = postfix
table = alias
select_field = goto
where_field = address


mysql_virtual_domains_maps.cf

user = postfix
password = postfix
hosts = localhost
dbname = postfix
table = domain
select_field = description
where_field = domain


mysql_virtual_mailbox_maps.cf

user = postfix
password = postfix
hosts = localhost
dbname = postfix
table = mailbox
select_field = maildir
where_field = username
additional_conditions = and active = '1'


mysql_sasl.cf

user = postfix
password = postfix
hosts = localhost
dbname = postfix
table = mailbox
select_field = password
where_field = username
additional_conditions = and active = '1'


Создаем файл /usr/local/lib/sasl2/smtpd.conf

pwcheck_method: auxprop
auxprop_plugin: mysql
mysql_user: postfix
mysql_passwd: postfix
mysql_hostnames: localhost
mysql_database: postfix
mysql_statement: select password from mailbox where username='%u@%r'


Далее

chmod 750 /usr/local/lib/sasl2
chgrp mail /usr/local/lib/sasl2


Веб-интерфейс для администрирования виртуальных доменов (можно взять
как образец) http://high5.net/postfixadmin/


Установка maildrop

maildrop является альтернативой широко используемому procmail и имеет
гораздо большие возможности - поддержка mysql и ldap, поддержка квот,
более мощный язык фильтрации, повышенная безопасность, поддержка
формата Maildir++.

Более подробная документации в директории /usr/local/share/doc/maildrop

cd /usr/ports/mail/maidrop


Открываем Makefile и меняем

CONFIGURE_ARGS+= --enable-syslog=1
--enable-use-flock
--with-etcdir="${PREFIX}/etc"
--enable-maildrop-uid="${MAILDROP_SUID}"
--enable-maildrop-gid="${MAILDROP_SGID}"


на

CONFIGURE_ARGS+= --enable-syslog=1
--enable-use-flock
--with-etcdir="${PREFIX}/etc"
--enable-maildrop-uid="${MAILDROP_SUID}"
--enable-maildrop-gid="${MAILDROP_SGID}"
--with-trashquota
--enable-maildropmysql
--with-mysqlconfig="${PREFIX}/etc/maildrop.config"


Далее

make WITH_MAILDIRQUOTA=yes install clean


После сборки запустите maildrop -v. Должны быть следующие строки
Maildir quota extension enabled.
Virtual user database via MySQL extension enabled.

В /usr/local/etc/postfix/master.cf измените конфиг maildrop на

maildrop unix - n n - - pipe
flags=Rhu user=vmail argv=/usr/local/bin/maildrop -w 90 -d ${recipient}


Создаем файл /usr/local/etc/maildrop.config со следующим содержанием

hostname localhost
port 3306
database postfix
dbuser postfix
dbpw postfix
dbtable mailbox
default_uidnumber 1005
default_gidnumber 1005
uid_field username
uidnumber_field 1005 # vmail
gidnumber_field 1005 # vmail
maildir_field maildir
homedirectory_field '/var/spool/virtual'
quota_field quota
mailstatus_field active
where_clause "where active = '1'"


Создаем файл /var/spool/virtual/.mailfilter со следующим содержанием

UMASK=077
LOGNAME=tolower($LOGNAME)
include "$HOME/.mailfilters/$LOGNAME"


Ставим права на запись и чтение только пользователю иначе maildrop
откажется работать.

chmod 600 /var/spool/virtual/.mailfilter
chown vmail:vmail /var/spool/virtual/.mailfilter


Создаем директорию /var/spool/virtual.mailfilters

mkdir -m 700 /var/spool/virtual/.mailfilters
chown vmail:vmail /var/spool/virtual/.mailfilters


Создаем include файл в формате user@domain соотвествующему переменной
$LOGNAME /var/spool/virtual/.mailfilters/user@test.local.net со
следующим содержанием

if ("/^X-Spam-Flag:.YES/")
{
to "$HOME/$LOGNAME/.Spam"
}
to "$HOME/$LOGNAME"


NB! В отличии от virtual maildrop сам не создает maildir, поэтому
следует создать нужный вам maildir и subfolders используя утилиту
maildirmake

su -fm vmail -c 'maildirmake /var/spool/virtual/user@test.local.net'
su -fm vmail -c 'maildirmake -f Spam /var/spool/virtual/user@test.local.net'


Файл .mailfilter - это файл дает возможность maildrop выбрать нужный
конфиг для пользователя, используя его логин, который берется из
переменной $LOGNAME (user@domain).

В директории .mailfilters хранятся конфиги для каждого виртуального
юзера.

Maildrop будет искать конфиг в формате user@domain и использовать его.
Можно написать скрипт, который при создании maildir, автоматически
создает нужный конфиг с дефолтными опциями в .mailfilters.

В данном примере maildrop отбирает почту с заголовком X-Spam-Flag:
YES, который генерирует spamassassin, установка которого будет
рассмотрена ниже, и кладет ее в папку Spam. Остальная почта
направляется в INBOX.

Примеры фильтров для maildrop можно найти на
http://sourceforge.net/projects/mdropspammailfilter

Создаем файл /usr/local/etc/quotawarnmsg

From: Mail Delivery System <Mailer-Daemon@test.local.net.>
Reply-To: root
To: Dear User
Subject: Mail quota warning
Mime-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 7bit

Your mailbox on the server is now more than 90% full. So that you can continue
to receive mail you need to remove some messages from your mailbox.


Данное письмо будет направляться пользователю, если обьем его
почтового ящика превысил 90%. Процент можно выставлять через опцию
maildrop -w % в postfix master.cf.


Установка Courier-imap

cd /usr/ports/mail/courier-imap && make WITH_CRAM=yes WITH_MYSQL=yes install clean

chmod 700 /usr/local/etc/courier
chmod 750 /usr/local/var/authdaemon
chgrp vmail /usr/local/var/authdaemon


Правим /usr/local/etc/courier/authmysqlrc

Для доступа к спулу почты /var/spool/virtual courier работает от юзера
vmail (uid 1005,gid 1005)

#DEFAULT_DOMAIN domain.tld
MYSQL_CLEAR_PWFIELD password
MYSQL_DATABASE postfix
MYSQL_GID_FIELD '1005'
MYSQL_HOME_FIELD '/var/spool/virtual'
MYSQL_LOGIN_FIELD username
MYSQL_MAILDIR_FIELD maildir
MYSQL_NAME_FIELD name
MYSQL_OPT 0
MYSQL_PASSWORD postfix
MYSQL_PORT 3306
MYSQL_QUOTA_FIELD quota
MYSQL_SERVER localhost
MYSQL_UID_FIELD '1005'
MYSQL_USERNAME postfix
MYSQL_USER_TABLE mailbox
MYSQL_WHERE_CLAUSE active='1'


Убедитесь что использована табуляция а не пробелы, иначе конфиг не
будет работать.

Создаем SSL сертификат

mkimapdcert


В imapd.conf меняем

TCPDOPTS="-nodnslookup -noidentlookup"


на

TCPDOPTS="-nodnslookup -noidentlookup -user=vmail"

IMAP_CAPABILITY_ORIG="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT
THREAD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 IDLE"


Установка SpamAssassin

cd /usr/ports/mail/p5-Mail-SpamAssassin && make install clean


В данном примере настройки пользователей будут хранится в базе mysql

Открываем /usr/local/share/doc/p5-Mail-SpamAssassin/spamassassin.sql и
добавляем в начало

CREATE DATABASE spamassassin;
USE spamassassin;


Далее выполняем

mysql < /usr/local/share/doc/p5-Mail-SpamAssassin/spamassassin.sql


Будет создана база spamassassin, где хранятся настройки пользователей.

Назначаем права на доступ к базе для юзера spamd

mysql
mysql> GRANT SELECT INSERT DELETE UPDATE ON spamassassin.* TO spamd@localhost I
DENTIFIED BY 'spamd';


Создаем юзера spamd от которого будет работать SA.

pw useradd spamd -d /var/spool/spamd -s /sbin/nologin


Создаем домашнюю директорию для Razor DCC и Pyzor.

mkdir -m 750 /var/spool/spamd
chown spamd /var/spool/spamd


Создаем файл /usr/local/etc/mail/spamassassin/local.cf

rewrite_subject 1
report_safe 0
use_terse_report 0
use_bayes on
auto_learn 1
skip_rbl_checks 0
use_razor2 1
use_DCC 1
use_pyzor 0
dcc_add_header 1
dns_available yes

# Секция для mysql
user_scores_dsn DBI:mysql:spamassassin:localhost
user_scores_sql_username spamd
user_scores_sql_password spamd
user_scores_sql_table userpref


В скрипте для запуска SA /usr/local/etc/rc.d/spamd.sh

case "$1" in

start)
[ -x ${PREFIX}/bin/spamd ] && ${PREFIX}/bin/spamd -u spamd
-r /var/run/spamd -H /var/spool/spamd -x -a -Q -L -m 16 -d && echo -n ' spamd'


Веб-интерфейс для SA можно скачать отсюда:
http://spamassassin.org/devel/php-sa-mysql-0.5.tar.gz (PHP)
http://spamassassin.org/devel/sa-user-admin-0.1.tar.gz (CGI)


Установка Drweb

cd /usr/ports/security/drweb-postfix


При установке порта в distinfo была указана версия
drweb-clients-4.29.12-D-sources.tar.gz, которой уже не было на
фтп-сервере drweb.

Поэтому я скачал последнюю на данный момент версию
drweb-clients-4.29.12-F-sources.tar.gz с ftp://ftp.drweb.ru/pub/unix

В Makefile изменил

DISTNAME= drweb-clients-4.29.12-D-sources


на

DISTNAME= drweb-clients-4.29.12-F-sources


Далее

md5 /usr/ports/distfiles/drweb-clients-4.29.12-F-sources.tar.gz | sed 's//usr
/ports/distfiles///' > distinfo

make install clean


После установки отредактируйте файлы
/usr/local/etc/drweb/drweb_postfix.conf и /usr/local/drweb/drweb32.ini.
В моем случае drwebd работал через unix сокет.

В /usr/local/etc/postfix/master.cf меняем

smtp inet n - n - 20 smtpd


на

smtp inet n - n - 20 smtpd -o content_filter=spam


Создаем транспорт spam

spam unix - n n - 5 pipe
flags=Rq user=drweb argv=/usr/local/bin/spamc -u mailnull
-e /usr/local/sbin/drweb-postfix
--conf=/usr/local/etc/drweb/drweb_postfix.conf -f ${sender} -- ${recipient}


В данном примере spamc запускается от sendmail'овского mailnull
(который без толку висел в /etc/passwd :) )

Принцип работы данной конструкции: почта направляется к spamd клиентом
SA spamc...проверяется на спам, далее направляется к drwebd клиентом
drweb_postfix и проверяется на наличие вирусов.

Запускаем сервисы

postfix start
/usr/local/etc/rc.d/drweb-0.sh start
/usr/local/etc/rc.d/spamd.sh start
/usr/local/etc/rc.d/courier-imap-imapd.sh start


Вывод sockstat -l

root master 30043 11 tcp4 *:25 *:*
vmail couriertcp 25437 6 tcp4 *:143 *:*
spamd perl 23513 5 tcp4 127.0.0.1:783 *:*
drweb drwebd 266 3 stream /usr/local/drweb/run/drwebd.sock


Отправляем тестовое письмо юзеру user@test.local.net

echo 'X-Spam-Flag: YES' | mail user@test.local.net


и смотрим в /var/log/maillog

postfix/smtpd[30072]: connect from test1.local.net[192.168.0.2]
postfix/smtpd[30072]: DDAFDA3: client=test1.local.net[192.168.0.2]
postfix/cleanup[30073]: DDAFDA3: message-id=<20030811104104.30F2D115@test1.local.net.>
postfix/qmgr[30071]: DDAFDA3: from=<user@test1.local.net.>, size=466, nrcpt=1 (queue active)
postfix/smtpd[30072]: disconnect from test1.local.net[192.168.0.2]
server spamd[23513]: connection from localhost [127.0.0.1] at port 56559
server spamd[30081]: processing message <20030811104104.30F2D115@test1.local.net.> for mailnull:1017.
server spamd[30081]: clean message (0.1/5.0) for mailnull:1017 in 5.1 seconds,485 bytes.
server drweb-postfix: dwlib: scan[30080]: message(/tmp/drweb.tmp.3qN7Z2) sent by user@test1.local.net is passed
server postfix/pickup[30070]: D685C7AF: uid=426 from=<user@test1.local.net.>
server postfix/cleanup[30073]: D685C7AF: message-id=<20030811104104.30F2D115@test.local.net.>
server postfix/pipe[30079]: DDAFDA3: to=<user@test.local.net.>, relay=spam, delay=13, status=sent (test.local.net)
server postfix/qmgr[30071]: D685C7AF: from=<user1@test1.local.net.>, size=734, n
rcpt=1 (queue active)
server postfix/virtual[30088]: D685C7AF: to=<user@test.local.net.>, relay=maildrop, delay=1, status=sent (maildir)


Пробуем забрать почту с ящика с помощью fetchmail или утилиты imtest,
которая входит в порт /usr/ports/mail/cyrus-imap.

imtest -m cram-md5 -a user@test.local.net -w test localhost

S: * OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT
THREAD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 IDLE XCOURIEROUTBOX=I
NBOX.Outbox] Courier-IMAP ready.
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THRE
AD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 IDLE XCOURIEROUTBOX=INBOX.Outbox
S: C01 OK CAPABILITY completed
C: A01 AUTHENTICATE CRAM-MD5
S: + PDlBNjY2N0E2MzAyRTcyQzE4ODU0NjE3MkNBQUQ5Q0FDQHVuaXgubG9jYWwubmV0Pg==
C: dXNlckB0ZXN0Mi5sb2NhbC5vcmcgYzcwNTdjNWJlNWQ5MzllYTU0ZDg3NTJmZTdjMGI5ZjA=
S: A01 OK LOGIN Ok.
Authenticated.
Security strength factor: 0
C: A1 LIST "" *
LIST (HasNoChildren) "." "INBOX.Spam"
LIST (Unmarked HasChildren) "." "INBOX"
S: A1 OK LIST completed.
C: A2 STATUS INBOX.Spam (MESSAGES)
STATUS "INBOX.Spam" (MESSAGES 1)
S: A2 OK STATUS Completed.
C: A3 FETCH 1 FULL


Проверяем smtp auth:

printf 'testtesttest' | mmencode (формат -
"usernameusernamepassword")
dGVzdAB0ZXN0AHRlc3Q= (запомните этот пароль или скопируйте в буфер)


Соединяемся с удаленного хоста (не с localhost :)).

telnet test.local.net 25
Trying 127.0.0.1...
Connected to test.local.net.
Escape character is '^]'.
220 test.local.net ESMTP Postfix
EHLO test
250-test.local.net
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-STARTTLS
250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5
250-AUTH=LOGIN PLAIN DIGEST-MD5 CRAM-MD5
250-XVERP
250 8BITMIME
MAIL FROM:
250 Ok
RCPT TO:
554 : Relay access denied
QUIT


Повторяем попытку

telnet test.local.net 25
Trying 127.0.0.1...
Connected to test.local.net.
Escape character is '^]'.
220 test.local.net ESMTP Postfix
EHLO test
250-test.local.net
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-STARTTLS
250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5
250-AUTH=LOGIN PLAIN DIGEST-MD5 CRAM-MD5


Вводим:

AUTH PLAIN dGVzdAB0ZXN0AHRlc3Q=
235 Authentication successful
MAIL FROM:
250 Ok
RCPT TO:
250 Ok
DATA

Обновлено: 13.03.2015