Заметки о работе с ОС FreeBSD. Статьи об установке и настройке ПО для FreeBSD.

18 декабря 2008 г.

rm: Argument list too long

Часто возникает вопрос, что делать если при удалении большого кол-ва файлов мы сталкиваемся с ошибкой Argument list too long. Связано это обычно с превышением кол-ва файлов свыше 1024.


[root@test-srv-04 /root/testdir82]# rm -rf *

bash: /bin/rm: Argument list too long


Выход довольно прост, как оказалось :)
[root@test-srv-04 /root/testdir82]# find . | xargs rm


Этот код удалит все файлы в текущей папке, независимо от того, сколько их.
Источник: http://www.dp76.com/log/579

15 декабря 2008 г.

Настройка dovecot для работы по протоколам imaps и pop3s

Будем настраивать dovecot 1.1.7 (версия на момент написания статьи) для работы по протоколам pop3s и imaps (SSL, TLS). Дополнительно подключим плагины quota и trash. Настроена авторизация пользователей в базе MySQL.

[root@imap-srv-142 ~]# pkg_info | grep dovecot
dovecot-1.1.7       Secure and compact IMAP and POP3 servers
[root@imap-srv-142 ~]# uname -mrs
FreeBSD 7.0-RELEASE-p3 i386

Предполагается, что dovecot уже установлен в систему.
Итак...

=== Файл dovecot.conf

base_dir = /var/run/dovecot/


# Протоколы, по которым будет отвечать dovecot
protocols = imap imaps pop3 pop3s


# Интерфейс, по которому dovecot будет принимать соединения. "*" - все интерфейсы.
listen = *


# Тоже самое, только для SSL.
#ssl_listen = 

# Запрещаем аутентификацию открытым текстом
disable_plaintext_auth = yes


# Завершать все дочерние процессы, если завершен мастер-процесс.
shutdown_clients = yes


# Формат временной метки для логов
log_timestamp = "%b %d %H:%M:%S "
syslog_facility = mail
ssl_disable = no


# Директория для хранения сокетов аутентификации
login_dir = /var/run/dovecot/login

# Каждый процесс аутентификации в chroot
login_chroot = yes


# От какого пользователя будет запускаться процесс аутентификации
login_user = dovecot


# Макисимальный размер процесса в памяти (Мб)
login_process_size = 256


# На каждое соединение - свой процесс
login_process_per_connection = yes


# Число свободных процессов ожидающих соединения
login_processes_count = 25


# Максимальное число процессов авторизации.
login_max_processes_count = 2048


# Максимальное число соединений
login_max_connections = 2048


# Приветствие сервера
login_greeting = COMPANYNAME Mail Server ready.


# Список элементов, которые будут записаны в лог-файл.
login_log_format_elements = user=<%u> method=%m rip=%r lip=%l %c


# Формат лога аутентификации
login_log_format = %$: %s


# Путь к директориям с почтой (%d - имя домена, %n - имя пользователя)
mail_location = maildir:/var/mail/%d/%n@%d


# Вкл/Выкл debug
#mail_debug = yes


# Показывать больше отладочной информации
#verbose_proctitle = yes


# Минимальный UID для пользователя
first_valid_uid = 20


# Минимальный GID для пользователя
first_valid_gid = 20


# Максимальное число запущенных процессов.
max_mail_processes = 2048


# Использовать хардлинки при копировании сообщений, если это возможно
maildir_copy_with_hardlinks = yes


# При копировании сообщений резервировать в ФС имя файла. Чтобы не было повторов.
maildir_copy_preserve_filename = yes


protocol imap {


   # Список плагинов, которые используются для протокола imap
   mail_plugins = quota imap_quota trash


   # Показывать возможности IMAP в приветственном сообщении
   login_greeting_capability = yes

   
   # Обработка ошибок почтовых клиентов
   imap_client_workarounds = delay-newmail netscape-eoh tb-extra-mailbox-sep


   # Сертификат и ключ. В данном случае для каждого домена - свой сертификат. Т. е. для
   # pop3 - один, для imap - другой.
   ssl_cert_file = /usr/local/etc/certificates/imap-srv-142.crt
   ssl_key_file = /usr/local/etc/certificates/imap-srv-142.key
}


