Настройка связки Postfix, Courier-Imap и LDAP

Леттиев Владимир Валерьевич
crux@syktsu.ru

  ·  Введение

 Целью данного HOW-TO является создание легко управляемой и масштабируемой почтовой системы, все записи о пользователях которой хранятся в LDAP.
 Описываемый процесс установки производился на Linux Mandrake 9.1. Сразу хотелось бы отметить, что поставляемые с этим дистрибутивом rpm-пакеты postfix'а и courier-imap'а не подойдут. К сожалению, после многих попыток было обнаружено, что настроить их на нормальную работу по данной схеме невозможно. Симптомы следующие: Postfix в логах ругался, что не может выложить почту в Maildir пользователя, якобы доступ на запись запрещён, а courier-imap в свою очередь всегда отказывал в доступе, ссылаясь на неправильный пароль. После установки postfix и courier-imap из сырцов с абсолютно той же конфигурацией вышеуказаные проблемы исчезли. Оставим это на совести сборщиков дистрибутива и перейдём к описанию процесса настройки.

  ·  OpenLDAP

 ~ Установка

 OpenLDAP был установлен из rpm'ов, поставляемых с дистрибутивом и был признан годным к употреблению. При желании можно было собрать также из сырцов, но так как данная сборка работала вполне корректно, то я оставил её как есть. В целом потребовались следующие пакеты:
  ·  openldap-2.0.27-5.3mdk
  ·  openldap-guide-2.0.27-5.3mdk
  ·  openldap-clients-2.0.27-5.3mdk
  ·  openldap-servers-2.0.27-5.3mdk
  ·  libldap2-2.0.27-5.3mdk
  ·  libldap2-devel-2.0.27-5.3mdk
  ·  libldap2-devel-static-2.0.27-5.3mdk


development-пакеты openldap потребуются при сборке postfix из сырцов.

 ~ Конфигурация

1. /etc/openldap/slapd.conf - конфигурационный файл сервиса slapd

       # Включите данные схемы
       include /usr/share/openldap/schema/core.schema
       include /usr/share/openldap/schema/cosine.schema
       include /usr/share/openldap/schema/corba.schema
       include /usr/share/openldap/schema/inetorgperson.schema
       include /usr/share/openldap/schema/nis.schema
       include /usr/share/openldap/schema/openldap.schema
       include /usr/share/openldap/schema/qmail.schema

       # Последняя схема была найдена среди исходников courier-imap, и я посчитал
       # необходимым включить её в slapd.conf.
       include /etc/openldap/schema/authldap.schema


       pidfile         /var/run/ldap/slapd.pid
       argsfile        /var/run/ldap/slapd.args

       modulepath      /usr/lib/openldap

       database        ldbm
       suffix          "dc=home,dc=ru"
       rootdn          "cn=root,dc=home,dc=ru"
       # Пароль rootpw лучше всего указывать в зашифрованном виде.
       # Для генерации шифрованного пароля используйте утилиту slappasswd
       # Например: slappaswd -h
       rootpw          6Q2kox8osDMVzi5zSKI6YQ==

       directory       /var/lib/ldap

       index   objectClass,uid,uidNumber,gidNumber     eq
       index   cn,mail,surname,givenname               eq,subinitial

       # logging
       loglevel 256

       # Basic ACL
       access to attr=userPassword
               by self write
               by anonymous auth
               by dn="cn=courier,ou=daemons,dc=home,dc=ru" read
               by * none

       access to attr=accountStatus
               by dn="cn=courier,ou=daemons,dc=home,dc=ru" read
               by dn="cn=postfix,ou=daemons,dc=home,dc=ru" read

       access to *
               by * read

 В принципе это основные моменты конфигурационного файла. Можно несколько усложнить конфигурацию: настроить более сложные правила доступа к LDAP-записям и т.д. Но это можно сделать позднее при необходимости. Главное, что текущей настройки достаточно для нормального запуска OpenLDAP. Если возникнут какие-либо проблемы, внимательно изучите логи, обычно там находится вся необходимая информация.
 Запускается ldap простой командой: service ldap start
 В сборке от Mandrake OpenLDAP запускается под непривелегированным пользователем ldap. Это следует учесть, если вы будете собирать OpenLDAP из сырцов, обязательно создайте пользователя и группу ldap, дайте этому пользователю права на запись в каталог /var/lib/ldap и запускайте демон slapd с параметрами: -u ldap -g ldap. Запускать slapd от суперпользователя, как говорит Григорий, "дурной тон"...

