Предыстория
Включаем дополнительные схемы в файле /etc/openldap/slapd.conf:
Прописываем нашу новую ldap базу в slapd-hdb-db01.conf:
Если планируется публиковать базу наружу, то конфигурируем интерфейс, который будет слушать наш Ldap сервер /etc/sysconfig/ldap (по умолчанию 127.0.0.1):
После чего должна создаться наша база в /var/lib/ldap/bases/your.ru
А вот пример скрипта AWK для его обработки:
Сразу скажу что я пользовался Windows портами awk утилит (http://gnuwin32.sourceforge.net/packages/gawk.htm), поэтому этот скрипт не тестировал под Linux. Будьте внимательны с переводом строки в файле при импорте на сервере. В качестве браузера и редактора каталога использовал JExplorer, никаких нареканий эта утилита не вызвала, умеет все, в том числе и экспотрировать и импортировать ветки каталога в .ldif файлы, единственное что — она написана на Java. В принципе слышал что можно поставить PhpLdapAdmin, но у меня это с ходу не получилось.
Я использую maildrop формат ящика (каждое письмо — отдельный текстовый файл в папке ящика). Ящики пользователей создаются сами при поступлении на них первого письма и при условии наличия разрешения на запись в каталог maildir пользователю, под которым работает postfix.
Теперь скомпилим эту транспортную схему командой
И обновим конфигурацию командой
В следующей серии настройка courier-imap и авторизации при получении почты.
Реализация
Платформа
AltLinux 4, версия ядра 2.6.18-std-smp-alt6. Все пакеты ставились из официального репозитария.Установка LDAP-сервера
Устанавливаем пакеты openldap-servers-2.3.35-alt0, libldap2.3-2.3.35-alt0, openldap-clients-2.3.35-alt0, openldap-2.3.35-alt0, openldap-doc-2.3.35-alt0.Включаем дополнительные схемы в файле /etc/openldap/slapd.conf:
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/courier.schema
include /etc/openldap/schema/qmail.schema
allow bind_v2
concurrency 20
gentlehup on
sizelimit -1
password-hash {CLEARTEXT}
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
replica-pidfile /var/run/slurpd.pid
replica-argsfile /var/run/slurpd.args
rootDSE /etc/openldap/rootdse.ldif
access to dn.exact=""
by * read
access to dn.subtree="cn=Subschema"
by * read
access to attrs=userPassword
by self write
by anonymous auth
by * none
modulepath /usr/lib/openldap
moduleload back_hdb.la
moduleload back_monitor.la
moduleload back_null.la
include /etc/openldap/slapd-hdb-db01.conf
Прописываем нашу новую ldap базу в slapd-hdb-db01.conf:
database hdb
suffix "dc=your,dc=ru"
rootdn "cn=admin,dc=your,dc=ru"
rootpw 123
directory /var/lib/ldap/bases/your.ru
index objectClass eq
index uid pres,eq,sub
index cn pres,eq,sub,subany
access to attrs=userPassword
by self write
by anonymous auth
by * none
access to *
by dn="cn=admin,dc=your,dc=ru" write
by * read
Если планируется публиковать базу наружу, то конфигурируем интерфейс, который будет слушать наш Ldap сервер /etc/sysconfig/ldap (по умолчанию 127.0.0.1):
SLAPDURLLIST="ldap://servername.your.ru/"
SLAPD_OPTIONS=""
SLURPD_OPTIONS='-t /'
Стартуем демона: service slapd start
После чего должна создаться наша база в /var/lib/ldap/bases/your.ru
Заполнение базы пользователей
Если есть уже существующая доменная база, то есть возможность выгрузить ее в текстовый CSV файл и пропарсить его с помощью AWK в готовый для импорта ldif файл. Так или иначе, удобнее всего создать текстовый файл со списком пользователей, а затем при помощи AWK скрипта преобразовать его в ldif, автоматически сгенерировав при этом и пароли пользователей. Таким образом у вас будет и скрипт резервной копии Ldap базы. Вот пример формата CSV файла выгрузки из Active Directory:"DN","objectClass","ou","distinguishedName","instanceType","whenCreated","whenChanged","uSNCreated", "uSNChanged","name","objectGUID","objectCategory","dSCorePropagationData","cn","sn","displayName", "proxyAddresses","altRecipientBL","targetAddress","mAPIRecipient","mailNickname","internetEncoding", "legacyExchangeDN","textEncodedORAddress","mail","msExchPoliciesIncluded","msExchALObjectVersion", "msExchHideFromAddressLists","givenName","altRecipient","department","homeMTA","homeMDB", "mDBUseDefaults","userAccountControl","codePage","countryCode","pwdLastSet","primaryGroupID", "objectSid","accountExpires","sAMAccountName","sAMAccountType","showInAddressBook","userPrincipalName", "msExchHomeServerName","msExchMailboxSecurityDescriptor","msExchUserAccountControl","msExchMailboxGuid", "member","groupType","badPwdCount","badPasswordTime","lastLogoff","lastLogon","userParameters","logonCount", "lastLogonTimestamp","gPLink","gPOptions","userCertificate","adminCount","msNPAllowDialin","title", "physicalDeliveryOfficeName","telephoneNumber","initials","postOfficeBox","company","deliverAndRedirect", "memberOf","scriptPath","localPolicyFlags","operatingSystem","operatingSystemVersion", "operatingSystemServicePack","dNSHostName","servicePrincipalName","isCriticalSystemObject","location","flags", "uNCName","versionNumber","serverName","portName","driverName","priority","printStartTime","printEndTime", "printBinNames","printMaxResolutionSupported","printOrientationsSupported","printCollate","printColor", "printShareName","printSpooling","printKeepPrintedJobs","driverVersion","printMaxXExtent","printMaxYExtent", "printMinXExtent","printMinYExtent","printMediaSupported","printerName","url","shortServerName", "printDuplexSupported","printLanguage","printStaplingSupported","printMemory","printRate","printRateUnit", "printMediaReady","printNumberUp","printPagesPerMinute","description","deletedItemFlags","submissionContLength", "garbageCollPeriod","msExchRequireAuthToSendTo","homePhone","otherTelephone","mobile", "showInAdvancedViewOnly","keywords","serviceClassName","serviceDNSName","serviceDNSNameType", "mS-SQL-Name","mS-SQL-RegisteredOwner","mS-SQL-Contact","mS-SQL-Location","mS-SQL-Memory","mS-SQL-Build", "mS-SQL-ServiceAccount","mS-SQL-CharacterSet","mS-SQL-SortOrder","mS-SQL-UnicodeSortOrder","mS-SQL-Clustered", "mS-SQL-NamedPipe","mS-SQL-MultiProtocol","mS-SQL-SPX","mS-SQL-TCPIP","mS-SQL-AppleTalk","mS-SQL-Vines", "mS-SQL-Status","mS-SQL-LastUpdatedDate","mS-SQL-InformationURL","mS-SQL-GPSLatitude","mS-SQL-GPSLongitude", "mS-SQL-GPSHeight","mS-SQL-Keywords","mSMQSites","mSMQServiceType","mSMQOSType","mSMQEncryptKey","mSMQSignKey", "mSMQDependentClientServices","mSMQRoutingServices","mSMQDsServices","mS-SQL-Description","mS-SQL-Alias", "mS-SQL-Size","mS-SQL-CreationDate","mS-SQL-LastBackupDate","mS-SQL-LastDiagnosticDate","mS-SQL-Applications","msRRASAttribute","mS-DS-CreatorSID","rIDSetReferences","delivContLength","autoReplyMessage","reportToOriginator","reportToOwner", "oOFReplyToOriginator","mSMQSignCertificates","mSMQDigests"
А вот пример скрипта AWK для его обработки:
##ВЫГРУЗКА ДЛЯ ГУГЛА
BEGIN {
FS=",";
##счетчик пользователей
userCounter = 0;
}
function pass(name)
{
return substr(name,1,1)""int(rand()*100000);
}
function trim(v)
{
## Remove leading and trailing spaces (add tabs if you like)
sub(/^ */,"",v);
sub(/ *$/,"",v);
return v;
}
##запятые могут встречаться внутри кавычек
{
num = 1;
for(i=1; i<= NF; i++)
{
if($(i)~/\"/)
{
rez[num] = $(i);
for(j=i+1; j<= NF; j++)
{
rez[num]= rez[num]","$(j);
if($(j)~/\"/)
{
i =j;
break;
}
}
gsub(/\"/, "", rez[num]);
}
else rez[num] = $(i);
num+= 1;
}
if(rez[2]=="user")
{
mail = rez[25];
split(substr($1, 5, length($1)), fio, "/");
if(rez[21]!= "")
{
userdn = "uid="rez[21]""substr(rez[1], length($1), length(rez[1]));
##Вытаскиваем русское наименование пользователя и его second name
i = 1;
while(i > 0)
{
if(i+1 in fio)
{
i++;
}
else
{
name = trim(fio[i]);
split(name, aname, " ");
if(2 in aname)
{
second_name = aname[2];
}
else
{
second_name = "null";
}
if(3 in aname)
{
second_name = second_name""aname[3];
}
delete aname;
break;
}
}
print "dn: cn="rez[21]",ou=People,dc=your,dc=ru\nobjectClass: inetOrgPerson\nobjectClass: organizationalPerson\nobjectClass: person\nobjectClass: qmailUser\nobjectClass: CourierMailAccount\nobjectClass: top\naccountStatus: active\ncn: "rez[21]"\nemployeeType: \ngidNumber: 100\nhomeDirectory: /var/spool/maildir\nmail: "mail"\nmailAlternateAddress: "rez[21]"@servername.your.ru\nmailAlternateAddress: "rez[21]"@your.ru\nmailMessageStore: /var/spool/maildir/"rez[21]"/\no: your.ru\nsn: "name"\nuid: "name"\nuidNumber: "userCounter+1000"\nuserPassword: "pass(rez[21])"\n";
userCounter += 1;
}
# uidNumber: 99 nobody
}
}
Сразу скажу что я пользовался Windows портами awk утилит (http://gnuwin32.sourceforge.net/packages/gawk.htm), поэтому этот скрипт не тестировал под Linux. Будьте внимательны с переводом строки в файле при импорте на сервере. В качестве браузера и редактора каталога использовал JExplorer, никаких нареканий эта утилита не вызвала, умеет все, в том числе и экспотрировать и импортировать ветки каталога в .ldif файлы, единственное что — она написана на Java. В принципе слышал что можно поставить PhpLdapAdmin, но у меня это с ходу не получилось.
Установка Postfix
Устанавливаем пакеты postfix-cyrus-2.3.11-alt1, postfix-control-1.6.1-alt1, postfix-2.3.11-alt1, postfix-ldap-2.3.11-alt1, cyrus-sasl2-2.1.22, libcourier-authlib-0.59.1-alt1.0, courier-imap-utils-4.1.2-alt1, courier-imap-4.1.2-alt1, courier-authlib-0.59.1-alt1.0, courier-authlib-ldap-0.59.1-alt1.0, procmail-3.22-alt7. Конфигурируем postfix:#/etc/postfix/main.cf
mailbox_command = /usr/bin/procmail -a $DOMAIN -d $LOGNAME
myhostname = servername.your.ru
#этой директивой мы замыкаем локальную почту пользователей сервера на виртуальную
local_transport = virtual
virtual_transport = virtual
virtual_mailbox_domains = your.ru
# этот каталог будет базовым для почтовых ящиков пользователей
virtual_mailbox_base = /var/spool/maildir
virtual_mailbox_maps = ldap:/etc/postfix/ldapvirtual.cf
virtual_uid_maps = static:999
virtual_gid_maps = static:12
virtual_mailbox_limit = 0
message_size_limit = 20480000
relayhost =
transport_maps = cdb:/etc/postfix/transport
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
# разрешить отправку писем только авторизованным клиентам
smtpd_recipient_restrictions = permit_sasl_authenticated, reject
smtpd_client_restrictions = permit
unknown_local_recipient_reject_code = 550
mynetworks = 192.168.0.0/24
Я использую maildrop формат ящика (каждое письмо — отдельный текстовый файл в папке ящика). Ящики пользователей создаются сами при поступлении на них первого письма и при условии наличия разрешения на запись в каталог maildir пользователю, под которым работает postfix.
#/etc/postfix/ldapvirtual.cf
server_host = servername.your.ru
server_port = 389
bind = yes
bind_dn = cn=admin,dc=your,dc=ru
bind_pw = 123
#узел каталога, который содержит пользователей
search_base = ou=People,dc=your,dc=ru
query_filter = (&(mail=%s)(objectClass=CourierMailAccount)(AccountStatus=active))
result_attribute = uid
result_format = %u/
#/etc/postfix/transport
your.ru :
.your.ru :
servername.your.ru :
* smtp:[mail.your_provider.ru]
Теперь скомпилим эту транспортную схему командой
postmap transport
И обновим конфигурацию командой
postfix reload
В следующей серии настройка courier-imap и авторизации при получении почты.