protocol pop3 {


   # Поддерживать команду LAST, которая существовала в старых спецификациях POP3.
   pop3_enable_last = yes

   # Держать mailbox закрытым (locked) на протяжении всей pop3-сессии.
   pop3_lock_session = no


   # Формат POP3 UIDL
   pop3_uidl_format = %08Xu%08Xv


   # Максимально число соединений для пользователя с одного IP-адреса.
   mail_max_userip_connections = 3


   # Обработка ошибок почтовых клиентов
   pop3_client_workarounds = outlook-no-nuls oe-ns-eoh

   # Также, как и в секции imap - сертификат и ключ. 
   ssl_cert_file = /usr/local/etc/certificates/pop3-srv-142.crt
   ssl_key_file = /usr/local/etc/certificates/pop3-srv-142.key
}

# Больше отладочной информации.
#auth_verbose = yes
#auth_debug = yes
#auth_debug_passwords = yes


auth default {

   # Механизм авторизации (доступны: plain login digest-md5 cram-md5 ntlm rpa
   # apop anonymous gssapi otp skey gss-spnego)
   mechanisms = plain


   # База с паролями
   passdb sql {
      args = /usr/local/etc/dovecot-sql.conf
   }

   # База с пользователями
   userdb sql {
      args = /usr/local/etc/dovecot-sql.conf
   }

   # Пользователь, от которого будет работать процесс авторизации
   user = root

}


plugin {


  # Описание квоты для пользователя (см. рис. 1)
  quota = maildir:User quota

  # Значение для квоты по умолчанию. Далее у нас будет возможность переопределить
  # это значение для каждого пользователя отдельно.
  quota_rule = *:storage=5G

  # Правило 2. Для директории Trash (Корзина)  - 10% от общей квоты.
  quota_rule2 = Trash:storage=10%%

  # Правило 3. Для директории Junk (Спам) - 20% от общей квоты.
  quota_rule3 = Junk:storage=20%%

  # Выполнять следующую команду при превышении определенного порога квоты 
  quota_warning = storage=95%% /usr/local/bin/dovecot-quota-warning.sh 95
  quota_warning2 = storage=50%% /usr/local/bin/quota-warning.sh 50

  # Плагин Trash. При переполнении квоты - удалять старые сообщения из каталогов
  # в порядке, указанном в этом файле (см. ниже).
  trash = /usr/local/etc/dovecot-trash.conf
}

Примерно так параметры квоты видит конечный пользователь:

Рис. 1. Скриншот сообщения о квоте в Mozilla Thunderbird

Далее нам нужны файлы:
dovecot-sql.conf
dovecot-trash.conf

=== Файл dovecot-sql.conf:

# Коннектор. Доступны mysql, pgsql, sqlite.
driver = mysql


# Строка подключения к БД
connect = host=db-srv-core dbname=mail_users user=dovecot password=password


# Схема авторизации по умолчанию
default_pass_scheme = PLAIN


# Запрос на проверку паролей
password_query = SELECT username as user, password \
FROM mailbox WHERE username = '%u' AND active = '1'


# Запрос на проверку информации пользователей. В данном случае я вывожу
# информацию о домашней директории, имени пользователя, домену и квотах
user_query = SELECT maildir as home, 26 AS uid, 26 AS gid, \
username as user, domain, concat('*:storage=', quota, 'B') as quota_rule \
FROM mailbox WHERE username = '%u' AND active = '1'



=== Файл dovecot-trash.conf:

# Тут все просто - при превышении квоты сначала удаляются сообщения из 
# директории Junk, затем из Trash и только потом из Sent.
1 Junk
2 Trash
3 Sent

В конечном итоге мы получили pop3s-, imaps-сервер, предоставляющий клиентам при подключении валидные сертификаты для каждого из своих хостов. При этом запрещена аутентификация открытым текстом. Почтовый клиент может работать через SSL или TLS.

Про создание самоподписанного сертификата можно почитать здесь:

Дампы таблиц MySQL можно взять в этой статье:

Документация по dovecot: http://wiki.dovecot.org/



2 декабря 2008 г.

Репликация баз данных MySQL 5