2. /etc/ldap.conf
       host 127.0.0.1
       base dc=home,dc=ru
       ldap_version 3
       rootbinddn cn=root,dc=home,dc=ru
       scope one
       pam_filter objectclass=posixAccount
       pam_login_attribute uid
       pam_member_attribute gid
       pam_password crypt
       nss_base_passwd ou=Users,dc=home,dc=ru?one
       nss_base_shadow ou=Users,dc=home,dc=ru?one
       ssl off

 Данный файл является конфигурацией ldap-клиента.

 ~ Добавление записей в LDAP

В LDAP будут хранится записи структуры каталога и пользовательских записей. Всё это можно представить в виде древовидной структуры:

dc=home,dc=ru-+
              |
              +- ou = users -+
              |              |
              |              +- uid = crux
              |
              +- ou = mailusers -+
              |                  |
              |                  +- uid = crux
              |
              +- ou = daemons -+
                               |
                               +- cn = postfix
                               |
                               +- cn = courier

 Т.е. имеется главный контейнер "home.ru". Далее выделяются контейнеры ou=users - где будут хранится описания пользователей (типа адресной книги), ou=mailusers - вся информация по почтовым пользователям (адреса, мыло, локальное хранилище почты и т.д.), ou=daemons - ldap-пользователи сервисов postfix и courier-imap (именно под данными пользователями указанные сервисы будут подключаться к ldap-серверу для получения необходимой им информации). В принципе, можно было обойтись без контейнера mailusers, а всю необходимую информацию включить в аттрибуты пользователей контейнера ou=users. Но в будущем мне может потребоваться помимо пользователей почты включить также пользователей Samba, Squid. При миграции аккаунтов возможны совпадения логинов различных пользователей, также для некоторых пользователей было бы желательно иметь различные пароли для разных сервисов. Поэтому такая схема (может быть некорректная с точки зрения теории) достаточно гибка и позволит мне без проблем проводить миграцию пользовательских учётных записей любых сервисов в LDAP.
 Переложим данную структуру в ldif-файлы:

Базовое дерево:

       #base.ldif
       dn: dc=home,dc=ru
       objectClass: dcObject
       dc: home

       dn: ou=Users,dc=home,dc=ru
       objectClass: organizationalUnit
       ou: Users
       description: Home Users

       dn: ou=mailusers, dc=home, dc=ru
       objectclass: top
       objectclass: organizationalunit
       ou: mailusers
       description: users with mailaccounts at my home.

       dn: ou=daemons, dc=home, dc=ru
       objectclass: top
       objectclass: organizationalunit
       ou: daemons
       description: daemons thats connect to LDAP

Добавим пользователей:

       #users.ldif
       dn: uid=crux,ou=Users,dc=home,dc=ru
       uid: crux
       cn: Lettiev V.V.
       cn: Vladimir Lettiev
       sn: Admin
       givenName: Vladimir
       title: Systems Administrator
       mail: crux@home.ru
       telephoneNumber: 24-55-07
       objectClass: Person
       objectClass: OrganizationalPerson
       objectClass: inetOrgPerson

       dn: uid=crux,ou=mailusers,dc=home,dc=ru
       uid: crux
       cn: Lettiev V.V.
       mail: Vladimir.Lettiev@home.ru
       mail: crux@home.ru
       mail: root@home.ru
       uidNumber: 1000
       gidNumber: 1000
       mailHost: mail.home.ru
       homeDirectory: /var/imap/home/crux
       mailMessageStore: /var/imap/home/crux/Maildir
       mailQuota: 200000000S, 20000C
       mailbox: crux/Maildir/
       objectClass: qmailuser
       objectClass: couriermailaccount
       userPassword: d+HKEvhLk8ZqwCRTrp574g==
       accountStatus: active
       mailForwardingAddress: crux@home.ru

       dn: cn=postfix,ou=daemons,dc=home,dc=ru
       objectClass: top
       objectClass: person
       cn: postfix
       sn: postfix
       userPassword: lT3u7UFC2hdWA

       dn: cn=courier,ou=daemons,dc=home,dc=ru
       objectClass: top
       objectClass: person
       cn: courier
       sn: courier
       userPassword: hjUyfu886SJhA

 Теперь необходимо записать эти данные в LDAP-каталог. Выполнятеся это следующей последовательностью команд:
# ldapadd -W -x -D "cn=root,dc=home,dc=ru" -f base.ldif
# ldapadd -W -x -D "cn=root,dc=home,dc=ru" -f users.ldif

Если всё прошло гладко и сообщений об ошибках не поступило, то можно переходить к следующему этапу.

  ·  Postfix

 MTA Postfix считается одним из самых безопасных, надёжным и простым в настройке почтовым сервисом. В данном примере используется версия 2.0.10.

 ~ Установка

 $ tar -xzf postfix-2.0.10.tar.gz
 $ cd postfix-2.0.10


Соберём makefiles с поддержкой LDAP ( devel-файлы LDAP должны находится в
/usr/include, а библиотеки в /usr/lib )

 $ make makefiles CCARGS="-I/usr/include -DHAS_LDAP" \
                  AUXLIBS="-L/usr/lib -lldap -L/usr/lib -llber"
 $ make

 Теперь надо создать пользователя postfix и группу postdrop (или убедится, что они уже есть)
 # groupadd postdrop
 # adduser -s /bin/false -G postdrop -d /var/spool/postfix postfix

 Теперь можно выполнить инсталляцию postfix
 # make install

 По ходу инсталяции будут задаваться вопросы, касаемые местоположения разных компонентов системы, фактически можно просто нажимать Enter, всё что предлагается по умолчанию вполне удобно.

 ~ Конфигурация

1. /etc/postfix/main.cf

       queue_directory = /var/spool/postfix
       command_directory = /usr/sbin
       daemon_directory = /usr/libexec/postfix
       mail_owner = postfix

       # Имя нашего MAIL хоста
       myhostname = mail.home.ru
       mydomain = home.ru
       myorigin = $mydomain

       inet_interfaces = all

       # Получать почту для доменов mail.home.ru и home.ru
       mydestination = $myhostname, $mydomain

       unknown_local_recipient_reject_code = 450

       # Сеть, которой мы доверяем
       mynetworks = 192.168.1.0/24, 127.0.0.0/8

       biff = no

       # Доставка для виртуальных доменов
       local_transport = virtual
       local_recipient_maps = $virtual_mailbox_maps
       message_size_limit = 10280000
       mailbox_size_limit = 20480000

       # Вся почта пользователей будет принадлежать одному пользователю
       # (например, vmail), с uid=1001 и gid=1001
       virtual_uid_maps = static:1001
       virtual_gid_maps = static:1001
       virtual_recipient_maps = ldap:ldapsource
       virtual_mailbox_size_limit = ldap:ldapquota
       virtual_minimum_uid = 500

       # Корневая папка, внутри которой будет хранится вся почта пользователей
       virtual_mailbox_base =/var/imap/home

       virtual_result_attribute = mailbox
       virtual_mailbox_maps = ldap:ldapsource
       virtual_maildir_extended = yes
       ldapquota_timeout = 10
       ldapquota_server_host = localhost
       ldapquota_search_base = ou=mailusers,dc=home,dc=ru
       ldapqouta_server_port = 389
       ldapqouta_domain = home.ru, mail.home.ru
       ldapquota_query_filter = (&(mail=%s)(accountstatus=active))
       ldapquota_result_attribute = mailquota

       # Параметры подключения к LDAP (юзер и пароль)
       ldapquota_bind = yes
       ldapquota_bind_dn = cn=postfix,ou=daemons,dc=home,dc=ru
       ldapquota_bind_pw = secretpass

       ldapsource_timeout = 10
       ldapsource_server_host = localhost
       ldapsource_search_base = ou=mailusers,dc=home,dc=ru
       ldapsource_server_port = 389
       ldapsource_domain = home.ru, mail.home.ru
       ldapsource_query_filter = (&(mail=%s)(accountstatus=active))
       ldapsource_result_attribute = mailbox

       # Параметры подключения к LDAP (юзер и пароль)
       ldapsource_bind = yes
       ldapsource_bind_dn = cn=postfix,dc=home,dc=ru
       ldapsource_bind_pw = secretpass

       alias_maps = hash:/etc/aliases
       alias_database = hash:/etc/aliases
       smtpd_banner = $myhostname ESMTP $mail_name ($mail_version) (Mandrake Linux)
       debug_peer_level = 4
       debugger_command =
                PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
                xxgdb $daemon_directory/$process_name $process_id & sleep 5
       delay_warning_time = 4
       sendmail_path = /usr/sbin/sendmail
       newaliases_path = /usr/bin/newaliases
       mailq_path = /usr/bin/mailq
       setgid_group = postdrop
       manpage_directory = /usr/local/man

 В данной конфигурации postfix будет доставлять почту виртуальным пользователям, т.е. фактически пользователи не существуют в системе, они присутствуют лишь в LDAP. Местоположение Maildir какалога определяется атрибутом mailbox пользователя. Вся почта пользователей будет принадлежать одному реальному пользователю vmail(uid=1001,gid=1001). Почтовая квота также определяется из атрибута пользователя mailQuota. Можно также было производить поиск alias'ов из LDAP-каталога, но в данном случае это излишне, потому что alias'ы прописываются пользователям в качестве дополнительных атрибутов mail.
 Можно проверить конфигурацию postfix (команда: postfix check), если же не появились сообщения об ошибках, то это значит, что всё ок и можно запустить Postfix (команда postfix start).

 ~ Тестирование

 Необходимо создать пользователя vmail и хранилище почты:

 # mkdir -p -m 0700 /var/imap/home
 # addgroup -g 1001 vmail
 # adduser -u 1001 -s /bin/false -d /var/imap/home vmail
 # chown -R vmail.vmail /var/imap

 А также создать Maildir-каталог пользователю crux
 # mkdir -m 0700 /var/imap/home/crux
 # maildirmake /var/imap/home/crux/Maildir
 # chown -R vmail.vmail /var/imap/home/crux


 Если у вас нет утилитки maildirmake, то это не проблема, под созданием  Maildir каталога, имеется ввиду создание каталогов:
 <userHomeDir>/Maildir
 <userHomeDir>/Maildir/cur
 <userHomeDir>/Maildir/new
 <userHomeDir>/Maildir/tmp

 Права на все каталоги - 0700.

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

