Почтовая система на базе MTA exim


Всеволод Стахов

В этой статье пойдет речь о создании эффективного почтового сервера на базе MTA exim. Первый вопрос, который, конечно же, приходит в голову – «Почему именно exim?». Отвечают на этот вопрос по-разному, поэтому я скажу, что меня так привлекает в exim:

n логичная схема обработки почты;

n высокая скорость работы;

n удобный формат конфигурационного файла;

n широчайшие возможности по поиску каких-либо значений в файлах, СУБД, LDAP;

n встроенная поддержка smtp-аутентификации;

n небольшое число найденных уязвимостей (фактически я знаю только об одной, найденной недавно, она касалась версий exim до 4.20 включительно);

n очень большое количество возможностей, а также чрезвычайная гибкость;

n возможность полной замены sendmail (т.е. можно сделать):

ln -sf /usr/local/sbin/exim /usr/libexec/sendmail

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

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

n простота управления пользователями;

n возможность предоставления доступа для отправки почты пользователям локальной сети и мобильным пользователям (при помощи smtp-аутентификации);

n максимальная защита от хакерских атак, вирусов и спама.

Базовой системой для установки MTA явилась FreeBSD 5.2.1, что обусловило определенные особенности установки. Перечислю весь набор программного обеспечения для организации mail-сервера:

n exim-4.34;

n MTA (mail transfer agent – агент передачи почты);

n courier-3.0.4 – imap-сервер для доступа к почте пользователей, не имеющих локальных пользовательских учетных записей (виртуальные пользователи);

n ClamAV – для поиска вирусов;

n SpamAssasin – для поиска спамерских писем;

n PostgreSQL-7.4.2 – для хранения всех данных о пользователях почтовой системы;

n 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, как основы для построения почтовой системы. Во-первых, Postgre SQL работает с правами системного пользователя 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);



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

n таблица accounts предназначена для хранения данных о виртуальных пользователях почтовой системы, назначение полей:

n uid – уникальный номер пользователя, имеет автоинкрементный тип;

n login – строка, содержащая имя пользователя в формате «имя@домен» для возможности доставки почты для пользователей различных доменов;

n password – пароль в открытом виде (для возможности безопасной cram-md5 аутентификации);

n maildir – путь к почтовому ящику в формате maildir -gecos – комментарий (для чего-нибудь да пригодится);

n gid – идентификатор группы (не нужен реально, но зачем-то требуется для courier);

n home – аналогично gid;

n mailquota – число в мегабайтах, указывающее квоту для пользователя;

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

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

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

Представим себе путь прохождения любого почтового сообщения. Любое письмо состоит из так называемого конверта и собственно данных. То, с чем мы привыкли работать в почтовых клиентах, как раз является «данными» и не имеет к конверту никакого отношения. В конверте описываются 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 состоит из нескольких частей:

n настройка глобальных параметров;

n настройка acl’s;

n настройка роутеров;

n настройка транспортов;

n настройка аутентификаторов;

n настройка очереди;

n настройка 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. Кое-где я добавил свои комментарии, чтобы улучшить понимание различных директив.

##########################################################

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

##########################################################


# Этот список доступа описывает проверки, осуществляемые при вызове любой 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: dialups.mail-abuse.org: relays.mail-abuse.org: relays.ordb.org:
work.drbl.caravan.ru: dul.ru:sbl.spamhaus.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
From: postmaster@test.ru
Subject: Your maildir is going full
This message is automaticaly gnerated by your mail server.
This means, that your mailbox is 75% full. If you would
override this limit new mail would not be delivered to you! "
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
newaliases /usr/local/sbin/exim
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.

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

Перейдем к следующей части – настройка courier. Этот 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-сервера):

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.

Комментарии вы можете присылать на cebka@jet.msk.su.

http://www.av5.com

Обновлено: 12.03.2015