Есть необходимость хранить online-копии баз данных на другом сервере.  Решено использовать master-slave репликацию MySQL.

Предполагается, что первый и второй MySQL серверы уже установлены и работают.

Для начала на первом сервере нам необходимо включить бинарный лог и назначить идентификатор этому серверу. 
Прописываем в my.cnf
log-bin=/var/db/mysql/srv-01-bin.log
server-id=1
Далее необходимо создать пользователя в БД, которым будет производиться репликация.
[root@db-srv-01 ~]# mysql -u root -h db-srv-01.local -p
mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave_db-srv-02'@'db-srv-02.local' IDENTIFIED BY 'Pa$$w0rd';
mysql> FLUSH PRIVILEGES;


Далее нам нужно сделать дамп всех БД, чтобы в дальнейшем развернуть его на втором сервере. Но для начала необходимо заблокировать таблицы на время дампа.

mysql> FLUSH TABLES WITH READ LOCK;


Также нам будут необходимы эти данные: имя файла бинарного лога master-сервера и позиция данных в бинарном логе.

mysql> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| srv-01-bin.000002 |    29599 |              |                  |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

Делаем дамп всех БД сервера.

[root@db-srv-01 ~]# mysqldump -u root -h db-srv-01.local -p -A > /tmp/dump_mysql_all.sql


Переходим к настройке второго сервера. В это время все БД первого сервера остаются заблокированными.

Разворачиваем БД из бэкапа на второй сервер.

[root@db-srv-02 ~]# mysql -u root -h db-srv-02.local -p < /tmp/dump_mysql_all.sql

Далее нам необходимо добавить в my.cnf следующие строки:

master-host = db-srv-01.local
master-user = slave_db-srv-02
master-password = Pa$$w0rd
master-port = 3306
server-id = 2
log-bin = /var/db/mysql/srv-02-bin.log
log-bin-index = /var/db/mysql/srv-02-bin-index.log
log-error = /var/db/mysql/srv-02-error.log
relay-log = /var/db/mysql/srv-02-relay.log
relay-log-info-file = /var/db/mysql/srv-02-relay-log.info
relay-log-index = /var/db/mysql/srv-02-relay-log.index
Необходимо указать стартовую позицию, с которой начинать репликацию.

[root@db-srv-02 ~]# mysql -u root -h db-srv-02 -p
mysql> CHANGE MASTER TO MASTER_LOG_FILE='srv-01-bin.000002';
mysql> CHANGE MASTER TO MASTER_LOG_POS=29599;
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State:
                  Master_Host: db-srv-01.local
                  Master_User: slave_db-srv-02
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: srv-01-bin.000002
          Read_Master_Log_Pos: 29599
               Relay_Log_File: srv-02-relay.000002
                Relay_Log_Pos: 28264
        Relay_Master_Log_File: srv-01-bin.000002
             Slave_IO_Running: No
            Slave_SQL_Running: No
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 29599
              Relay_Log_Space: 28416
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
1 row in set (0.00 sec)
Запускаем репликацию.

mysql> START SLAVE;
Query OK, 0 rows affected (0.00 sec)

Проверяем.

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: db-srv-01.local
                  Master_User: slave_db-srv-02
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: srv-01-bin.000002
          Read_Master_Log_Pos: 30360
               Relay_Log_File: srv-02-relay.000003
                Relay_Log_Pos: 252
        Relay_Master_Log_File: srv-01-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 30360
              Relay_Log_Space: 28562
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
1 row in set (0.00 sec)
Теперь необходимо разблокировать БД.

[root@db-srv-01 ~]# mysql -u root -h db-srv-01 -p
mysql> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)

Все.

Новые записи в таблицах автоматически появятся в на втором сервере.

При подготовке статьи я использовал следующие материалы:
1. "Статья Live Backups of MySQL Using Replication" http://www.onlamp.com/pub/a/onlamp/2005/06/16/MySQLian.html
2.  "How to Set Up Replication" из документации по MySQL http://dev.mysql.com/doc/refman/5.0/en/replication-howto.html

30 октября 2008 г.

Создаем самоподписанный SSL-сертификат

Для начала нам нужно создать приватный ключ, который мы будем использовать для создания CSR- или CRT-сертификатов.