Проверим отправку сообщений:
 $ mail -s "test  message" crux@home.ru
 Privet Crux
 .
 CC:

 Письмо отправилось. Замечательно, теперь необходимо настроить Courier-Imap для того чтобы пользователи смогли получать свою почту.

  ·  Courier-Imap

 Courier-Imap - это превосходный IMAP, POP3 сервер. Поддержка ldap встроена, и при компиляции он не требует devel-файлов OpenLDAP.

~ Установка

 $ tar xzf courier-imap-1.7.3.tar.gz
 $ cd courier-imap-1.7.3
 $ ./configure --prefix=/usr/local
 $ make
 $ make check
 # make install
 # make install-configure

 ~ Конфигурация

 1. /usr/local/etc/authdaemonrc

       authmodulelist="authldap"
       authmodulelistorig="authldap"
       daemons=5
       version=""
       authdaemonvar=/usr/local/var/authdaemon

 2. /usr/local/etc/authldaprc

       LDAP_SERVER             localhost
       LDAP_PORT               389
       LDAP_BASEDN             ou=mailaccounts,dc=home,dc=ru
       LDAP_BINDDN             cn=courier, ou=daemons, dc=home, dc=ru
       LDAP_BINDPW             supersecret
       LDAP_TIMEOUT            5
       LDAP_MAIL               mail
       LDAP_FILTER             (objectClass=CourierMailAccount)
       LDAP_GLOB_UID           vmail
       LDAP_GLOB_GID           vmail
       LDAP_HOMEDIR            homeDirectory
       LDAP_MAILDIR            mailMessageStore
       LDAP_DEFAULTDELIVERY    defaultDelivery
       LDAP_MAILDIRQUOTA       mailQuota
       LDAP_FULLNAME           cn
       LDAP_CRYPTPW            userPassword
       LDAP_DEREF              never
       LDAP_TLS                0

 3. /usr/local/etc/ipmapd

       ADDRESS=0
       PORT=143
       MAXDAEMONS=40
       MAXPERIP=4
       PIDFILE=/var/run/imapd.pid
       TCPDOPTS="-nodnslookup -noidentlookup"
       AUTHMODULES="authdaemon"
       AUTHMODULES_ORIG="authdaemon"
       DEBUG_LOGIN=0
       IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT \
         THREAD=REFERENCES SORT QUOTA IDLE"
       IMAP_CAPABILITY_ORIG="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT \
         THREAD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 IDLE"
       IMAP_IDLE_TIMEOUT=60
       IMAP_CAPABILITY_TLS="$IMAP_CAPABILITY AUTH=PLAIN"
       IMAP_CAPABILITY_TLS_ORIG="$IMAP_CAPABILITY_ORIG AUTH=PLAIN"
       IMAP_DISABLETHREADSORT=0
       IMAP_CHECK_ALL_FOLDERS=0
       IMAP_OBSOLETE_CLIENT=0
       IMAP_ULIMITD=65536
       IMAP_USELOCKS=0
       IMAP_ENHANCEDIDLE=0
       IMAP_TRASHFOLDERNAME=Trash
       IMAP_EMPTYTRASH=Trash:7
       IMAP_MOVE_EXPUNGE_TO_TRASH=0
       SENDMAIL=/usr/sbin/sendmail
       HEADERFROM=X-IMAP-Sender
       IMAPDSTART=YES

 4. /usr/local/etc/pop3d

       PIDFILE=/var/run/pop3d.pid
       MAXDAEMONS=40
       MAXPERIP=4
       AUTHMODULES="authdaemon"
       AUTHMODULES_ORIG="authdaemon"
       DEBUG_LOGIN=0
       POP3AUTH=""
       POP3AUTH_ORIG="LOGIN CRAM-MD5 CRAM-SHA1"
       POP3AUTH_TLS=""
       POP3AUTH_TLS_ORIG="LOGIN PLAIN"
       PORT=110
       ADDRESS=0
       TCPDOPTS="-nodnslookup -noidentlookup"
       POP3DSTART=YES

 ~ Запуск

 Для того чтобы запустить IMAP и POP3 сервисы, воспользуйтесь следующими
