Ads 468x60px

четверг, 31 мая 2012 г.

Debian squezee. Связка dovecot 2 + exim на postgresql.

Исходные данные: на Debian squezee имеем dovecot 2 установленный по заметке, и exim собранный по другой заметке.
Цель: настроить exim на совместную работу с dovecot, аутентификацию пользователей exim делать через dovecot, дабы не хранить в базе пароли в открытом виде.
Подготовительная работа
Резервная копия существующих настроек
$ sudo tar -jcvf etc.exim4.tbz /etc/exim4/*
Пересоздаем каталог для исключения возможных пересечений
$ sudo rm -rf /etc/exim4/*
$ sudo mkdir -p /etc/exim4/conf.d
Конфигурация exim.
Главный файл запуска /etc/exim4/exim4.conf

######################################################################
#      Runtime configuration file for Exim 4 (Debian Packaging)      #
######################################################################
#                    MAIN CONFIGURATION SETTINGS                     #
######################################################################

# Just for reference and scripts. 
# On Debian systems, the main binary is installed as exim4 to avoid
# conflicts with the exim 3 packages.
exim_path = /usr/sbin/exim4

# основные настройки
.include /etc/exim4/conf.d/100.main.conf

### конфигурация ACL для входящей почты
begin acl
# Эти правила срабатывают для каждого получателя
acl_check_rcpt:
# Начало файла ACL - те, кого срубаем сразу же
.include /etc/exim4/conf.d/200.acl_check_rcpt.conf
# Конец конфигурации - блэк-листы, задержки и прочее
.include /etc/exim4/conf.d/400.acl_check_rcpt_end.conf
# Тут идут ACL проверяющие содержимое (тело) письма.
# Без них будут пропускаться все сообщения.
.include /etc/exim4/conf.d/500.acl_check_data.conf

# чё делаем с почтой
begin routers
# Инклюдим конфигурацию роутреров
.include /etc/exim4/conf.d/600.routers.conf

# начинаются транспорты - как доставляем почту
begin transports
# Инклюдим транспорты
.include /etc/exim4/conf.d/700.transports.conf

# Конфигурация повторов и перезаписи
begin retry
.include /etc/exim4/conf.d/800.retry_and_rewrite.conf

# Секция авторизации при отправке писем.
begin authenticators
# Аутентификация юзеров.
.include /etc/exim4/conf.d/900.authenticators.conf

# © lissyara       2006-02-25, 01:19
# © DNK            
# © felis-lybica Thu May 24 13:32:57 MSK 2012
Основной конфигурационный файл /etc/exim4/conf.d/100.main.conf:
# Имя хоста. Используется в EHLO.
# Фигурирует в других пунктах, если они не заданы -
# типа qualify_domain и прочих..
# Если тут ничё не установлено (строка закомметрована)
# то используется то, что вернёт функция uname()
primary_hostname = you.domain.name

# Здесь мы указываем, где находить наш postgresql сервер, соединение
# осуществляется через локальный сокет, команда hide помогает спрятать эту
# настройку при вызове exim -bP, когда exim выводит 
# все конфигурационные опции в стандартный вывод. Учтите,
# что сам conf.d/100.main.conf должен иметь владельца root:wheel и
# иметь права доступа 0600, что отличается от того, что принято по умолчанию
# (0644)
hide pgsql_servers = localhost/vmail/vmail/secret

###################################
# Тут мы описываем списки доменов #
###################################
# Local_domains включает домены, считающиеся локальными, то есть те домены, для
# которых exim делает локальную доставку, для остальных доменов почта
# доставляется по MX записям в DNS.
domainlist local_domains =${lookup pgsql{SELECT array_to_string(array(SELECT domain FROM local_domain),':')}}
# Список хостов, почту на которые мы явно отвергаем
hostlist host_reject = ${lookup pgsql{SELECT array_to_string(array(SELECT domain FROM hostreject),':')}}
#Список доменов куда разрешен прием
domainlist relay_to_domains = ${lookup pgsql{SELECT array_to_string(array(SELECT hosts FROM relaytohosts),':')}}
# Список адресов, с которых разрешена передача почты во внешний мир
hostlist relay_from_hosts =${lookup pgsql{SELECT array_to_string(array(SELECT hosts FROM relayfromhosts),':')}}

# A это как раз кусок вышеописанного анахронизма - про почту в
# виде user@[222.222.222.222] - принимать её или нет. По дефолту
# (когда строка закомментирована) значение - false. Если захотите
# поставить true то надо будет добавить в список доменов
# комбинацию @[] - она означает `все локальные адреса`
allow_domain_literals = false

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

# Здесь мы описываем наш антивирус
av_scanner = clamd:/var/run/clamav/clamd.ctl

# Настройки пользователя и группы по умолчанию
exim_user = vmail
exim_group = vmail

# Порты какие будет слушать Exim (25)
daemon_smtp_ports = 25

# Никогда не осуществляем доставку под рутом - root должен быть алиасом на
# другого локального пользователя. Кстати, это _обязательное_ условие, заданное
# еще на этапе компиляции
never_users = root

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

# По дефолту, экзим отфутболивает все `неквалифицированные` адреса,
# состоящие тока из локальной части. Для того чтобы разрешить такие письма
# определённых хостов используются эти директивы:
# для `неквалифицированных` отправителей
sender_unqualified_hosts = +relay_from_hosts

# для `неквалифицированных` получателей
recipient_unqualified_hosts = +relay_from_hosts

# список адресов, через запятую, на которые засылаются
# сообщения о замороженных сообщениях (о замороженых
# уведомлениях о заморозке, сообщения не генерятся. - я
# надеюсь эта строка понятна :))
#freeze_tell = admin@lissyara.su

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

# Приветствие сервера
smtp_banner = "$primary_hostname, ESMTP EXIM $version_number"

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

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

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

# Принудительная синхронизация. Если отправитель
# торопится подавать команды, не дождавшись ответа,
# то он посылается далеко и надолго :) Немного,
# спам режется.
smtp_enforce_sync = true

# Выбираем, что мы будем логировать
# + - писать в логи,
# - - Не писать в логи.
# +all_parents - все входящие?
# +connection_reject - разорваные соединения
# +incoming_interface - интерфейс (реально - IP)
# +lost_incoming_connections - потеряные входящие
# соединения
# +received_sender - отправитель
# +received_recipients - получатель
# +smtp_confirmation - подтверждения SMTP?
# +smtp_syntax_error - ошибки синтаксиса SMTP
# +smtp_protocol_error - ошибки протокола SMTP
# -queue_run - работа очереди (замороженные мессаги)
log_selector = \
        +all \
#       -incoming_port \
#       -incoming_interface \
        -arguments \
        -smtp_connection \
        -lost_incoming_connection \
        -queue_run

# Убираем собственную временную метку exim`a из логов, её ставит
# сам syslogd - нефига дублировать
syslog_timestamp = no
log_file_path = syslog : /var/log/exim4/%s-%D.log
Файл начала ACL, список правил по которым отсекаем письма /etc/exim4/conf.d/200.acl_check_rcpt.conf
# Проверка получателей

  # принимать сообщения которые пришли с локалхоста,
  # не по TCP/IP
  accept  hosts = :

  # Запрещаем письма содержащие в локальной части
  # символы @; %; !; /; |. Учтите, если у вас было
  # `percent_hack_domains` то % надо убрать.
  # Проверяются локальные домены
        deny    message = "incorrect symbol in address"
                domains = +local_domains
                local_parts     = ^[.] : ^.*[@%!/|]
                delay   = 30s

  # Проверяем недопустимые символы для
  # нелокальных получателей:
        deny    message = "incorrect symbol in address"
                domains = !+local_domains
                local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
                delay   = 30s

  # Запрещщаем тех, кто не обменивается приветственными
  # сообщениями (HELO/EHLO)
        deny    message         = "HELO/EHLO require by SMTP RFC"
                condition       = ${if eq{$sender_helo_name}{}{yes}{no}}
                delay           = 30s

# если логин и заголовок from не совпадает ругаемся и запрещаем
        deny   authenticated = *
          message = "Sender address and authentication address do not match"
          condition = ${if ! match{$authenticated_id@$qualify_domain}{$sender_address}{yes}{no} }

  # Принимаем сообщения от тех, кто аутентифицировался:
  # Вообще, большинство конфигов в рунете - это один и тот же
  # конфиг написанный Ginger, в котором этот пункт расположен
  # внизу. Но при таком расположении рубятся клиенты с adsl,
  # ppp, и прочие зарезанные на последующих проверках. Но это
  # жа неправильно! Этом мои пользователи из дома! Потому
  # я это правило расположил до проверок.
  accept  authenticated = *
        control       = submission

# Рубаем нах, тех, кто подставляет свой IP в HELO
        deny    message         = We don't allow domain literals, many spam...
                hosts           = !+relay_from_hosts:*
                condition       = ${if isip{$sender_helo_name}{yes}{no}}
                delay           = 30s

# Рубаем хело с нашим именем
        deny    condition       = ${if match_domain{$sender_helo_name} \
                        {$primary_hostname:+local_domains:+relay_to_domains} \
                        {true}{false}}
                message         = Message was delivered by ratware - own
                log_message     = remote host used our name in HELO/EHLO.
                delay   = 30s

# Рубаем мудаков с недопустимыми символами в helo (пока видел тока такие)
  deny    condition     = ${if match{$sender_helo_name}{\N_\N}{yes}{no}}
          hosts         = !127.0.0.1 : !localhost : !+relay_from_hosts : *
          set acl_m0    = ${eval:$acl_m0+20}

# Ограничения эксчейнджа - юзер не может начинаться/заканчиваться точкой.
  deny          message =       Invalid address
                senders =       \N^\.|\.@\N
Блэк листы /etc/exim4/conf.d/400.acl_check_rcpt_end.conf
# Рубаем хосты типа *adsl*; *dialup*; *pool*;....
  # Нормальные люди с таких не пишут. Если будут
  # проблемы - уберёте проблемный пункт (у меня клиенты
  # имеют запись типа asdl-1233.zone.su - я ADSL убрал...)
  deny    message       = "Не нравится мне Ваш хост..."
          condition     = ${if match{$sender_host_name} \
                               {adsl|dialup|pool|peer|dhcp} \
                               {yes}{no}}

  # Проверка получателя в локальных доменах.
  # Если не проходит, то проверяется следующий ACL,
  # и если непрошёл и там - deny
  accept  domains       = +local_domains
          endpass
          message       = "В этом домене нет такого пользователя"
          verify        = recipient

  # Проверяем получателя в релейных доменах
  # Опять-таки если не проходит -> следующий ACL,
  # и если непрошёл и там - deny
  accept  domains       = +relay_to_domains
          endpass
          message       = "Моя сервера не знать маршрут на этот хост..."
          verify        = recipient
  # Разрешаем почту от доменов в списке relay_from_hosts
  accept  hosts         = +relay_from_hosts
        deny hosts         =!+relay_from_hosts

  # Реализация нашего бан-листа
  deny   hosts          = +host_reject
         message        = You are banned. Go away.

  # Список доменов, почту от которых не принимаем
  deny    message       = "domain in blacklist "
          condition     = ${if eq {$sender_address_domain} \
                                {${lookup pgsql{SELECT domain FROM black_domain WHERE domain = '$sender_address_domain'}}} \
                            {yes}{no} }
#       log_message   = Deny by domain $sender_address of domain $sender_address_domain 

  # Если неподошло ни одно правило - чувак явно ищет
  # открытый релей. Пшёл прочь. :)
  deny    message       = "Свободен. Это тебе не ОпенРелей."
Проверка содержимого и наличия вирусов /etc/exim4/conf.d/500.acl_check_data.conf
# Список доступа для проверки 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|\.exe|\.vbs)$\N} \
                     {1}{0}}

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

  accept

# Проверка содержимого на вирусы
acl_check_virus:

        # Вот что-что, а вирусы нам не нужны.
        deny  message   = Message rejected: virus found. \
                        Your message was successfully trashed.
                malware     = *
accept
Маршрутизация /etc/exim4/conf.d/600.routers.conf
# Роутер, осуществляющий поиск по 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 работает даже для иерархических алиасов
# Также определяются транспорты
# для передачи почты в файл (>/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'}{$value}fail}
  user = vmail
  group = vmail
  file_transport = address_file
  pipe_transport = address_pipe


#routers переадресация почты
userforward:
  driver = redirect
  allow_fail
  allow_defer
  data = ${lookup pgsql{SELECT recipients FROM userforward \
         WHERE local_part='${local_part}'}}

# Локальная доставка, если данный пользователь найдем в базе
localuser:
  driver = accept
  condition = ${lookup pgsql {select 500 as uid from \
                users where username = '$local_part'}{yes}{no}}
  transport = local_delivery
  cannot_route_message = Unknown user
Транспорт /etc/exim4/conf.d/700.transports.conf:
######################################################################
#                      TRANSPORTS CONFIGURATION                      #
######################################################################
#                       ORDER DOES NOT MATTER                        #
#     Only one appropriate transport is called for each delivery.    #
######################################################################

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

# Этот транспорт доставляет почту в локальные maildir'ы. 
# Путь к maildir хранится
# опять же в таблице accounts. Разрешения на директорию 0770 для возможности
# работы с данными директориями imap сервера. При этом владельцем является
# группа и пользователь из users
#(потому при вставлении записей в эту таблицу
# Также из таблицы users извлекается данные о размере квоты, и
# устанавливается порог в 75% от квоты, когда пользователю посылается указанное
# предупреждение об подходе к порогу квоты
local_delivery:
  driver = appendfile
  directory = ${lookup pgsql{select home||username as home from \
                users where username = '$local_part'}{$value}fail}
  create_directory
  directory_mode = 0700
  maildir_format
  delivery_date_add
  envelope_to_add
  return_path_add
  group = vmail
  user = vmail
  mode = 0600
  no_mode_fail_narrower
#  quota = ${lookup pgsql{select mailquota from \
#        accounts where login = '$local_part'}{$value}fail}M
#  quota_warn_message = "\
#          To: $local_part\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
Повторы и перезапись /etc/exim4/conf.d/800.retry_and_rewrite.conf
# Настройки по умолчанию, которые я не трогал, управляют интервала повторной
# передачи сообщений

# 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
Аутентификация /etc/exim4/conf.d/900.authenticators.conf
# аутентификация средствами dovecot
dovecot_login:
  driver = dovecot
  public_name = LOGIN
  server_socket = /var/run/dovecot/auth-client
# setting server_set_id might break several headers in mails sent by authenticated smtp. So be careful.
  server_set_id = $auth1

dovecot_plain:
  driver = dovecot
  public_name = PLAIN
  server_socket = /var/run/dovecot/auth-client
  server_set_id = $auth1
База данных.
Таблицы для формирования списков конфигурации exim'a:
$ psql vmail -U vmail
vmail=# CREATE TABLE local_domain (domain text);
vmail=# CREATE TABLE hostreject (domain text, coment text);
vmail=# CREATE TABLE black_domain(domain text);
vmail=# CREATE TABLE relayfromhosts (hosts text, coment text);
vmail=# CREATE TABLE relaytohosts (hosts text, coment text);
vmail=# CREATE TABLE userforward (id serial, local_part text, recipients text);
vmail=# CREATE TABLE aliases (
        mail VARCHAR(128) NOT NULL PRIMARY KEY,
        alias VARCHAR(128) NOT NULL);
Заполняем таблицы:
vmail=# INSERT INTO local_domain VALUES ('you.domain.name');
vmail=# INSERT INTO hostreject VALUES ('81.52.142.217','orange.fr by IP');
vmail=# INSERT INTO black_domain VALUES ('orange.fr');
vmail=# INSERT INTO relayfromhosts VALUES ('localhost','from this host');
vmail=# INSERT INTO relayfromhosts VALUES ('127.0.0.0/8','localhost inside');
vmail=# INSERT INTO relayfromhosts VALUES ('192.168.0.0/16','from local net');
vmail=# INSERT INTO relaytohosts VALUES ('you.domain.name','You self');
vmail=# INSERT INTO userforward(local_part,recipients) VALUES ('retest','test@you.domain.name');
vmail=# INSERT INTO aliases VALUES('info','test');
vmail=# \q
При таком заполнении таблиц письма отправленные на test@you.domain.name и info@you.domain.name будут доставлены на почтовый ящик retest@you.domain.name.
Системные изменения.
Права на папки.
Смена владельца служебных папок exim'a, так как после установке debian создает их для пакета exim4-daemon-light:
$ sudo chown vmail:vmail /var/log/exim4
$ sudo chown -R vmail:vmail /var/spool/exim4
Антивирус.
Установка:
$ sudo aptitude install clamav-daemon clamav-freshclam
Добавление в группу для сканирования файлов в спуле exim'a:
$ sudo gpasswd --add clamav vmail
Перезапуск антивируса для применения новых прав:
$ sudo service clamav-daemon restart
Последний штрих
Не забыть перезапустить exim:
$ sudo service exim4 restart

Статьи которые использовались для создания конфигурации:
Exim + dovecot + PgSQL + web интерфейсы почты и управления
Настройка exim (relay) и M$ exchange (почтарь внутри локалки)

2 комментария:

Viacheslav Rymar комментирует...

Отличная статья! Спасибо! все заработало :)

felis-lybica комментирует...

спасибо, очень рад)