Наши партнеры

UnixForum






Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

Ошибка базы данных: Table 'a111530_forumnew.rlf1_users' doesn't exist
На главную -> MyLDP -> Тематический каталог -> Серверные службы Linux

Перевод почтового сервера с Kerio Mail на Linux

Автор: Александр Тарасов aka oioki
Дата: 29 марта 2009

Организации, в которой я работаю, потребовалось перевести почту с коммерческого сервера Kerio Mail 6 на свободный вариант - Linux-сервер на базе Postfix+Dovecot. Особенностью является и то, что большинство почтовых пользователей завязаны на Active Directory. В организации используется несколько доменов. Эта статья представляет собой описание действий по настройке и собственно переносу почты - может быть, кому-нибудь пригодится.

Базовая установка

На новый сервер решено ставить Ubuntu 8.04. Сразу поставим необходимые пакеты:

apt-get install postfix postfix-ldap dovecot-common dovecot-imapd dovecot-pop3d mailx
Основной идеей решения является то, что адрес электронной почты пользователя хранится в поле mail каждого пользователя Active Directory, желающего иметь почту. В организации используется несколько доменов, поэтому обращаться мы будем к глобальному каталогу, который работает на контроллере корневого домена леса - root.domain.ru.

Настройка Postfix

Postfix - агент передачи почты (Mail Transfer Agent, MTA). Занимается пересылкой почты, пришедшей на порт 25 (SMTP). Вот основной конфигурационный файл, далее объясню что к чему:
/etc/postfix/main.cf (показать код)
smtpd_banner = mail.domain.ru: proud of postfix.
biff = no
append_dot_mydomain = no
myhostname = mail.domain.ru
myorigin = domain.ru
mydestination = localhost
relayhost = relay.domain.ru
mynetworks = 10.0.0.0/16, 127.0.0.0/8
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

# Virtual mailbox settings
virtual_mailbox_domains = /etc/postfix/domains.cf
virtual_mailbox_base = /var/mail
virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf
virtual_minimum_uid = 8
virtual_uid_maps = static:8
virtual_gid_maps = static:8
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
message_size_limit = 20480000

# SASL Authentication
smtpd_sasl_auth_enable = no
smtpd_sasl_exceptions_networks = $mynetworks
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

smtpd_recipient_restrictions =
	permit_mynetworks,
	permit_sasl_authenticated,
	reject_unauth_destination,
	permit
В нашем случае он будет принимать лишь почту для отдельных доменов (virtual_mailbox_domains) - список этих доменов хранится в виде простого списка:
/etc/postfix/domains.cf (показать код)
dom1.domain.ru
dom2.domain.ru
dom3.domain.ru
root.domain.ru
Остальные письма будут перенаправляться на ближайший сервер пересылки почты (relayhost). Проверка того, существует ли на данном сервере адресат, которому предназначено письмо, осуществляется через LDAP-запросы (virtual_mailbox_maps). Вот конфигурационный файл, описывающий LDAP-запросы:
/etc/postfix/ldap-users.cf (показать код)
version = 3

server_host = root.domain.ru:3268
query_filter = (&(objectclass=user)(mail=%s))

result_attribute = samaccountname
result_format = %s

bind = yes
bind_dn = root\mailbind
bind_pw = topsecret
Вкратце, что делает этот файл. Он принимает в качестве параметра строку %s с адресом электронной почты. Делается LDAP-запрос от имени пользователя mailbind@root.domain.ru. Запрос отправляется на сервис глобального каталога (который работает на порту TCP 3268 контроллера корневого домена леса), и ведется поиск объекта класса user с адресом %s. Если такой объект (то есть пользователь) найден, то возвращается поле sAMAccountName - поиск успешен. После этого Postfix считает, что такой пользователь в базе есть, и передает письмо сервису Dovecot (virtual_transport). Если пользователь с такой почтой не найден, тогда Postfix ответит таким сообщением:
550 5.1.1 <fedor@dom.domain.ru>: Recipient address rejected: User unknown in virtual mailbox table
Еще нужно прописать в файле master.cf сервис dovecot:
dovecot unix - n n - - pipe flags=DRhu user=mail:mail argv=/usr/lib/dovecot/deliver -d $(recipient)

Настройка Dovecot