командами:
       # /usr/local/libexec/imapd.rc start
       # /usr/local/libexec/pop3d.rc start

 Следует отметить, что если вы отключаете какой-либо из этих двух сервисов, то второй тоже должен быть отстановлен, т.к. скрипты запуска сделаны таким образом, что они запускают или останавливают сервис authdaemon.ldap и если один из сервисов остановить, то будет остановлен и authdaemon.ldap, соотвественно оставшийся сервис (скажем pop3) не сможет обрабатывать запросы, т.к. не сможет подключиться к authdaemon.ldap.

Теперь можно проверить почтовый ящик crux@home.ru.
 $ telnet localhost 110
 Trying 127.0.0.1...
 Connected to localhost (127.0.0.1).
 Escape character is '^]'.
 +OK Hello there.
 user crux@home.ru
 +OK Password required.
 pass mysuperpass
 +OK logged in.
 list
 +OK POP3 clients that break here, they violate STD53.
 1 374
 .
 quit
 +OK Bye-bye.
 Connection closed by foreign host.

 Как видно письмо присутствует в ящике. Также следует отметить, что в качестве логина использовался не "crux", а crux@home.ru. Т.к. в качестве атрибута пользователя, по которому ведётся поиск в LDAP используется "mail", если бы в параметре LDAP_MAIL файла authldaprc мы поставили бы атрибут "uid", то в таком случае логин был бы просто "crux". Но представьте себе ситуацию, когда у вас есть почтовые адреса admin@mail.home.ru и admin@net.home.ru и они принадлежат двум разным людям, то если использовать в качестве логина пользователя его uid, то можем получить, например, что первый admin будет входить под логином admin1, a другой под admin2 - что неочевидно (исходя из названия мыла), да и не очень удобно.

 Пожалуй это всё. Если есть вопросы или вы обнаружили ошибки, пишите на crux@syktsu.ru

  ·  Использованные источники

1. LDAP for Postfix with Courier IMAP / T. Knab, http://annapolislinux.org/docs/plc/postfix-cour… /
2. ldap, postfix and courier-imap howto / J.Vriesman, http://jeroen.protheus.com/postfix-courier-ldap… /
3. LDAP_README, VIRTUAL_README (документация по Postfix) / http://www.postfix.org /