[root@test248 ~]# openssl genrsa -out ca.key 1024
Generating RSA private key, 1024 bit long modulus
Затем создаем CSR-сертификат:
[root@test248 ~]# openssl req -new -key ca.key -out ca.csr
После чего нам зададут несколько вопросов:
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:RU
Locality Name (eg, city) []:Saint-Petersburg
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Test Co Ltd
Organizational Unit Name (eg, section) []:IT Department
Common Name (eg, YOUR name) []:test248.domain.com
Email Address []:itdepartment@domain.com

A challenge password []:Pa$$w0rd
An optional company name []:Test Co Ltd
Далее создаем самоподписанный сертификат:
[root@test248 ~]# openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
Signature ok
subject=/C=RU/ST=RU/L=Saint-Petersburg/O=Test Co Ltd/OU=IT Department/CN=test248.domain.com/emailAddress=itdepartment@domain.com
Getting Private key
Параметр: "-days 365" - количество дней, которые будет действовать сертификат

В итоге мы получили файл ca.crt, который мы можем использовать с, например, Apache или Dovecot для осуществления защищенных соединений с клиентами.

28 октября 2008 г.

Установка и настройка Exim 4.69

Задача: установить и настроить Exim 4.69 (последния в портах версия на момент написания статьи).
Итак, имеем FreeBSD 6.3:

[root@mail /var/mail]# uname -mrs
FreeBSD 6.3-RELEASE i386

Включаем/выключаем нужные опции (посмотреть весь список можно в Makefile).
.if ${.CURDIR} == ${PORTSDIR}/mail/exim
WITH_MYSQL=             yes
LOG_FILE_PATH?=         syslog
WITH_CONTENT_SCAN=      yes
WITH_DEFAULT_CHARSET?=  koi8-r
WITHOUT_IPV6=           yes
WITHOUT_NIS=            yes
.endif

[root@mail /usr/ports/mail/exim]# make install clean

В /etc/rc.conf прописываем следующие строки:
sendmail_enable="NONE"
exim_enable="YES"
Меняем файл /etc/mail/mailer.conf на следующий:
[root@cisco3 /etc/mail]# cat 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

Файл /usr/local/etc/exim/configure:

# Основное имя хоста
primary_hostname = mx1.domain.ru

# Параметры подключения к БД в формате "хост/имя_базы/пользователь/пароль"
hide mysql_servers = db_host/exim/exim/PASSWORD

# Список локальных доменов
domainlist local_domains = ${lookup mysql{SELECT domain FROM domain WHERE domain='${domain}' AND active='1'}}

# Список доменов/хостов, для которых хост является входящим релеем
domainlist relay_to_domains = ${lookup mysql{SELECT domain FROM domain WHERE domain='${domain}' AND active='1'}}
# Список доменов/хостов, для которых хост является исходящим релеем. Т.е. без авторизации. hostlist relay_from_hosts = localhost : 127.0.0.0/8 : 192.168.0.0/16

# Включаем ограничения (будут объявлены ниже, в секции ACL)
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data

# Пусть к сокету clamd (Предполагается что clamd уже установлен и настроен)
av_scanner = clamd:/var/run/clamav/clamd.sock


# Разрешаем всем клиентам использовать TLS
tls_advertise_hosts = *


# Пути к TLS-сертификату и приватному ключу
tls_certificate = /etc/mail/ca.crt
tls_privatekey = /etc/mail/ca.key

# Список портов, которых будем слушать
daemon_smtp_ports = 25 : 465 : 587
# 465 порт нужен если хотим принимать почту с почтовых серверов Microsoft с использованием TLS.
tls_on_connect_ports = 465

# Имя домена, добавляемое ко всем адресам, идущим без "@" и имени домена. Например, для системных пользователей.
qualify_domain = mx1.domain.ru

# Запрещаем принимать почту с адресов типа user@[10.11.12.13]
allow_domain_literals = false

# Пользователь и группа, от которой работает Exim
exim_user = mailnull
exim_group = mail
never_users = root

# Эта опция заставляет делать обратный DNS-запрос для каждого входящего IP-адреса. Могут быть проблемы с некоторыми почтовыми серверами.
#host_lookup = *