Dovecot выполняет роли доставщика писем от Postfix в локальные каталоги (/var/mail), а также POP3- и IMAP-сервера - доставляет письма конечным пользователям. Вот основной конфигурационный файл, далее будет все разъяснено подробнее.
/etc/dovecot/dovecot.conf (показать код)
login_greeting = Welcome to IMAP/POP3 server
base_dir = /var/run/dovecot/
mail_location = maildir:/var/mail/%d/%n
protocols = imap pop3

protocol imap {
	listen = *:143
	login_executable = /usr/lib/dovecot/imap-login
	mail_executable = /usr/lib/dovecot/imap
	imap_max_line_length = 65536
	mail_plugin_dir = /usr/lib/dovecot/modules/imap
}

protocol pop3 {
	listen = *:110
	login_executable = /usr/lib/dovecot/pop3-login
	mail_executable = /usr/lib/dovecot/pop3
	pop3_uidl_format = %08Xu%08Xv
	mail_plugin_dir = /usr/lib/dovecot/modules/pop3
}

protocol lda {
	postmaster_address = postmaster@mail.domain.ru
	hostname=mail.domain.ru
	sendmail_path = /usr/lib/sendmail
	auth_socket_path = /var/run/dovecot/auth-master
	rejection_reason = Ваше сообщение "%s" адресату <%t> было отклонено
		по следующей причине: %n%r.%n%nЕсли вы действительно хотите, чтобы
		письмо дошло, пожалуйста, свяжитесь с почтовым администратором
		<postmaster@mail.domain.ru>
}

plugin {
        quota = maildir
        quota_rule = *:storage=50M
        quota_rule2 = Trash:ignore
        quota_warning = storage=90%% /etc/dovecot/scripts/quota-warning.sh 90
}

log_timestamp = "%Y-%m-%d %H:%M:%S "
auth_verbose = no
auth_debug = no
auth_debug_passwords = no
mail_debug = no

mail_privileged_group = mail
first_valid_uid = 8
last_valid_uid = 8
maildir_copy_with_hardlinks = yes
disable_plaintext_auth = no

auth default {
	mechanisms = plain

   userdb passwd-file {
      args = /etc/dovecot/quotas.conf
   }	
	userdb static {
		args = uid=8 gid=8 allow_all_users=yes
	}
	passdb ldap {
		args = /etc/dovecot/ldap.conf
	}

	user = nobody
	socket listen {
		master {
			path = /var/run/dovecot/auth-master
			mode = 0660
			user = mail
			group = mail
		}
		client {
			path = /var/spool/postfix/private/auth
			mode = 0660
			user = postfix
			group = postfix
		}
	}
}
Основные моменты здесь - записи userdb и passdb в разделе auth. Запись userdb static означает, что для всех пользователей будет предложена одна и та же схема хранения писем, а именно /var/mail/почтовый_домен/левая_часть_адреса. Здесь все пользователи разрешены (allow_all_users=yes), потому что их существование уже было проверено ранее сервисом Postfix. Проверка пароля требуется в случае подключения POP3- или IMAP-клиентом. Здесь уже вступает в действие запись passdb. Как видно из конфигурационного файла, аутентификация происходит с помощью LDAP-запросов. Следующий файл описывает порядок работы:
/etc/dovecot/ldap.conf (показать код)
ldap_version = 3
auth_bind = yes

hosts = root.domain.ru:3268
base = dc=domain,dc=ru
dn = mailbind@root.domain.ru
dnpass = topsecret
pass_filter = (&(objectclass=user)(mail=%u))
Для работы квот в том виде, в котором они здесь представлены, потребуется Dovecot версии 1.1 или выше. Суть данной настройки в том, что мы выделяем всем пользователям почтовый ящик размером 50 Мб, однако при этом не учитываем размер корзины. Отдельным пользователям можно установить иную квоту (в том числе и безлимит, которому соответствует значение 0). Исключения по квоте хранятся в файле такого формата:
/etc/dovecot/quotas.conf (показать код)
unlim@dom3.domain.ru::8:8::::userdb_quota_rule=*:storage=0
big@dom2.domain.ru::8:8::::userdb_quota_rule=*:storage=100M
. . .
Оповещение пользователя о приближающемся переполнении ящика осуществляется с помощью скрипта:
/etc/dovecot/scripts/quota-warning.sh (показать код)
#!/bin/bash

ADMIN=postmaster@root.domain.ru
PERCENT=$1

