Почтовая система Exim + Cyrus + OpenLDAP на FreeBSD
Материал из BiTel WiKi
Необходимые для настройки системы скрипт и LDAP схему вы можете загрузить взять из этого архива Медиа:email_exim_cyrus.zip.
1.1. ставим cyrus-sasl-2.1.20. никаких особых телодвижений не нужно. рекомендую отключить ненужные механизмы аутентификации. во freebsd для этого нужно положить в каталог /usr/ports/security/cyrus-sasl2 файл sys.mk со следующим содержимым:
WITHOUT_OTP=yes WITH_DEV_URANDOM=yes WITHOUT_GSSAPI=yes
настроек никаких пока не надо.
1.2. ставим openldap-server-2.2.26 (и зависимости) с поддержкой sasl. во freebsd этот порт находится в каталоге /usr/ports/net/openldap22-sasl-server 1.3. ставим cyrus-imapd-2.2.12. во freebsd этот порт находится в каталоге /usr/ports/mail/cyrus-imapd22. тоже все по умолчанию. 1.4. ставим exim-4.51. в каталоге /usr/ports/mail/exim. я добавил следующие опции при сборке (файл sys.mk в каталоге порта):
WITH_CONTENT_SCAN= yes WITHOUT_IPV6= yes WITH_OPENLDAP= yes WITH_OPENLDAP_VER= 22 WITH_DEFAULT_CHARSET= KOI8-R WITH_AUTH_SASL= yes
собственно для почтовой системы ничего больше не нужно. для скрипта, который будет создавать/удалять ящики и ставить квоты, нужны будут перловые порты p5-perl-ldap-0.33 и p5-Authen-SASL-2.09 со всеми зависимостями.
сейчас на машине supermail установлены следующие пакеты (некоторые ставились как зависимости):
=== cut === autoconf-2.13.000227_5 Automatically configure source code on many Un*x platforms autoconf-2.59_2 Automatically configure source code on many Un*x platforms automake-1.4.6_1 GNU Standards-compliant Makefile generator (legacy version automake-1.9.5 GNU Standards-compliant Makefile generator (version 1.9) bash-3.0.16_1 The GNU Project's Bourne Again SHell cidr-2.3.2 RFC 1878 subnet calculator / helper cvsup-without-gui-16.1h_2 General network file distribution system optimized for CVS cyrus-imapd-2.2.12 The cyrus mail server, supporting POP3 and IMAP4 protocols cyrus-sasl-2.1.20_1 RFC 2222 SASL (Simple Authentication and Security Layer) cyrus-sasl-saslauthd-2.1.20_1 SASL authentication server for cyrus-sasl2 db42-4.2.52_4 The Berkeley DB package, revision 4.2 exim-4.51 High performance MTA for Unix systems on the Internet expat-1.95.8_1 XML 1.0 parser written in C gettext-0.14.1 GNU gettext package glib-2.6.4 Some useful routines of C programming (current stable versi gmake-3.80_2 GNU version of 'make' utility help2man-1.35.1 Automatically generating simple manual pages from program o kav4freebsd-5.x-5.0.5 Summary: kav4freebsd libiconv-1.9.2_1 A character set conversion library libslang-1.4.9 Routines for rapid alpha-numeric terminal applications deve libtool-1.3.5_2 Generic shared library support script (version 1.3) libtool-1.5.10_1 Generic shared library support script (version 1.5) lynx-2.8.5 A non-graphical, text-based World-Wide Web client m4-1.4.3 GNU m4 makedepend-2000.12.28 A dependency generator for makefiles mc-4.6.0_15 Midnight Commander, a free Norton Commander Clone mime-support-3.33.1 MIME Media Types list mutt-1.4.2.1_2 The Mongrel of Mail User Agents (part Elm, Pine, Mush, mh, mysql-client-4.0.24_1 Multithreaded SQL database (client) mysql-server-4.0.24_1 Multithreaded SQL database (server) nspr-4.4.1_1 A platform-neutral API for system level and libc like funct openldap-sasl-client-2.2.26 Open source LDAP client implementation with SASL2 support openldap-sasl-server-2.2.26 Open source LDAP server implementation with SASL2 support p5-Authen-SASL-2.09 Perl5 module for SASL authentication p5-Convert-ASN1-0.18 Perl5 module to encode and decode ASN.1 data structures p5-IO-Socket-SSL-0.96 Perl5 interface to SSL sockets p5-Net-SSLeay-1.25 Perl5 interface to SSL p5-URI-1.35 Perl5 interface to Uniform Resource Identifier (URI) refere p5-XML-NamespaceSupport-1.08 A simple generic namespace support class p5-XML-SAX-0.12 Simple API for XML p5-gettext-1.03 Message handling functions p5-perl-ldap-0.33 A Client interface to LDAP servers perl-5.8.6_2 Practical Extraction and Report Language pkgconfig-0.17.2 A utility to retrieve information about installed libraries popt-1.7 A getopt(3) like library with a number of enhancements, fro portupgrade-20041226_2 FreeBSD ports/packages administration and management tool s ruby-1.8.2_3 An object-oriented interpreted scripting language ruby18-bdb1-0.2.2 Ruby interface to Berkeley DB revision 1.8x with full featu trafshow-3.1_5,1 Full screen visualization of network traffic unarj-2.65_1 Allows files to be extracted from ARJ archives unrar-3.43,3 Extract, view & test RAR archives unzip-5.52_1 List, test and extract compressed files in a ZIP archive vim-lite-6.3.62 Vi "workalike", with many additional features (Lite package zip-2.3_2 Create/update ZIP files compatible with pkzip === cut ===
когда все установлено, приступаем к настройке.
2.1 настраиваем openldap.
сначала кладем в /usr/local/etc/openldap/schema файл со схемой (vmail.schema), затем правим /ust/local/etc/openldap/slapd.conf. у меня получилось примерно так:
=== cut === include /usr/local/etc/openldap/schema/core.schema include /usr/local/etc/openldap/schema/cosine.schema include /usr/local/etc/openldap/schema/nis.schema include /usr/local/etc/openldap/schema/vmail.schema pidfile /var/run/openldap/slapd.pid argsfile /var/run/openldap/slapd.args access to * by self write by users read by anonymous auth by dn="cn=ldapadmin,dc=ufamail,dc=ru" write by dn="cn=mta,dc=ufamail,dc=ru" read database bdb suffix "dc=ufamail,dc=ru" rootdn "cn=ldapadmin,dc=ufamail,dc=ru" rootpw {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx directory /var/db/openldap-data index objectClass eq index cn,sn pres,eq,approx,sub index mailBox eq index status eq index uidNumber eq index gidNumber eq password-hash {CLEARTEXT} sasl-authz-policy to sasl-regexp uidNumber=(.*)\\+gidNumber=(.*),cn=peercred,cn=external,cn=auth ldap:///dc=ufamail,dc=ru??sub?(&(uidNumber=$1)(gidNumber=$2)) sasl-regexp uid=(.*@.*),cn=external,cn=auth ldap:///dc=ufamail,dc=ru??sub?(&(mailBox=$1)(status=enabled)) sasl-regexp uid=(.*),cn=external,cn=auth ldap:///dc=ufamail,dc=ru??sub?(|(cn=$1)(&(mailBox=$1@ufanet.ru)(status=enabled))) === cut ===
последние строчки нужны для того, чтобы работала т.н. proxy authorization. подробнее читать в документации на openldap и cyrus sasl.
теперь нужно добавить в базу данных ldap пользователей, кторые будут служебными. это, во-первых, пользователь от имени которого работает cyrus, во-вторых, пользователь от имени которого работает mta (exim). нужно это для того, чтобы и cyrus imapd, и exim могли успешно аутентифицировать пользователей.
Создать файл root.ldif с содержанием:
dn: dc=ufamail,dc=ru objectClass: dcObject objectClass: organization o: ufamail dc: ufamail dn: cn=cyrus,dc=ufamail,dc=ru cn: cyrus sn: cyrus uid: cyrus homeDirectory: /usr/local/cyrus objectClass: person objectClass: posixAccount saslAuthzTo: dn.regex:mailbox=.* saslAuthzTo: dn.regex:cn=.*,dc=ufamail,dc=ru saslAuthzTo: dn.regex:uid=.*,cn=external,cn=auth uidNumber: 60 gidNumber: 60 dn: cn=mta,dc=ufamail,dc=ru cn: mta sn: mta uid: mailnull userPassword: xxxxxxxxxxxxx homeDirectory: /var/spool/mqueue objectClass: person objectClass: posixAccount saslAuthzTo: dn.regex:mailbox=.* saslAuthzTo: dn.regex:cn=.*,dc=ufamail,dc=ru saslAuthzTo: dn.regex:uid=.*,cn=external,cn=auth uidNumber: 26 gidNumber: 6 dn: mailBox=admin@ufanet.ru,dc=ufamail,dc=ru mailBox: admin@ufanet.ru status: enabled objectClass: mailAccount userPassword: xxxxxxxxxxxxx
Потом добавить корневую запись:
ldapadd -x -D "cn=ldapadmin,dc=ufamail,dc=ru" -W -f root.ldif
спросит пароль на rootpw из конфига slapd.conf и потом добавит корень.
вот примерное содержимое базы после добавления в нее нужных записей (выводит программа slapcat):
=== cut === dn: dc=ufamail,dc=ru objectClass: dcObject objectClass: organization o: ufamail dc: ufamail dn: cn=cyrus,dc=ufamail,dc=ru cn: cyrus sn: cyrus uid: cyrus homeDirectory: /usr/local/cyrus objectClass: person objectClass: posixAccount saslAuthzTo: dn.regex:mailbox=.* saslAuthzTo: dn.regex:cn=.*,dc=ufamail,dc=ru saslAuthzTo: dn.regex:uid=.*,cn=external,cn=auth uidNumber: 60 gidNumber: 60 dn: cn=mta,dc=ufamail,dc=ru cn: mta sn: mta uid: mailnull userPassword: xxxxxxxxxxxxx homeDirectory: /var/spool/mqueue objectClass: person objectClass: posixAccount saslAuthzTo: dn.regex:mailbox=.* saslAuthzTo: dn.regex:cn=.*,dc=ufamail,dc=ru saslAuthzTo: dn.regex:uid=.*,cn=external,cn=auth uidNumber: 26 gidNumber: 6 dn: mailBox=admin@ufanet.ru,dc=ufamail,dc=ru mailBox: admin@ufanet.ru status: enabled objectClass: mailAccount userPassword: xxxxxxxxxxxxx === cut ===
обратите внимание на следующие вещи:
1. у пользователя cyrus нет пароля. это и не нужно, т.к. cyrus использует т.н. external mech при аутентификации пользователя (подробности см. в документации). в принципе, exim тоже использует external mech при аутентификации, но кроме аутентификации exim еще и иногда делает выборки (lookups) в базе данных ldap, а для этого уже нужно bind'иться к ней с паролем.
2. uidNumber и gidNumber взяты не с потолка, а соответствуют uid и gid от которых работают cyrus imapd и exim. без этого не будет работать proxy authz
3. мы добавили еще обычный аккаунт admin@ufanet.ru. это наш будущий администратор cyrus imapd, который будет управлять созданием/удалением почтовых ящиков и установкой квот.
после того как база создана можно попробовать, как работает связка openldap+sasl:
# su -m cyrus >> ldapwhoami -v -Y EXTERNAL -U cyrus -H ldapi:// SASL/EXTERNAL authentication started SASL username: uidNumber=60+gidNumber=60,cn=peercred,cn=external,cn=auth SASL SSF: 0 dn:cn=cyrus,dc=ufamail,dc=ru >> ldapwhoami -Y EXTERNAL -H ldapi:// -X u:admin@ufanet.ru SASL/EXTERNAL authentication started SASL username: u:admin@ufanet.ru SASL SSF: 0 dn:mailBox=admin@ufanet.ru,dc=ufamail,dc=ru если что-то не так, в первую очередь нужно проверить права на сокет /var/run/openldap/ldapi. они должны быть примерно такими: >> ls -l /var/run/openldap/ldapi srwxrwxrwx 1 ldap ldap 0 May 23 12:41 /var/run/openldap/ldapi для того, чтобы этого добиться, я запускаю slapd с такими параметрами в /etc/rc.conf: >> grep slapd /etc/rc.conf slapd_enable="YES" slapd_flags='-4 -h "ldap:/// ldapi:///"' slapd_sockets="/var/run/openldap/ldapi" slapd_sockets_mode="777"
после того, как работоспособность связки openldap - cyrus-sasl проверена, приступаем к настройке cyrus-imapd. для начала нужно собрать плагин ldapdb. берут его в исходниках openldap либо в свежих (с cvs-сервера) исходниках cyrus-sasl. разница в том, что в первом случае придется приложить больше усилий для сборки.
о том, как собрать под Linux, есть соответствующий README в каталоге с плагином. для сборки под FreeBSD выполните:
cd /usr/ports/security/cyrus-sasl2-ldapdb ; make install clean
собрав плагин, положите получившиеся файлы в /usr/local/lib/sasl2 (или где там у вас лежат плагины от cyrus-sasl):
>> ls -l /usr/local/lib/sasl2/| grep ldapdb -rw-r--r-- 1 root wheel 14116 Apr 28 22:44 libldapdb.a lrwxr-xr-x 1 root wheel 14 Apr 28 22:16 libldapdb.so -> libldapdb.so.2 -rwxr-xr-x 1 root wheel 18719 Apr 28 22:44 libldapdb.so.2
теперь настроим cyrus-imapd. для этого внесем следующие директивы в /usr/local/etc/imapd.conf (правьте под себя!):
=== cut === pass8bit: yes defaultdomain: ufanet.ru lmtp_downcase_rcpt: yes unix_group_enable: no virtdomains: yes servername: imap.ufamail.ru allowanonymouslogin: no allowplaintext: yes quotawarn: 90 timeout: 30 imapidlepoll: 60 imapidresponse: no poptimeout: 10 popminpoll: 0 admins: admin admin@ufanet.ru admin@ufamail.ru autocreatequota: 0 plaintextloginpause: 1 singleinstancestore: yes reject8bit: no sieveusehomedir: false sievedir: /var/imap/sieve annotation_db: skiplist duplicate_db: berkeley-nosync mboxlist_db: skiplist ptscache_db: berkeley seenstate_db: skiplist subscription_db: flat tlscache_db: berkeley-nosync sasl_pwcheck_method: auxprop sasl_auxprop_plugin: ldapdb sasl_ldapdb_uri: ldapi:// sasl_ldapdb_mech: EXTERNAL tls_cert_file: /usr/local/etc/ufamail.pem tls_key_file: /usr/local/etc/ufamail.pem tls_ca_file: /usr/local/etc/ufamail.pem === cut ===
последние три строчки - пусть к самоподписанному сертификату. нужны для того, чтобы можно было забирать почту по ssl/tls. о том, как создать самоподписанный сертификат, почитайте в документации на openssl. желательно сразу добавить в сертификат все имена, под которыми сервер будет известен клиентам. например:
smtp.ufanet.ru smtp.ufamail.ru imap.ufanet.ru imap.ufamail.ru
сделав все настройки и действия, описанные в документации на cyrus-imapd, запускаем его и проверяем работоспособность:
>> imtest -a admin@ufanet.ru localhost S: * OK imap.ufamail.ru Cyrus IMAP4 v2.2.12 server ready C: C01 CAPABILITY S: * CAPABILITY IMAP4 IMAP4rev1 ACL QUOTA LITERAL+ MAILBOX-REFERRALS NAMESPACE UIDPLUS ID NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY SORT THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE IDLE STARTTLS AUTH=NTLM AUTH=DIGEST-MD5 AUTH=CRAM-MD5 SASL-IR S: C01 OK Completed C: A01 AUTHENTICATE NTLM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx S: + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Please enter your password: C: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx S: A01 OK Success (no protection) Authenticated. Security strength factor: 0
с помощью ключа -m проверьте все механизмы аутентификации, которые вы предполагаете использовать на сервере. я рекомендую как минимум такие: plain, login, cram-md5, digest-md5, ntlm
если все работает, приступаем к настройке exim. после редактирования у меня получился вот такой файл конфигурации (сравните с умолчальным):
=== cut === domainlist local_domains = @ domainlist virt_domains = ufamail.ru domainlist our_domains = +local_domains : +virt_domains domainlist relay_to_domains = hostlist relay_from_hosts = localhost acl_smtp_rcpt = acl_check_rcpt acl_smtp_mail = acl_delay_mail_from acl_smtp_data = acl_content_scan exim_user = mailnull exim_group = mail never_users = root rfc1413_query_timeout = 0s ignore_bounce_errors_after = 2d timeout_frozen_after = 7d daemon_smtp_ports = 25 : 465 allow_mx_to_ip = no auto_thaw = 2h bounce_return_body = yes bounce_return_size_limit = 50K bounce_sender_authentication = mailer-daemon@ufamail.ru delay_warning = 2h:8h:365d errors_reply_to = postmaster@ufamail.ru helo_accept_junk_hosts = 192.168.168.0/22 : 81.30.192.0/19 message_size_limit = 10M pipelining_advertise_hosts = : queue_run_max = 10 recipients_max = 100 smtp_accept_max = 500 smtp_accept_max_per_connection = 20 smtp_accept_queue_per_connection = 100 smtp_banner = $smtp_active_hostname ESMTP server ready smtp_connect_backlog = 100 smtp_enforce_sync = yes tls_advertise_hosts = * tls_certificate = /usr/local/etc/ufamail.pem tls_on_connect_ports = 465 received_header_text = Received: \ ${if def:sender_rcvhost {from $sender_rcvhost\n\t}\ {${if def:sender_ident {from $sender_ident }}\ ${if def:sender_helo_name {(helo=$sender_helo_name)\n\t}}}}\ ${if def:authenticated_id {authenticated as $authenticated_id\n\t}}\ by $primary_hostname \ ${if def:received_protocol {with $received_protocol}} \ ${if def:tls_cipher {($tls_cipher)\n\t}}\ (Exim $version_number)\n\t\ id $message_id\ ${if def:received_for {\n\tfor $received_for}} smtp_accept_max_per_host = \ ${lookup{$sender_host_address}iplsearch*\ {/usr/local/etc/exim/maxconnects}{$value}{5}} av_scanner = aveserver:/var/run/aveserver spool_directory = /storage/spool/exim begin acl acl_delay_mail_from: accept authenticated = * delay = 0s accept delay = ${lookup{$sender_host_address} iplsearch*{/usr/local/etc/exim/delayhosts}{$value}{1m}} acl_content_scan: deny message = This message contains malware ($malware_name) malware = */defer_ok accept acl_check_rcpt: accept hosts = : deny message = Restricted characters in address domains = +our_domains local_parts = ^[.] : ^.*[@%!/|] deny message = Restricted characters in address domains = !+our_domains local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./ accept local_parts = postmaster : abuse domains = +our_domains require verify = sender/callout=30s,connect=5s deny message = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text dnslists = list.dsbl.org : dnsbl.njabl.org : dul.dnsbl.sorbs.net : bl.spamcop.net : relays.ordb.org accept domains = +our_domains endpass verify = recipient accept domains = +relay_to_domains endpass verify = recipient accept hosts = +relay_from_hosts accept authenticated = * deny message = relay not permitted begin routers dnslookup: driver = dnslookup domains = ! +our_domains transport = remote_smtp ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 : 192.168.0.0/16 : 172.16.0.0/12 : 10.0.0.0/8 : 224.0.0.0/4 no_more system_aliases: domains = +local_domains driver = redirect allow_fail allow_defer data = ${lookup{$local_part}lsearch{/etc/aliases}} user = mailnull group = mail file_transport = address_file pipe_transport = address_pipe userforward: driver = redirect domains = +local_domains check_local_user file = $home/.forward no_verify no_expn check_ancestor file_transport = address_file pipe_transport = address_pipe reply_transport = address_reply condition = ${if exists{$home/.forward} {yes} {no} } localuser: driver = accept domains = +local_domains check_local_user transport = local_delivery cannot_route_message = Unknown user ldap_aliases: driver = redirect domains = +virt_domains allow_fail allow_defer hide data = ${lookup ldap { \ user="cn=mta,dc=ufamail,dc=ru" \ pass=${quote:XXXXXXXXX} \ ldapi:///dc=ufamail,dc=ru\ ?forward?sub?\ (&(mailBox=${quote_ldap:$local_part@$domain})\ (status=enabled)(objectclass=mailAccount))\ }\ {$value} fail} file_transport = address_file pipe_transport = address_pipe ldap_user: driver = accept domains = +virt_domains hide local_parts = ldap;\ user="cn=mta,dc=ufamail,dc=ru" \ pass=${quote:XXXXXXXX} \ ldapi::///dc=ufamail,dc=ru\ ?mailBox?sub?\ (&(mailBox=${quote_ldap:$local_part@$domain})\ (status=enabled)(objectclass=mailAccount)) transport = cyrus_delivery cannot_route_message = Unknown user begin transports remote_smtp: driver = smtp local_delivery: driver = appendfile file = /var/mail/$local_part delivery_date_add envelope_to_add return_path_add group = mail user = $local_part mode = 0660 no_mode_fail_narrower address_pipe: driver = pipe return_output address_file: driver = appendfile delivery_date_add envelope_to_add return_path_add address_reply: driver = autoreply cyrus_delivery: driver = lmtp batch_max = 20 user = cyrus socket = /storage/imap/socket/lmtp begin retry * * F,2h,15m; G,16h,1h,1.5; F,4d,6h begin rewrite begin authenticators plain: driver = cyrus_sasl public_name = PLAIN server_set_id = $1 login: driver = cyrus_sasl public_name = LOGIN server_set_id = $1 cram_md5: driver = cyrus_sasl public_name = CRAM-MD5 server_set_id = $1 ntlm: driver = cyrus_sasl public_name = NTLM server_set_id = $1 === cut ===
основные исправления здесь - роутеры ldap_aliases, ldap_user и authenticator'ы plain, login, cram-md5 и ntlm -- Best regards, damir mailto:boco@ufanet.ru