# На сколько задерживаем сообщение о доставке, если его не удалось доставить :)
ignore_bounce_errors_after = 2d


# Сколько хранить "замороженные" сообщения
timeout_frozen_after = 7d


# Опция повышает производительность разбивая директорию spool на поддиректории.
split_spool_directory = true


# Почта с этих хостов/доменов будет приниматься несмотря на ошибки в HELO/EHLO
helo_accept_junk_hosts = 192.168.0.0/16


# Через какое время повторять отправку "замороженных" сообщений
auto_thaw = 1h


# Максимальное число одновременных соединений
smtp_accept_max = 100


# Максимальное число сообщений, принимаемых за одну tcp-сессию
smtp_accept_max_per_connection = 50


# Максимальное число соединений с одного хоста/домена
smtp_accept_max_per_host = 20


# Максимальное число параллельных процессов доставки
remote_max_parallel = 15


# Ограничение на размер части письма, вкладываемого в сообщение об ошибке
return_size_limit = 150k


# Максимальный размер сообщения
message_size_limit = 30M


# Не писать дату и время в логи. В нашем случае их пишет syslogd
syslog_timestamp = no


# Описание тех самых ограничений, которые объявлены выше
begin acl
acl_check_rcpt:

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


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

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

# Разрешаем почту на postmaster без проверок 
accept local_parts   = postmaster
domains       = +local_domains

# Включаем проверку отправителя
require verify        = sender


# Запрещаем соединения с теми, кто не предоставляет приветствие по RFC (HELO/EHLO)
deny message       = "HELO/EHLO required by RFC"
condition     = ${if eq{$sender_helo_name}{}{yes}{no}}

# Разрешаем аутентифицированные соединения
accept  authenticated = *


# Запрещаем соединения с теми, кто подставляет в приветствие IP-адрес вместо имени
deny message       = "Do not put IP address in HELO!"
hosts         =  * : !+relay_from_hosts
condition     = ${if eq{$sender_helo_name}{$sender_host_address}{true}{false}}

# Запрещаем соединения с теми, кто подставляет IP-адрес нашего сервера в приветствии
deny condition     = ${if eq{$sender_helo_name}{$interface_address}{yes}{no}}
hosts         = !127.0.0.1 : !localhost : *
message       = "Do not put my IP address in HELO!"

# Запрещаем соединения с теми, у кого в приветствии только цифры
deny condition     = ${if match{$sender_helo_name}{\N^\d+$\N}{yes}{no}}
hosts         = !127.0.0.1 : !localhost : *
message       = "There is only numbers in HELO!"

# Запрещаем соединения с теми, у кого в имени хоста присутствуют adsl, dialup и т.д.
deny message       = "Bad hostname!"
condition     = ${if match{$sender_host_name}{adsl|dialup|pool|peer|dhcp}       {yes}{no}}

# Задержка установления соединения. Как один из методов борьбы со спамом.
 warn
set acl_m0 = 30s

# Убираем задержку для "своих" доменов/хостов
 warn
hosts = +relay_from_hosts
set acl_m0 = 0s

# Проверка на существование пользователей в локальных доменах
accept domains       = +local_domains
endpass
message       = "User unknown"
verify        = recipient

# Проверка на существование пользователей в релейных доменах
accept domains       = +relay_to_domains
endpass
message       = "Not routeable address"
verify        = recipient

# Если не подошло ни под одно правило - скорее всего ищут открытый релей
deny    message       = "There is no open relay"

acl_check_data:


# Запрещаем сообщения содержащие вирусы
deny malware    = *
message    = This message contains a virus ($malware_name).

# Принимаем сообщение
accept


begin routers


# Поиск маршрута к хосту в DNS
dnslookup:
driver = dnslookup
domains = ! +local_domains
transport = remote_smtp
ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
no_more

# Поиск алиасов
system_aliases:
driver      = redirect
allow_fail
allow_defer
data = ${lookup mysql{SELECT goto FROM alias WHERE address='${quote_mysql:$local_part@$domain}' OR address='${quote_mysql:@$domain}'}}

begin transports


# Включаем доставку по SMTP на удаленные хосты
remote_smtp:
driver = smtp