message()
{
        echo "MIME-Version: 1.0"
        echo "Content-Type: text/plain; charset=utf-8"
        echo "Content-Transfer-Encoding: 16bit"
        echo "From: $ADMIN"
        echo "To: $USER"
        echo "Subject: Внимание! Ваш ящик почти заполнен."
        echo "Уважаемый пользователь!"
        echo "Ваш почтовый ящик заполнен на $PERCENT%."
        echo "Учтите, что при превышении квоты будет невозможно хранить сообщения в вашем почтовом ящике."
        echo "Для устранения проблемы требуется почистить свои почтовые папки (в первую очередь корзину)."
        echo ""
        date +'%e %B %Y, %k:%M'
}

message | sendmail -f $ADMIN "$USER"

Перенос привязки почты к ActiveDirectory

Привязка к AD, конечно теперь существует, но дело в том, что в Kerio привязка осуществлялась через собственный конфиг-файл, а мы собираемся прописать e-mail адреса в самой AD. Значит, нужно обработать конфигурационный файл Kerio Mail - он называется users.cfg - и выделить из него привязки к AD. Однако не все пользователи были привязаны к AD, а у тех, которые привязаны, логин на почту и AD совпадает. Это все надо учесть. Обработку файла произведем в три этапа:

1. Выделим из файла users.cfg тройки (AD-логин,левая часть адреса,почтовый домен). Если пользователь аутентфицируется через внутреннюю базу Kerio (т.е. Auth_type=0), то AD-логин пока не пишем - забиваем строку-пустышку "ADLOGIN". Иначе пишем одинаковые логины. Вот скрипт на Perl:

make-list.pl (показать код)
#!/usr/bin/perl

$mydomain="$ARGV[0].domain.ru";

open(USERS,"users.cfg");
@users=<USERS>;
close(USERS);

