# $Id: cyrus-sendmail.howto.txt,v 1.5 2007/05/10 09:24:32 aost Exp $ Настройка виртуальных почтовых доменов на базе cyrus-imap и sendmail (FreeBSD 5.X). 1. Исходная задача. На работающем сервере, где уже имеются почтовые ящики с живыми POP3 клиентами и штатными мейлбоксами (базовая почтовая система FreeBSD), развернуть imap сервер и виртуальные домены на нем. Старые клиенты продолжают пользоваться своими старыми ящиками. Сделать это желательно не прибегая к изменению исходного кода используемых программ. Чтобы старые и новые пользователи не мешали друг другу при получении почты по POP3 - новые пользователи с виртуальными доменами ходят только по протоколам pop3s или imap. 2. Установка необходимого программного обеспечения. Sendmail - поставляется и обновляется вместе с операционной системой. $ sendmail -d0.1 -bv cyrus Version 8.13.3 Compiled with: DNSMAP LOG MAP_REGEX MATCHGECOS MILTER MIME7TO8 MIME8TO7 NAMED_BIND NETINET NETUNIX NEWDB NIS PIPELINING SASLv2 SCANF STARTTLS TCPWRAPPERS USERDB XDEBUG Особенности сборки sendmail описаны в /etc/make.conf или в соответствующем файле из дерева исходных текстов: # $FreeBSD: src/share/examples/etc/make.conf,v 1.229.2.12 2005/03/07 20:39:34 phk Exp $ # Setting the following variables modifies the build environment for # sendmail and its related utilities. For example, SASL support can be # added with settings such as: # with SASLv2: SENDMAIL_CFLAGS=-I/usr/local/include -DSASL=2 SENDMAIL_LDFLAGS=-L/usr/local/lib SENDMAIL_LDADD=-lsasl2 Пересборка sendmail-a отдельно от "world" делается следующими командами: cd /usr/src/usr.sbin/sendmail # make clean && make obj # make depend && make && make install ...... или более полный вариант: cd /usr/src/lib/libsm && make obj depend all cd /usr/src/lib/libsmutil && make obj depend all cd /usr/src/usr.sbin/sendmail && make obj depend all install ...... Cyrus-imap - устанавливается из портов и попутно ставит cyrus-sasl cyrus-imapd-2.2.12_1 The cyrus mail server, supporting POP3 and IMAP4 protocols cyrus-sasl-2.1.21 RFC 2222 SASL (Simple Authentication and Security Layer) 3. Конфигурация Cyrus Практически не отличается от того, что рекомендовано в документации. ==== imapd.conf ==== # altnamespace: yes servername: host.base-domain.ru (здесь и далее названия вымышленные) admins: superadmin admin@virt-domain.ru # # собственно включение поддержки виртуальных доменов # если не хочется биться с резольвингом обратной зоны - ставим userid virtdomains: userid defaultdomain: base-domain.ru # # _две_ директивы для некодированных в MIME русских Subject-ов #reject8bit: no munge8bit: no pass8bit: yes # # sasl авторизация sasl_pwcheck_method: auxprop sasl_auxprop_plugin: sasldb # ==== imapd.conf ==== Сертификаты для cyrus-а генерируем примерно таким скриптом: ==== cyrus_create_cert.sh ==== #!/bin/sh # # Генерируем сертификаты (в процессе нужно будет заполнить несколько # полей информацией об организации): # IMAP_KEYPATH="/var/imap/server.pem.new" # openssl req -new -x509 -nodes -out ${IMAP_KEYPATH} -keyout ${IMAP_KEYPATH} -days 365 # chown cyrus:mail ${IMAP_KEYPATH} # openssl x509 -noout -text -in ${IMAP_KEYPATH} # # Вышеприведенной командой мы создали X.509 сертификат, действительный 1 # год (эта строчка для генерации есть в документации к cyrus-imapd). За # более подробной информацией по поводу сертификатов и openssl в общем # можно сходить на http://www.openssl.org/ в раздел документации, # ==== cyrus_create_cert.sh ==== Если все устраивает, то переименовываем server.pem.new в server.pem и пускаем в работу. В основном, при генерации сертификатов надо обращать внимание на примерно такую строчку: "serial:BB:2E:DD:AF:3E...", на одной из машин этот serial, при генерации ключей, почему-то упорно был равен нулю - с таким ключом cyrus работать не захотел. Если используется серверный сертификат, подписанный кем-то сторонним - то сертификат подписывающей организации так же должен присутствовать в файле сертификатов (server.pem), иначе "лучший мейлер всех времен и народов" - thebat! - отказывается работать с таким сервером, куда бы мы ему эти сертификаты не засовывали локально. ==== cyrus.conf ==== # # Проследить, чтобы было раскомментировано # lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=0 ==== cyrus.conf ==== Конфигурационные файлы готовы, остается запустить описанную в документации процедуру создания базы(partition) Cyrus-а, и можно стартовать master-процесс, который слушает указанные в cyrus.conf порты. Sendmail Для работы sendmail по SSL генерим ключи и указываем пути к ним в конфиге. ==== /etc/mail/certs/create_cert.sh ==== #!/bin/sh # # openssl req -new -x509 -keyout cakey.pem -out cacert.pem -days 365 # openssl req -nodes -new -x509 -keyout sendmail.pem -out sendmail.pem -days 365 # openssl x509 -noout -text -in sendmail.pem # chmod 600 ./sendmail.pem # ==== /etc/mail/certs/create_cert.sh ==== Файл `hostame`.mc - для работы сендмейла через SSL/TLS добавлены следующие строчки: dnl ### do SMTPAUTH define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5')dnl TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5')dnl если надо, чтобы работали пользователи с outlook-ами - то в методы надо добавить LOGIN, PLAIN. dnl ### do STARTTLS define(`confCACERT_PATH', `/etc/mail/certs')dnl define(`confCACERT', `/etc/mail/certs/cacert.pem')dnl define(`confSERVER_CERT', `/etc/mail/certs/sendmail.pem')dnl define(`confSERVER_KEY', `/etc/mail/certs/sendmail.pem')dnl define(`confCLIENT_CERT', `/etc/mail/certs/sendmail.pem')dnl define(`confCLIENT_KEY', `/etc/mail/certs/sendmail.pem')dnl DAEMON_OPTIONS(`Family=inet, Addr=XXX.XXX.XXX.XXX, Port=465, Name=MTA-SSL, M=s')dnl - добавлен новый мейлер cyrusv2, но не объявлен локальным доставщиком почты. Дело в том, что старые пользователи должны продолжать пользоваться своими почтовыми ящиками по старой схеме. ==== sendmail.mc ==== MAILER(local) MAILER(smtp) MAILER(cyrusv2) ==== sendmail.mc ==== после чего по make cf создаем новый sendmail.cf ************* Доставка почты в Cyrus ******************************************** Понятно, что ни один из нижеперечисленных вариантов не является моей собственной разработкой, я просто попытался собрать и опробовать то, что мне было понятнее и удобнее. Вариант 1. Стандартный, описанный в большинстве руководств "о том, как скрестить cyrus с ...". Т.е., объявление в .mc файле cyrus-а в качестве локального мейлера со всеми вытекающими последствиями. В этом варианте можно входящую почту перехватывать и направлять на системного пользователя с помощью алиасов: ==== virtusertable ==== spamtrap@your.domain spamtrap-local ==== virtusertable ==== ==== aliases ==== spamtrap-local: "| /usr/local/bin/procmail -d spamtrap" ==== aliases ==== Вариант 2. Виртуальный домен: DNS, в котором MX запись указывает на наш внешний адрес, имя домена заносим в mailertable и в relay-domains, ни в какие local-host-names его заносить не надо! ==== relay-domains ==== virt-domain.ru ==== relay-domains ==== ==== mailertable ==== virt-domain.ru cyrusv2:/var/imap/socket/lmtp ==== mailertable ==== Вместо cyrusv2 может быть включен другой "доставщик", образцы описания которых имеются ниже. Если хочется использовать возможности virtusertable - то схема немножко усложняется: - virt-domain.ru у сендмейла назначаем локальным в local-host-names - поднимаем в локальном DNS домен virt-domain.local, заменяем содержимое relay-domains и mailertable на вновь созданный локальный домен. ==== relay-domains ==== virt-domain.local ==== relay-domains ==== ==== mailertable ==== virt-domain.local cyrusv2:/var/imap/socket/lmtp ==== mailertable ==== - пишем в virtusertable соответствие: vasya@virt-domain.ru ---> petya@virt-domain.local komp@virt-domain.ru ---> komp В вышеприведенном примере первый адрес будет доставлен в почтовую базу cyrus-а пользователю petya (если такой существует), а второй адрес - в /var/mail/komp локальному пользователю системы. Однозначного примера, как задать параметры флагов для cyrusv2 из mc я не нашел, а разбираться не было времени, поэтому поменял значения прямо в sendmail.cf ==== sendmail.cf ==== Mcyrusv2, ... S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP/HdrToL, E=\r\n, ... ==== sendmail.cf ==== Без этой замены EnvToL на EnvToSMTP не работает доставка на витруальные домены с примерно такой диагностикой: ... while talking to localhost: >>> DATA <<< 550-Mailbox unknown. Either there is no mailbox associated with this <<< 550-name or you do not have authorization to see it. <<< 550 5.1.1 User unknown ==== Andrew Degtiariov ==== >> включение в конфиг (mc файл), следующей конструкции, >> поможет избавить от необходимости правки sendmail.cf: MAILER_DEFINITIONS # Mcyrusv2, P=[IPC], F=lsDFMnqA@/:|SmwXzW, E=\r\n, # S=EnvFromSMTP, R=EnvToSMTP/HdrToL, T=DNS/RFC822/X-Unix, # W=120s, # A=FILE /var/imap/socket/lmtp ==== Andrew Degtiariov ==== При использовании вышеприведенного фрагмента не надо использовать строчку: MAILER(cyrusv2) т.к. эта конструкция берет описание мейлера из системного файла конфигурации. Но, у меня данная конструкция не заработала. ==== Slava Olhovchenkov === http://zxy.spb.ru/tips/sendmail/cyrus.html ==== MAILER_DEFINITIONS Mvirtual, P=[IPC], F=lsDFMnqXzA@/:|m5, S=EnvFromSMTP/HdrFromSMTP, R=VDom/HdrToSMTP, E=\r\n, T=DNS/RFC822/SMTP, A=FILE /usr/local/cyrus/socket/lmtp LOCAL_RULESETS SVDom R$+ $: $> "EnvToSMTP" $1 R$+ < @ $* .> $: $1 < @ $2 > R$+ < @ $* > $: $1 $(mailertable $2 $) R$+ virtual : $* $: $1 @ $2 R$* $: $(vluser $1:maildrop $) R$* :maildrop<> $@ $1 R$* :maildrop $: $1 $| $(cyrus $1 $: $) R $* $| $* $@ $1 R $* $| $* $@ $1 R $* $| $* $: $1 R$+ @ $+ $: $1 $(vluser @$2:maildrop $) R$+ @ $+ :maildrop<> $@ @$2 R$* :maildrop $: $1 === Vitaly E. Lavrov === Причин (использовать свое описание доставщика) 2: - флаги мейлера. В оригинале он локальный т.е. имя домена теряется. - заголовки и правила проверки R=. IMHO флаги можно/нужно изменить на F=sDFMnqXPz0@m5 вместо F=lsDFMnqXzA@/:|m5, Зачем нужны для релея флаги: l This mailer is local A Look up the user ...in the alias database Зачем виртуальным юзерам нужно: / : | И не помешает: 0 Don't look up MX records P This mailer wants a "Return-Path:" line. Cyrus ее хочет. === Vitaly E. Lavrov === ==== Slava Olhovchenkov === Работоспособность этого описания я не проверял. Вариант 3. Альтернативный вариант доставки через procmail и delivery, позволяющий использовать предварительную сортировку средствами procmail-а. Вся почта принимается на локального юзера и обрабатывается через .forward и .procmailrc, либо на уровне системы включением procmail как локального доставщика почты для всех. ==== procmail-cyrus-delivery.sh ==== #!/bin/sh # http://subwiki.honeypot.net/cgi-bin/view/Freebsd/SendMailAndCyrus # script name: procmail-cyrus-delivery.sh # LOGNAME=$1 formail -I"From " | /usr/local/cyrus/bin/deliver -a $LOGNAME -m user.$LOGNAME ==== procmail-cyrus-delivery.sh ==== ==== .procmailrc ==== :0fw * ^Subject: ERROR | /path/to/your/scripts/procmail-cyrus-delivery.sh $LOGNAME ==== .procmailrc ==== 4. Администрирование и работа. В документации где-то попалась фраза о том, что в виртуальных доменах нельзя назначить shared папки, которые были бы доступны пользователям разных доменов. Соответственно, для каждого вновь поднимаемого домена нужно добавить запись про админа в директиве admins: файла imapd.conf, чтобы во-первых, можно было делегировать кому-то управление, не опасаясь, что будет снесено все, и, во-вторых, для того, чтобы не вводить каждый раз "длинное" имя пользователя при работе с его ящиком. Для админа virt-domain-а - ящики имеют привычные короткие имена пользователей(то, что написано до @). Замечания: папки для юзеров virt-domain (и его админа - тоже) надо создавать под аккаунтом админа virt-domain, причем, для самого админа - руками (cyradm), иначе, из почтового клиента, типа Thunderbird и административного аккаунта - subfolders получаются не вида user.name.foo, а в виде паблик фолдера "foo@virt-domain" с правами "anyone lrs". Чей это глюк - пока не разбирался. для админа virt-domain перестает работать схема "altnamespace: yes", то есть, его subfolders должны быть созданы заранее в виде: localhost> lm INBOX* INBOX (\HasChildren) INBOX.Sent (\HasNoChildren) subfolders у непривилегированых пользователей виртуального домена, из клиента Thunderbird создаются нормально и с нормальными правами. localhost> lm user.post* user.post (\HasChildren) user.post.Trash (\HasNoChildren) user.post.Sent (\HasNoChildren) subfolders у пользователей виртуального домена из cyradm с правами "главного администратора" ищутся и выглядят примерно так: localhost> lm user.test*@virt-domain.ru user.test.&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-@virt-domain.ru (\HasNoChildren) user.test.&BCcENQRABD0EPgQyBDgEOgQ4-@virt-domain.ru (\HasNoChildren) user.test@virt-domain.ru (\HasChildren) в случае использования в качестве сепаратора - "слэша" (unixhierarchysep: yes), создание ящика вида user.name (с точкой) - ошибки не вызывает, но такой бокс переходит в категорию паблик фолдеров. при попытке выцепить проходящее _мимо_ письмо в локальный мейлбокс, замечено, что virtusertables в отношении виртуальных доменов - не работают, скорее всего должны работать штатные операции sendmail-а по работе с виртуальными доменами. Appendix Небольшой скриптик, генерирующий пароли для ввода в saslpasswd2 ==== add_sasldb_user.sh ==== #!/bin/sh # $Id: cyrus-sendmail.howto.txt,v 1.5 2007/05/10 09:24:32 aost Exp $ # Небольшой скриптик, генерирующий пароли для ввода в saslpasswd2 # SASL_CMD="/usr/local/sbin/saslpasswd2" SASL_DBL="/usr/local/sbin/sasldblistusers2" # if [ ! -f ${SASL_CMD} -a ${SASL_DBL} ]; then echo "Error: executable files not found!" echo "${SASL_CMD} or ${SASL_DBL}" exit fi # if [ "x$1" = "x" ]; then echo "Usage: $0 user@name" exit fi # # check user # CHK_DBL=`${SASL_DBL}|grep ${1}` # if [ -z "${CHK_DBL}" ]; then AUTO=`pw -V /tmp useradd post -w random 2>/dev/null |awk '{print $0}'` echo ${AUTO}|${SASL_CMD} -cp ${1} && echo "Added user: $1 pass: ${AUTO}" else echo "Error: possible duplicate user" echo "Found in sasldb:" echo "${CHK_DBL}" exit fi # ==== add_sasldb_user.sh ==== Отлов спама и складывание его в доступный всем на чтение ящик. Создаем ящик со следующими правами: localhost> lam user.spamtrap spamtrap lrswipkxtea anyone lrs В строке запуска спамассассина пишем что-то типа: spamass_milter_socket="/var/run/spamass-milter.sock" spamass_milter_flags="-f -p ${spamass_milter_socket} -bspamtrap -- -s 150000" В ежедневных скриптах, выполняемых по крону пишем строчку очистки мейлбоксов: # Clean users TrashCan folder after 14 day su - cyrus -c "/usr/local/cyrus/bin/ipurge -s -f -d 14 user.\*.Trash" # # Spamtrap cleaning su - cyrus -c "/usr/local/cyrus/bin/ipurge -s -f -d 72 user.spamtrap" # Вот пока, собственно, и весь опыт, наработанный мной на виртуальных почтовых доменах. Andrey Y. Ostanovsky