Почтовая система 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