for($j=0; $j<scalar(@users); $j++)
{
	$line=$users[$j];
	if ( $line =~ /\ \ \ \ \<variable\ name=\"Name\"\>.*\<\/variable\>\r\n/ )
	{
		$line =~ s/\ \ \ \ \<variable\ name=\"Name\"\>//;
		$line =~ s/\<\/variable\>\r\n//;
		$j++;
		$domain=$users[$j];
		$domain =~ s/\ \ \ \ \<variable\ name=\"Domain\"\>//;
		$domain =~ s/\<\/variable\>\r\n//;
		
		if ( $domain eq $mydomain )
		{
			for($k=$j+1; $k<scalar(@users); $k++)
			{
				$line2=$users[$k];
				if ( $line2 =~ /\ \ \ \ \<variable\ name=\"Auth_type\"\>.*\<\/variable\>\r\n/ )
				{
					$line2 =~ s/\ \ \ \ \<variable\ name=\"Auth_type\"\>//;
					$line2 =~ s/\<\/variable\>\r\n//;
					if ( $line2 eq '0' )
					{
						print "ADLOGIN:$line:$domain:\n";
					}
					else
					{
						print "$line:$line:$domain:\n";
					}
					last;
				}
			}
		}
	}
}
Вызывать надо примерно так: ./make-list.pl dom1 > step1.out. Результат обработки таким скриптом:
step1.out (показать код)
ADLOGIN:user1:dom1.domain.ru:
ADLOGIN:user2:dom1.domain.ru:
user3:user3:dom1.domain.ru:
. . .

2. Далее нужно сгенерировать LDIF-файл, описывающий действия, которые нужно произвести с базой данных ActiveDirectory. В данном случае мы меняем поле mail определенных пользователей нужным нам образом. Вот скрипт, генерирующий LDIF-файл. Кроме того, он ищет в AD логины, совпадающие с левыми частями интересующих нас почтовых адресов - таким образом восстанавливаем привязку к AD.

make-ldif.pl (показать код)
#!/usr/bin/perl

@data=<STDIN>;

for($j=0; $j<scalar(@data); $j++)
{
	# Разбиваем строку на поля
	($adlogin,$email,$domain) = split(/:/, $data[$j]);

	# Если не было привязки к AD, попытаемся ее восстановить, найдя 
	if ( $adlogin eq 'ADLOGIN' )
	{
		$field = $email;
	}
	else
	{
		$field = $adlogin;
	}

	# Ищем Distinguished Name в Active Directory
	open(CONVERTFD,"./dn-lookup $field |");
	$dn = <CONVERTFD>;
	close(CONVERTFD);
	
	if ( $dn eq '' )
	{
		print STDERR "# Не найдено соответствие для почты $email\@$domain.\n";
	}
	else
	{
		if ( $adlogin eq 'ADLOGIN' )
		{
			print STDERR "# Привязка $email\@$domain к логину $email восстановлена.\n";
		}

		# Выводим код LDIF-операции
		print $dn;
		print "changetype: modify\n";
		print "replace: mail\n";
		print "mail: $email\@$domain\n";
		print "-\n";
	}
}
Здесь используется вспомогательный скрипт следующего содержания:
dn-lookup.sh (показать код)
#!/bin/sh
ldapsearch -h root.domain.ru -p 3268 -b "dc=root,dc=domain,dc=ru" "(sAMAccountName=$1)" \
   -x -D "mailbind@ROOT.DOMAIN.RU" -w "topsecret" | grep "dn:"  | head -n 1
Он возвращает Distinguished Name (DN) пользователя, логин которого в AD передается первым аргументом. Вот примерный результат второго шага:
step2.out (показать код)
CN=user1,CN=Users,DC=dom2,DC=domain,DC=ru
changetype: modify
replace: mail
mail: user1@dom2.domain.ru
-
CN=user2,CN=Users,DC=dom2,DC=domain,DC=ru
changetype: modify
replace: mail
mail: user2@dom2.domain.ru
-
CN=user3,CN=Users,DC=dom1,DC=domain,DC=ru
changetype: modify
replace: mail
mail: user3@dom1.domain.ru
-
3. Наконец, осталось принять изменения в Active Directory, с помощью такой команды:
ldapmodify -f step-2.out -h root.domain.ru -x -D "superadmin@ROOT.DOMAIN.RU"
Потребуется ввести пароль пользователя superadmin, причем этот пользователь должен обладать правами на изменение каталога.

Перенос почты

Итак, теперь все готово для приема и отправки почты. Однако у нас есть уже существующие письма пользователей, которые необходимо аккуратно перенести. У нас она будет осуществляться с помощью такого скрипта:
kerio2maildir (показать код)
#!/bin/sh

### Скрипт переноса из Kerio в Maildir-структуру

KERIOMAIL=/mnt/mail/Store/mail

### Список доменов
list_domains()
{
        ls -1 $KERIOMAIL | grep -v "\#public"
}

### Копирование каталога пользователя $2 из домена $1
make_user()
{
        DEST=$1/$2
        SRC=$KERIOMAIL/$DEST
        mkdir $DEST

        mkdir -p $DEST/.Trash/new
        mkdir -p $DEST/.Trash/cur
        mkdir -p $DEST/.Trash/tmp
        cp $SRC/Deleted\ Items/\#msgs/* $DEST/.Trash/new

        mkdir -p $DEST/.Drafts/new
        mkdir -p $DEST/.Drafts/cur
        mkdir -p $DEST/.Drafts/tmp
        cp $SRC/Drafts/\#msgs/* $DEST/.Drafts/new

        mkdir -p $DEST/.Sent/new
        mkdir -p $DEST/.Sent/cur
        mkdir -p $DEST/.Sent/tmp
        cp $SRC/Sent\ Items/\#msgs/* $DEST/.Sent/new

        mkdir -p $DEST/new
        mkdir -p $DEST/cur
        mkdir -p $DEST/tmp
        cp $SRC/INBOX/\#msgs/* $DEST/new
}

### Список пользователей домена $1
list_users()
{
        ls -1 $KERIOMAIL/$1 | grep -v "\#public"
}

### Копирование домена $1
make_domain()
{
        for user in `list_users $1`;
        do
                make_user $1 $user
        done
}

### Пересоздаем каталоги с доменами
for domain in `list_domains`;
do
        rm -Rf $domain
        mkdir $domain
        make_domain $domain
done
Как видно из этого скрипта, он просто переносит почту из файловой структуры Kerio в структуру Maildir.

Заключение

Итак, мы перенесли почту из коммерческого почтовика Kerio Mail 6 на Linux-сервер, да еще с привязкой к ActiveDirectory. Все довольны. Любые отзывы, пожелания и предложения принимаются на почту tam [sobaka] asu [dot] ru.



Комментарии