# Доставка до локальных получателей
mysql_delivery:
driver = appendfile
check_string = ""
create_directory
delivery_date_add
# Т.к. мы строим мультидоменный почтовый сервер, то и почта будет храниться в каталогах вида /var/mail/exim/domain.ru/user@domain.ru
directory = ${lookup mysql{SELECT CONCAT('/var/mail/exim/', `domain`, '/', `maildir`) FROM `mailbox` WHERE `username`='${local_part}@${domain}'}}
directory_mode = 770
envelope_to_add
group = mail
maildir_format
maildir_tag = ,S=$message_size
message_prefix = ""
message_suffix = ""
mode = 0600

address_pipe:
driver = pipe
return_output

address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add

# Транспорт для автоответов. Оставляем и надеемся в будущем настроить :)
address_reply:
driver = autoreply

begin retry

# Когда делать очередную попытку отправки недоставленных писем
*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h


begin rewrite

begin authenticators

# Описание типа аутентификации plain
PLAIN:
driver                     = plaintext
server_set_id              = $auth2
server_prompts             = :
server_condition           = ${lookup mysql{SELECT username FROM mailbox WHERE username = '${quote_mysql:$1}' AND password = '${quote_mysql:$2}'}{yes}{no}

#EOF

Далее создаем базу exim на локальном или удаленном хосте при помощи этого дампа (дамп с сайта lissyara.su):

# Не забудьте поменять занчения localhost, user, password на свои :)
-- 
-- БД: `exim`
-- 
USE mysql;
INSERT INTO `user` (`Host`, `User`, `Password`)
VALUES ('localhost','exim',password('exim'));
INSERT INTO `db` (`Host`, `Db`, `User`, `Select_priv`)
VALUES ('localhost','exim','exim','Y');
FLUSH PRIVILEGES;
GRANT USAGE ON exim.* TO exim@localhost;
GRANT SELECT, INSERT, DELETE, UPDATE ON exim.* TO exim@localhost;
CREATE DATABASE `exim`;
USE `exim`;
-- --------------------------------------------------------

-- 
-- Структура таблицы `alias`
-- 

CREATE TABLE `alias` (
  `address` varchar(255) NOT NULL default '',
  `goto` text NOT NULL,
  `domain` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`address`),
  KEY `address` (`address`)
) TYPE=MyISAM COMMENT='Aliases';
-- --------------------------------------------------------

-- 
-- Структура таблицы `domain`
-- 

CREATE TABLE `domain` (
  `domain` varchar(255) NOT NULL default '',
  `description` varchar(255) NOT NULL default '',
  `aliases` int(10) NOT NULL default '0',
  `mailboxes` int(10) NOT NULL default '0',
  `maxquota` int(10) NOT NULL default '0',
  `transport` varchar(255) default NULL,
  `backupmx` tinyint(1) NOT NULL default '0',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`domain`),
  KEY `domain` (`domain`)
) TYPE=MyISAM COMMENT='Domains';
-- --------------------------------------------------------

-- 
-- Структура таблицы `mailbox`
-- 

CREATE TABLE `mailbox` (
  `username` varchar(255) NOT NULL default '',
  `password` varchar(255) NOT NULL default '',
  `name` varchar(255) NOT NULL default '',
  `maildir` varchar(255) NOT NULL default '',
  `quota` int(10) NOT NULL default '0',
  `domain` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`username`),
  KEY `username` (`username`)
) TYPE=MyISAM COMMENT='Mailboxes';




Осталось заполнить таблицы базы и можно запускать Exim:
[root@mail ~]# /usr/local/etc/rc.d/exim start 

Итог: Установлен и настроен почтовый сервер Exim 4.69 с возможностью обслуживания множества доменов одновременно. Настроена проверка сообщений на вирусы с помощью clamav. Почта сохраняется в каталоги вида domain.ru/username@domain.ru. Все домены, пользователи и алиасы хранятся в БД MySQL.

Используемая литература:
  1. Documentation and FAQ http://www.exim.org/
  2. "Связка exim и dovecot с веб интерфейсом postfixadmin" http://www.lissyara.su/?id=1173

PS: Возможно что-то недописал или забыл. В ближайшее время отредактирую.