Настройка Exim. Создание почтового сервера.

Создание почтового сервера на базе MTA Exim (exim mail mta virtual spam virus clamav freebsd imap postgresql)

В этой статье пойдет речь о создании эффективного почтового сервера на базе MTA exim. Первый вопрос, который, конечно же приходит в голову - "А почему именно exim?". Отвечают на этот вопрос по-разному, поэтому я скажу, что меня так привлекает в exim-е:
- логичная схема обработки почты;
- высокая скорость работы;
- удобный формат конфигурационного файла;
- широчайшие возможности по поиску каких-либо значений в файлах, СУБД, LDAP
- встроенная поддержка smtp-аутентификации
- небольшое число найденных уязвимостей (фактически я знаю только об одной, найденной недавно, она касалась версий exim-a до 4.20 включительно)
- очень большое количество возможностей, а также чрезвычайная гибкость
- возможность полной замены sendmail(т.е. можно сделать ln -sf /usr/local/sbin/exim /usr/libexec/sendmail :-))

На мой взгляд, exim является весьма и весьма удачным продуктом, не зря он используется по умолчанию в ОС Debian GNU Linux. Два больших минуса exim-a состоят в том, что отсутствует качественная документация на русском языке необходимость правки Makefile для включения тех или иных возможностей exim-а.

Итак, для начала подумаем, что должна содержать "идеальная" с точки зрения удобства администрирования и использования почтовая система. Сформулируем ряд требований к почтовой системе:

1) простота управления пользователями
2) возможность предоставления доступа для отправки почты пользователям локальной сети и мобильным пользователям (при помощи smtp аутентификации)
3) максимальная защита от хакерских атак, вирусов и спама
Базовой системой для установки MTA явилась FreeBSD 5.2.1, что обусловило определенные особенности установки.

Перечислю весь набор программного обеспечения для организации mail сервера:
- exim-4.34 - MTA (mail transfer agent - агент передачи почты)
- courier-3.0.4 - imap сервер, для доступа к почте пользователей, не имеющих локальных пользовательских учетных записей (виртуальные пользователи)
- clamav - для поиска вирусов
- spamassasin - для поиска спамерских писем
- postgresql-7.4.2 - для хранения всех данных о пользователях почтовой системы
- squirrelmail - просто приятный веб-интерфейс для почты (требует веб-сервер и php)

Конечно, можно собрать все вышеперечисленные компоненты и вручную, но я не поклонник такого подхода. Во-первых надо очень четко представлять порядок сборки различных компонентов. Во-вторых, необходимо разбираться в куче опций для связки различных библиотек. В-третьих, надо четко представлять себе все пути и знать, каких пользователей надо добавлять. Ну и в-четвертых, это дело очень сложно обновлять. Потому мы воспользуемся услугами системы портов (если у вас, например, Debian GNU Linux, то нужный пакет называется exim4-daemon-heavy). Для этого ставим следующие порты:

- databases/pogstgresql7
- mail/exim (при компиляции необходимо указать следующие опции: make WITH_PGSQL=yo
- mail/p5-Mail-SpamAssassin
- security/clamav
- mail/courier-imap (при компиляции опять же указываем: make WITH_CRAM=yo WITH_POSTGRESQL=yo
- mail/squirrelmail

После сборки всего нужного переходим к стадии настройки. Тут придется затратить порядочное количество времени на настройку всех компонентов почтовой системы, и целью этой статьи является минимизация этого времени :) Итак, начнем с настройки СУБД postgresql, как основы для построения почтовой системы.

Во-первых postgresql работает с правами системного пользователя pgsql (обратите внимание, этот пользователь имеет реальный shell и домашний каталог - /usr/local/pgsql/). Поэтому для начала задаем пароль для данного пользователя:

# passwd pgsql

Далее делаем su pgsql и начинаем создание базы данных:

# su pgsql
% psql

вводим пароль пользователя pgsql и попадаем в командную строку sql запросов. Для подробного ознакомления с возможностями СУБД, советую обратиться к руководству или же одной из книг.

создаем БД:

CREATE DATABASE users;

присоединяемся к данной БД:

\c users


создаем таблицу пользовательских аккаунтов, а также constraint'ы для нее:

CREATE TABLE accounts (
uid serial NOT NULL,
login character varying(128),
"password" character varying(128),
maildir character varying(255),
gecos character varying(255),
gid integer DEFAULT 150,
home character varying(255),
mailquota integer DEFAULT 20
);
ALTER TABLE ONLY accounts
ADD CONSTRAINT uid_k PRIMARY KEY (uid);
ALTER TABLE ONLY accounts
ADD CONSTRAINT login_k UNIQUE (login);


создаем таблицу алиасов:

CREATE TABLE aliases (
mail character varying(128) NOT NULL,
alias character varying(128)
);
ALTER TABLE ONLY aliases
ADD CONSTRAINT mail_k PRIMARY KEY (mail);


Поясню назначение таблиц и полей:

Таблица accounts предназначена для хранения данных о виртуальных пользователях почтовой системы, назначение полей:
-uid - уникальный номер пользователя, имеет автоинкрементный тип
-login - строка, содержащая имя пользователя в формате "имя@домен" для возможности доставки почты для пользователей различных доменов
-password - пароль в открытом виде (для возможности безопасной cram-md5 аутентификации)
-maildir - путь к постовому ящику в формате maildir
-gecos - комментарий (для чего-нибудь, да пригодится :) )
-gid - идентификатор группы (не нужен реально, но зачем-то требуется для courier'а)
-home - аналогично gid
-mailquota - число в мегабайтах, указывающее квоту для пользователя

Таблица aliases представляет собой просто замену /etc/aliases, содержит два поля - mail (исходный адрес) и alias (адрес для перенаправления).

После этого будем считать, что postgresql у нас работает. Однако, для полного использования возможностей этой СУБД лучше почитать документацию.

Далее перейдем к настройке собственно MTA exim. Конфигурационный файл для версии "из портов" хранится в /usr/local/etc/exim/configure. Для начала я бы хотел пояснить значение некоторых терминов и рассказать о базовых принципах работы exim'a.

Представим себе путь прохождения любого почтового сообщения. Любое письмо состоит из так называемого "конверта" и собственно данных. То, с чем мы привыкли работать в почтовых клиентах, как раз является "данными" и не имеет к конверту никакого отношения. В конверте описываются 2 параметра: mail from: и rcpt to:, которые указывают отправителя и получателей соответственно.

Сеанс работы с MTA может предваряться "приветствием" - стандартным (HELO) и расширенным (EHLO). В приветствии должно указываться FQDN клиента, хотя, по ряду причин, не стоит слишком строго следить за именно
FQDN, т.к. многие машины могут находиться за NAT'ом. MTA в ответ на HELO или EHLO сообщает о своих возможностях, обеспечивая тем самым синхронизацию клиента и сервера.

Далее exim осуществляет проверку целевых адресов на предмет их допустимости для данного сервера. Этот этап может предваряться аутентификацией и установкой TLS-сессии. Если пользователь прошел какой-либо из этих этапов, ему присваиваются определенные флаги, которые в дальнейшем могут использоваться на этапе проверки конверта.

По умолчанию exim осуществляет проверку недопустимых символов в адресах и позволяет отпарвлять почту только из локальных доменов и только на локальные домены. Кроме того, при успешной аутентификации письмо
проходит и в интернет. Для остальных писем релей (передача писем) запрещена. Все проверки в exim4 осуществляются на основании механизма acl (access control list - список доступа).

Также может осуществляться проверка данных (этот механизм добавляется при установке патча exiscan, который при установке портов уже ставится).
После успешной прохождения этого этапа exim просматривает rewrite правила, для переписывания отдельных частей конверта (может использоваться в целях перенаправления всех писем на какой-либо смарт-хост, например).

Далее письмо попадает на цепочку так называемых "роутеров", которые определяют, как именно доставлять письмо. Среди роутеров фигурирует dnslookup, доставляющий письма на основании MX записей в DNS, проверка файла алиасов и .forward файлов ну и локальная доставка. Каждый роутер имеет некое условие срабатывания и соответствующий транспорт. При выполнении условия, exim выбирает указанный транспорт для доставки письма, иначе письмо проходит на следующий роутер (поэтому важен порядок описания роутеров в конфигурационном файле).

Транспорты же определяют порядок доставки письма. Таким образом, настройка exim'а состоит из нескольких частей:

-настройка глобальных параметров
-настройка acl's
-настройка роутеров
-настройка транспортов
-настройка аутентификаторов
-настройка очереди
-настройка rewrite правил

В настройке exim'а широко используются различные списки (hostlist, domainlist и dnslist) и так называемые lookup'ы, при помощи которых exim извлекает данные из внешних источников.

Многие мои знакомые, пытаясь освоить exim, считали lookup'ы самой запутанной темой, потому я остановлюсь на этом вопросе чуть подробнее. 
Существует два типа поиска: поиск по одному ключу (single-key) и поиск по запросу (query). Первый используется для поиска в локальных файлах, а второй - в различного рода базах (sql, ldap и прочее). Любые lookup'ы могут быть вложенными, то есть в одном поиске используются результаты другого.

Поиск на основе single key строится примерно так:

${lookup{$var_to_search}lsearch{/path/to/file}}


особо следует отметить расставление фигурных скобок. Если вы знакомы с функциональными языками, вроде лиспа, то такой синтаксис для вас будет привычен, иначе просто нужно считать каждую конструкцию списком, который обрабатывает exim. Тогда все строковые и другие константы тоже заключаются в фигурные скобки.
То есть вышеприведенный пример можно рассматривать как
$список -> ${lookupсписок} -> ${lookup {$var_to_search} driver{driver_arguments}}.

При этом сам файл, в котором осуществляется поиск должен выглядеть так:

$var_to_search: значение

Приведу более конкретный пример - построение списка доменов из файла на основании адреса отправителя (пример из документации):

domainlist domains = ${lookup{$sender_host_address}lsearch{/some/file}}

при этом сам файл должен выглядеть следующим образом:

192.168.3.4: domain1 : domain2 : ...
192.168.1.9: domain3 : domain4 : ...

При этом поиск осуществляется по первому полю.

Отличие query-style поиска в том, что мы явно не указываем, что искать, указывая вместо этого запрос. Так, например выглядит типичный запрос к sql базе:

${lookup driver{query}{action_if_query_succeed}{action_if_query_failed}}

Например:

domainlist domains = ${lookup pgsql{select domains from domains where \
sender='$sender_host_address'}{$value}fail}

При успешном выполнении запроса возвращается значение из базы, иначе выполняется специальное действие fail, означающее неудачный запрос.
Несколько пугающими бывают запросы к ldap. Разберу их поподробнее.
уазание сервера и порта ldap выглядит следующим образом:

ldap_default_servers = 127.0.0.1::389

запросы к директории выглядят так:

${lookup ldap{ldap://ldap.test.ru/dc=${domain},ou=mail,o=tehnopark?mail?sub?\             
(&(objectClass=inetOrgPerson)\                                                
(mail=${local_part}@${domain}))}{$value} fail}

Форма запроса описана в стандарте, но, думаю, ее стоит дополнительно пояснить.

В запросе мы указываем адрес ldap сервера (ldap://ldap.test.ru/), basedn для поиска (dc=${domain},ou=mail,o=tehnopark), значение, которое нужно вернуть (mail), описание запроса (также в постфиксной форме, характерной для
функциональных языков:

(&(objectClass=inetOrgPerson)(mail=${local_part}@${domain})))

Когда требуется аутентификация на сервере, тогда просто указываем нечто вроде

${lookup ldap
{user="cn=manager,o=tehnopark of innovation,c=RU" pass=secret
ldap:///o=tehnopark%20of%20innovation,c=RU?sn?sub?(cn=foo)}
{$value}fail}

Заметьте необходимость замены пробелов на %20, как того требует стандарт.

Более подробно обо всем этом можно узнать на http://www.exim.org/exim-html-4.30/doc/html/spec_9.html#CHAP9

Думаю, для дальнейшего понимания статьи, этого вполне достаточно.

Итак, собственно конфигурационный файл exim'a. Кое-где я добавил свои комментарии, чтобы улучшить понимание различных директив.

######################################################################
#                  Runtime configuration file for Exim               #
######################################################################

# Здесь мы определяем макросы, описывающие различные пути

CONFIG_PREFIX=/usr/local/etc/exim
ACL_PREFIX=CONFIG_PREFIX/acls
CERTDIR=CONFIG_PREFIX/certs

# Здесь мы указываем, где находить наш postgresql сервер, соединение
# осуществляется через локальный сокет, команда hide помогает спрятать эту
# настройку при вызове exim -bP, когда exim выводит все конфигурационные опции в
# стандартный вывод. Учтите,
# что сам /usr/local/etc/exim/configure должен иметь владельца root:wheel и
# иметь права доступа 0600, что отличается от того, что принято по умолчанию
# (0644)
hide pgsql_servers = (/tmp/.s.PGSQL.5432)/users/pgsql/pAsSwOrD

# Тут мы описываем списки доменов

# Local_domains включает домены, считающиеся локальными, то есть те домены, для
# которых exim делает локальную доставку, для остальных доменов почта
# доставляется по MX записям в DNS. Обратите внимание на дополнительные файлы
# ACL_PREFIX/localdomains и ACL_PREFIX/hostingdomains, в которых перечислены
# домены, разделенные переводом строки (то есть, по одному домену на каждую
# строку)
domainlist local_domains = unona.test.ru : ACL_PREFIX/localdomains : ACL_PREFIX/hostingdomains
# Дополнительная настройка
domainlist hosting_domains = ACL_PREFIX/hostingdomains
# Список хостов, почту на которые мы явно отвергаем
hostlist host_reject = ACL_PREFIX/hostreject
domainlist relay_to_domains =
# Список адресов, с которых разрешена передача почты во внешний мир
hostlist   relay_from_hosts = localhost : 192.168.1.0/24 : ACL_PREFIX/relayfromhosts

# Проверка получателя
acl_smtp_rcpt = acl_check_rcptъ
# Проверка mime содержимого
acl_smtp_mime = acl_check_mime
# Проверка на спам и вирусы
acl_smtp_data = acl_check_virus

# Здесь мы описываем наш антивирус
av_scanner = clamd:127.0.0.1 3310
# И spamassasin
spamd_address = 127.0.0.1 783
# Настройки пользователя и группы по умолчанию
exim_user = mailnull
exim_group = mail
# Никогда не осуществляем доставку под рутом - root должен быть алиасом на
# другого локального пользователя. Кстати, это _обязательное_ условие, заданное
# еще на этапе компиляции
never_users = root

# Настройки директории для очереди
spool_directory = /var/spool/exim
# Разделяем spool_directory на несколько более маленьких - аналог хеш таблицы,
# ускоряет обработку spool'а
split_spool_directory

# Пытаемся сделать соответствие прямой и обратной зоны dns для каждого хоста.
# Несколько затратно, но весьма полезно
host_lookup = *

# Убираем проверку identd на клиентской стороне. Из-за неправильно настроенных
# firewall'ов это часто вызывает длительные тайм-ауты, кроме того, этот сервис
# поднят не у многих
rfc1413_query_timeout = 0s

# Указываем кое-какие лимиты (их назначение ясно из названия)
smtp_accept_max = 50
smtp_connect_backlog = 40
smtp_accept_max_per_host = 10
smtp_accept_queue = 22
smtp_accept_queue_per_connection = 10
recipients_max = 16
recipients_max_reject = true
message_size_limit = 16M
accept_8bitmime

# Игнорируем сообщения, которые приходят нам же, давность которых более 12-ти часов
ignore_bounce_errors_after = 12h

# Удаляем замороженные сообщения, давность которых больше недели.
timeout_frozen_after = 7d

# Настройки TLS
tls_certificate = CERTDIR/mailed.crt
tls_privatekey = CERTDIR/mailed.key
tls_advertise_hosts = *
tls_verify_certificates = *
# Следующая опция закомментирована, но весьма полезна, позволяя авторизироваться
# только через безопасный ssl канал
#auth_advertise_hosts = ${if eq{$tls_cipher}{}{}{*}}

######################################################################
#                       ACL CONFIGURATION                            #
#         Specifies access control lists for incoming SMTP mail      #
######################################################################

begin acl

# Этот список доступа описывает проверки, осуществляемые при вызове любой RCPT
# команды
acl_check_rcpt:

# Вначале проверяем достоверность отправителя
require verify = sender
# Принимаем соединения от локальных MUA (то есть не через TCP/IP)
accept  hosts = :
#############################################################################
# Проверка соответствия почтового адреса стандарту  
deny    message       = Restricted characters in address
domains       = +local_domains
local_parts   = ^[.] : ^.*[@%!/|]
accept domains = +local_domains
# Здесь прописаны так называемые dnsbl, то есть черные списки MTA с открытым
# релеем, мы проверяем ip адрес отправителя на соответствие таким спискам и
# блокируем письмо, если отправитель был найден в таком списке
deny    message = host is listed in $dnslist_domain
dnslists = blackholes.mail-abuse.org:relays.mail-abuse.org

# Правило на проверку всех почтовых адресов, кроме локальных (менее строгое)
deny    message       = Restricted characters in address
domains       = !+local_domains
local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
#############################################################################

# Принимаем почту для пользователя postmaster локальных доменов, не взирая на
# отправителя
accept  local_parts   = postmaster
domains       = +local_domains

# Deny unless the sender address can be verified.

accept  domains       = +local_domains
endpass
verify        = recipient

# Если домен в списке relay_to_domains, то разрешаем релей
accept  domains       = +relay_to_domains
endpass
verify        = recipient
accept  domains = +hosting_domains
endpass
verify = recipient

accept  hosts         = +relay_from_hosts

# Принимаем любые соединения, которые были успешно авторизованы
accept  authenticated = *

# Реализация нашего бан-листа
deny   hosts = +host_reject
message = You are banned. Go away.
# Запрещаем все, что не разрешено, закрывая тем самым релей для спамеров
deny    message       = relay not permitted

# Список доступа для проверки mime частей сообщения
acl_check_mime:

# Произодим декодирование mime сообщений. Полезно для дальнейшей проверки на
# вирусы
warn decode = default

# Можно очень быстро отсеять сообщения, просто запретив некоторые mime
# вложения, чаще всего содержащие вирусы, хотя, конечно, это не панацея
deny message = Blacklisted file extension detected
condition = ${if match \
{${lc:$mime_filename}} \
{\N(\.wav|\.cpl|\.pif|\.bat|\.scr|\.lnk|\.com)$\N} \
{1}{0}}

# Много ли у нас людей, знающих китайский? А вот китайского спама это поубавит
# :)
deny message = Sorry, noone speaks chinese here
condition = ${if eq{$mime_charset}{gb2312}{1}{0}}

accept

# Проверка содержимого на вирусы и спам
acl_check_virus:
# Мы не запрещаем письма со спамом, а просто добавляем заголовок,
# содержащий количество спамерских очков, а пользователь на своей
# стороне уже просто настраивает свои фильтры. Так мы исключаем жалобы
# со стороны пользователей о потерянных письмах
warn  message = X-Spam-Score: $spam_score ($spam_bar)
spam = nobody:true

# Добавляем заголовки, указывающие, что письма были проверены
# spamasssasin'ом
warn message = X-Spam-Scanned: Yes
warn message = X-Spam-Scanner: SpamAssassin running on mail.test.ru

# Вот что-что, а вирусы нам не нужны.
deny  message   = Message rejected: virus found. Your message was successfully trashed.
hosts       = *
malware = *
accept

######################################################################
#                      ROUTERS CONFIGURATION                         #
#               Specifies how addresses are handled                  #
######################################################################
#     THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT!       #
# An address is passed to each router in turn until it is accepted.  #
######################################################################

begin routers

# Роутер, осуществляющий поиск по MX записям в DNS
dnslookup:
driver = dnslookup
domains = ! +local_domains
transport = remote_smtp
ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
no_more

# Все останльные роутеры обслуживают доставку локальной почты

# Драйвер алиасов пользователя. Обратите внимание на lookup в pgsql базе. Что
# интересно, этот lookup работает даже для иерархических алиасов, например,
# postmaster -> root -> cebka -> cebka@jet.msk.su Также определяются транспорты
# для передачи почты в файл (>/path/to/file) и в pipe
# (|/usr/local/libexec/slocal)
system_aliases:
driver = redirect
allow_fail
allow_defer
data = ${lookup pgsql{select alias from aliases where mail ='$local_part@$domain'}{$value}fail}
user = mailnull
group = mail
file_transport = address_file
pipe_transport = address_pipe

# Для локальных пользователей также создаем возможность перенаправления почты
# через ~/.forward файл. Если включена директива allow_filter, то в .forward
# файле можно использовать язык sieve фильтров. Для подробностей см.
# документацию на www.exim.org, т.к. на рассмотрение этой темы уйдет слишком
# много времени
userforward:
driver = redirect
check_local_user
file = $home/.forward
no_verify
no_expn
check_ancestor
# allow_filter
file_transport = address_file
pipe_transport = address_pipe
reply_transport = address_reply
condition = ${if exists{$home/.forward} {yes} {no} }

# Локальная доставка, если данный пользователь найдем в базе

localuser:
driver = accept
condition = ${lookup pgsql {select uid from accounts where login = '$local_part@$domain'}{yes}{no}}
transport = local_delivery
cannot_route_message = Unknown user

######################################################################
#                      TRANSPORTS CONFIGURATION                      #
######################################################################
#                       ORDER DOES NOT MATTER                        #
#     Only one appropriate transport is called for each delivery.    #
######################################################################

begin transports

# Драйвер для доставки через соединения с удаленными smtp серверами
remote_smtp:
driver = smtp

# Этот транспорт доставляет почту в локальные maildir'ы. Путь к maildir хранится
# опять же в таблице accounts. Разрешения на директорию 0700 для возможности
# работы с данными директориями imap сервера. При этом владельцем является
# группа и пользователь из accounts (потому при вставлении записей в эту таблицу
# надо начинать значения uid с достаточно большого числа, например, 2000 и
# пересекаться с реальными пользователями оно должно только если реальному
# пользователю нужен локальный доступ к maildir'у).
# Также из таблицы accounts извлекается данные о размере квоты, и
# устанавливается порог в 75% от квоты, когда пользователю посылается указанное
# предупреждение об подходе к порогу квоты
local_delivery:
driver = appendfile
directory = ${lookup pgsql{select maildir from accounts where login = '$local_part@$domain'}{$value}fail}
create_directory
directory_mode = 0770
maildir_format
delivery_date_add
envelope_to_add
return_path_add
group = ${lookup pgsql{select gid from accounts where login = '$local_part@$domain'}{$value}fail}
user = ${lookup pgsql{select uid from accounts where login = '$local_part@$domain'}{$value}fail}
mode = 0660
no_mode_fail_narrower
quota = ${lookup pgsql{select mailquota from accounts where login = '$local_part@$domain'}{$value}fail}M
quota_warn_message = "\
To: $local_part@domain\n\
From: postmaster@test.ru\n\
Subject: Your maildir is going full\n\
This message is automaticaly gnerated by your mail server.\n\
This means, that your mailbox is 75% full. If you would \n\
override this limit new mail would not be delivered to you!\n"
quota_warn_threshold = 75%

# Транспорт, осуществляющий доставку в pipe
address_pipe:
driver = pipe
return_output

# Транспорт, осуществляющий доставку прямо в файл
address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add

# Этот транспорт используется для автоматического ответа на сообщения об ошибках
address_reply:
driver = autoreply

######################################################################
#                      RETRY CONFIGURATION                           #
######################################################################

begin retry

# Настройки по умолчанию, которые я не трогал, управляют интервала повторной
# передачи сообщений

# This single retry rule applies to all domains and all errors. It specifies
# retries every 15 minutes for 2 hours, then increasing retry intervals,
# starting at 1 hour and increasing each time by a factor of 1.5, up to 16
# hours, then retries every 6 hours until 4 days have passed since the first
# failed delivery.

# Address or Domain    Error       Retries
# -----------------    -----       -------

*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h

######################################################################
#                      REWRITE CONFIGURATION                         #
######################################################################

begin rewrite

# Создаем правило, по переписыванию заголовка To: с *@test.ru на локальный
# smart-host - @unona.test.ru. Это было сделано для локальных пользователей,
# по идее с хранением пользователей в postgres, уже не нужно, показано для
# примера.
*@test.ru $1@unona.test.ru T

######################################################################
#                   AUTHENTICATION CONFIGURATION                     #
######################################################################

# Описания аутентификации

begin authenticators
# CRAM-MD5 аутентификация, требует наличия пароля в открытом виде, имя
# пользователя должно быть в формате user@domain, как оно хранится в таблице
# accounts
lookup_cram:
driver = cram_md5
public_name = CRAM-MD5
server_secret = ${lookup pgsql {select password from accounts where login='$1'}{$value}fail}
server_set_id = $1
# LOGIN аутентификация - не требует хранения пароля в открытом виде, однако, по
# сети пароль передается в открытом виде - требуется лишь выполнение условия
# server_condition - $1 - имя пользователя, а $2 - пароль. LOGIN безопасен
# только при установлении ssl соединения.
login:
driver = plaintext
public_name = LOGIN
server_prompts = Username:: : Password::
server_condition = ${lookup pgsql {select login from accounts where login='$1' and password='$2'}{yes}{no}}
server_set_id = $1

######################################################################
#                   CONFIGURATION FOR local_scan()                   #
######################################################################

# If you have built Exim to include a local_scan() function that contains
# tables for private options, you can define those options here. Remember to
# uncomment the "begin" line. It is commented by default because it provokes
# an error with Exim binaries that are not built with LOCAL_SCAN_HAS_OPTIONS
# set in the Local/Makefile.

# begin local_scan

# End of Exim configuration file






Далее необходимо создать сертификат для smtp сервера. В ходе эксплуатации выяснилось, что некоторые клиенты, например, The Bat!, требуют, чтобы в CN сертификта (подробнее о сертификатах и способах их генерации можно прочитать в моей статье из данного журнала, располагающейся по адресу http://cebka.pp.ru/my/openssl.txt) содержалось имя (FQDN) сервера. Например, для сервера на mail.test.ru серификат должен содержать CN: mail.test.ru.
Содержание остальных полей некритично. Создать сертификат можно, например, так:

# openssl genrsa -out mailed.key 2048
# openssl req -new -x509 -key mailed.key -days 365 -out mailed.crt

При этом все поля сертификата будут запрошены. Учтите, что файл секретного ключа не должен быть зашифрован, иначе exim не сможет его прочитать, просто установите владельцем этого файла root:wheel и установите права 0600.

После этого можно попробовать запустить exim в режиме отладки:

exim -bd -d+all

и понаблюдать за выводимыми сообщениями. Чтобы включить exim вместо sendmail делаем следующие действия:
в файле /etc/rc.conf нужны следующие строки:

sendmail_enable="NONE"
exim_enable="YES"
# А также для spamassasin и clamav:
clamav_clamd_enable="YES"
spamd_enable="YES"


Далее настраиваем доставку почты для локальных приложений через exim, для чего файл /etc/mail/mailer.conf у нас должен выглядеть следующим образом:

sendmail        /usr/local/sbin/exim
send-mail       /usr/local/sbin/exim
mailq           /usr/local/sbin/exim -bp
newaliases      /usr/local/sbin/exim -bi
hoststat        /usr/local/sbin/exim
purgestat       /usr/local/sbin/exim


Далее перейдем к настройке clamav: заходим в /usr/local/etc/ и копируем clamav.conf.sample в clamav.conf и правим его таким образом, чтобы он принимал соединения через tcp/ip, а не через локальный сокет, для чего в clamav.confнужны
следующие строки:

TCPSocket 3310
TCPAddr 127.0.0.1

Далее копируем freshclam.conf.sample в freshclam.conf. Этот файл указывает настройки для программы freshclam, использующейся для обновления антифирусных баз clamav.

SpamAssasin работает без дополнительных настроек.

Перейдем к следующей части - настройка courier'a. Этот imap сервер для своей работы использует несколько процессов, которые, в свою очередь, настраиваются из различных конфигурационных файлов. В моем примере запущено 3 процесса - authdaemon, courier-imapd и courier-imapd-ssl. Причем во внешний мир открыт
только courier-imapd-ssl. Для начала создадим сертификат для imapd-ssl и для TLS соединений с imapd:

правим файл /usr/local/etc/couier-imap/imapd.cnf на предмет своего dn для сертификата, для чего в части req_dn прописываем свои настройки (не забудте, что cn должен совпадать с FQDN imap сервера):

[ req_dn ]
C=RU
ST=Moskow region
L=Moskow
O=Tehnopark
OU=Internet technologies
CN=test.ru
emailAddress=postmaster@test.ru

Далее генерируем сертификат специальным скриптом:

cd /usr/local/share/courier-imap/
./mkimapdcert

После чего настроим imap аутентификацию:
cd /usr/local/etc/courier-imap/
cp authdaemonrc.dist authdaemonrc
далее в authdaemonrc заменяем список модулей для аутентификации на:

authmodulelist="authpgsql"

Теперь courier знает, что ему нужно аутентифицироваться через pgsql. Надо только настроить сам pgsql модуль, настройки которого хранятся в authpqsqlrc. Он должен содержать следующее:

# Соединяемся с СУБД через локальный сокет (не указан адрес)
PGSQL_PORT              5432
PGSQL_USERNAME          pgsql
PGSQL_PASSWORD          pAsSwOrD
PGSQL_DATABASE          users

# Настройки таблицы для аутентификации, здесь мы указываем, в каких полях
# таблицы хранятся различные пользовательские данные:
PGSQL_USER_TABLE        accounts
PGSQL_CLEAR_PWFIELD     password
DEFAULT_DOMAIN          test.ru
PGSQL_UID_FIELD         uid
PGSQL_GID_FIELD         gid
PGSQL_LOGIN_FIELD       login
PGSQL_HOME_FIELD        home
PGSQL_NAME_FIELD        gecos
PGSQL_MAILDIR_FIELD     maildir


Перейдем к настройке непосредственно imapd:
скоприуем imapd.dist в imapd. Правим следующие строчки (для остальных настроек
вполне подходят значения по умолчанию):

# imapd слушает только на локальном адресе, для внешних соединений мы будем
# использовать imapd-ssl
ADDRESS=127.0.0.1

# По умолчанию в NO, делаем в YES, чтобы imapd мог запускаться
IMAPDSTART=YES

Этих настроек, в принципе, хватает. Далее копируем imapd-ssl.dist в imapd-ssl и
правим следующие строчки:

IMAPDSSLSTART=YES

После чего делаем запуск courier-imap при старте системы. Для этого заходим в /usr/local/etc/rc.d и снова немного попереименовываем файлы:

# mv courier-imap-imapd-ssl.sh.sample courier-imap-imapd-ssl.sh
# mv courier-imap-imapd.sh.sample courier-imap-imapd.sh


После этого считаем, что наша почтовая система практически готова. Нужно только немного понастраивать squirrelmail для чего заходим в /usr/local/www/squirrelmail и запускаем скрипт ./configure. В принципе, интерфейс конфигурации понятен без лишних пояснений, потому я не буду особо останавливаться на этой проблеме (не забудьте, главное, указать imap и smtp сервера). Делаем симлинк на /usr/local/www/squirrelmail из какого-либо VirtualHost'а или из под непосредственно DocumentRoot самого apache. Вот, в принципе, и все.

Есть некоторые особенности запуска squirrelmail в при включенном safe_mode в php. Во-первых все php файлы и каталоги squirrelmail должны принадлежать тому пользователю, из под которого работает apache (настройка VirtualHost или глобальная, по умолчанию - www:nogroup). Кроме того необходимо сменить разрешения в /var/spool/squirrelmail:

# chmod 1777 /var/spool/squirrelmail/attach
# chmod 1777 /var/spool/squirrelmail/pref


Ну и владельца установить того же, что и на /usr/local/www/squirrelmail.


Теперь дам ссылки на пару полезных скриптов, написанных в ходе эксплуатации системы:
-скрипт статистики clamav'а: http://cebka.pp.ru/samag/clamstat.tar.bz2
-скрипт проверки пересечения uid'ов из БД и системных: http://cebka.pp.ru/samag/uidchk.pl


В конце приведу список полезных ссылок:

- http://www.exim.org - сайт MTA exim, очень хорошая и подробная документация
- ftp://ftp.exim.org/pub/exim/config.samples.tar.bz2 - примеры разнообразных конфигурационных параметров, полезно для ознакомления
- http://duncanthrax.net/exiscan-acl/ - патч exiscan с сопутствующей документацией
- http://www.clamav.net - сайт свободного антивируса clamav
- http://www.spamassasin.org - официальный сайт SpamAssasin'a
- http://www.courier-mta.org - ресурс courier продуктов, в том числе и courier-imap
- http://www.squirrelmail.org - сайт web-mail системы squirrelmail
- http://www.nixp.ru/cgi-bin/go.pl?q=articles;a=mta-home - exim+mutt+bmx для домашней почтовой системы (хорошая и интересная статья)
- http://tomster.org/geek/freebsdcookbook/ - альтернативный вариант реализации почтовой системы, где вместо courier'а используется cyrus imapd.

Операции с документом

Яндекс.Метрика Top.Mail.Ru