LDAP Linux Auth: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
Строка 300: Строка 300:
 
dn: cn=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
 
dn: cn=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
 
uid: nssproxy-node1
 
uid: nssproxy-node1
  +
gecos: Network Service Switch Proxy User
  +
objectClass: top
  +
objectClass: account
  +
objectClass: posixAccount
  +
objectClass: shadowAccount
  +
userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa
  +
shadowLastChange: 15140
  +
shadowMin: 0
  +
shadowMax: 99999
  +
shadowWarning: 7
  +
loginShell: /bin/false
  +
uidNumber: 801
  +
gidNumber: 801
  +
homeDirectory: /home/nssproxy
  +
</PRE>
  +
... и т д
  +
<PRE>
  +
dn: cn=nssproxy-node4,ou=service_users,dc=customer_organization,dc=fuel_domain
  +
uid: nssproxy-node4
 
gecos: Network Service Switch Proxy User
 
gecos: Network Service Switch Proxy User
 
objectClass: top
 
objectClass: top

Версия 15:13, 17 мая 2016


LDAP Server Installation

"Тихая" установка

DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils

Современные дистрибутивы OpenLDAP используют сам LDAP как хранилище конфигурации.


Посмотреть содержимое можно так:

ldapsearch -Y EXTERNAL -H ldapi:///  -b "cn=config"

Создать отдельную базу данных для своих объектов.
Внимательно проверить права на директорию - она должна существовать и быть доступна серверу на запись (/var/lib/ldap_fuel_domain/)

dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap_fuel_domain/
olcSuffix: dc=fuel_domain
olcAccess: {0}to  *  by *  write
olcLastMod: TRUE
olcRootDN: cn=admin,dc=fuel_domain
olcRootPW: {SSHA}bxQpFzYmIkILSbDEL3cVl+nf03mdra/t
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

Обратить внимание на

olcAccess: {0}to  *  by *  write

Изначально я даю полный доступ всем на все, изменю его позже.
Создание: (подключение через -H ldapi:/// в установке по умолчанию доступно руту без пароля.

ldapadd  -Y EXTERNAL -H ldapi:/// <  database
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "olcDatabase={2}hdb,cn=config"

Если права на директорию неправильные ИЛИ не настроен apparmor возникает ошибка:

root@node-3:~/ldap# ldapadd  -Y EXTERNAL -H ldapi:/// <  database
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "olcDatabase={2}hdb,cn=config"
ldap_add: Other (e.g., implementation specific) error (80)
	additional info: olcDbDirectory: value #0: invalid path: Permission denied

Исправить:

/etc/apparmor.d/usr.sbin.slapd

##
  /var/lib/ldap** rwk,


Для работы создаем свой домен куда будем помещать все объекты.

  • domain
# fuel_domain
dn: dc=fuel_domain
objectClass: top
objectClass: dcObject
objectClass: organization
o: fuel_users
  • domain_admin
# admin
dn: cn=admin,dc=fuel_domain
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: {SSHA}bxQpFzYmIkILSbDEL3cVl+nf03mdra/t

Пароль пользователя генерируется утилитой ldappasswd, в моем примере это 'r00tme'

Загрузить объекты:

ldapadd  -Y EXTERNAL -H ldapi:/// <  domain
ldapadd  -Y EXTERNAL -H ldapi:/// <  domain_admin

Проверить, подключившись с ново-созданным пользователем

ldapsearch -D "cn=admin,dc=fuel_domain" -w 'r00tme' -b 'dc=fuel_domain' '(objectclass=*)'
  • -D - "логин"
  • -w - пароль
  • -b - base, ветка дерева в которой искать
  • '(objectclass=*)' - "что искать", в примере - "все"

Результат поиска:

# extended LDIF
#
# LDAPv3
# base <dc=fuel_domain> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# fuel_domain
dn: dc=fuel_domain
objectClass: top
objectClass: dcObject
objectClass: organization
o: fuel_users
dc: fuel_domain

# admin, fuel_domain
dn: cn=admin,dc=fuel_domain
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9YnhRcEZ6WW1Ja0lMU2JERUwzY1ZsK25mMDNtZHJhL3Q=

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2


Исправить права на базу:

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fuel_domain" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=fuel_domain" write by * read
ldapmodify  -Y EXTERNAL  -H ldapi:/// < 03_fix_permissions
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={2}hdb,cn=config"

Проверить права можно например скачав весь конфиг:

ldapsearch -Y EXTERNAL -H ldapi:///  -b "cn=config" >  all_config

PHP LDAP Addmin

Опционально можно поставить phpldapadmin

apt-get  install phpldapadmin

Настройки минимальны и ограничиваются указанием домена пользователя

 diff /etc/phpldapadmin/config.php /etc/phpldapadmin/config.php.original
300c300
< $servers->setValue('server','base',array('dc=fuel_domain'));
---
> $servers->setValue('server','base',array('dc=example,dc=com'));
326c326
< $servers->setValue('login','bind_id','cn=admin,dc=fuel_domain');
---
> $servers->setValue('login','bind_id','cn=admin,dc=example,dc=com');

LDAP Configuration

Aliases

Для простоты я создаю алиасы что бы не вводить пароль каждый раз

alias ldapsearch='ldapsearch -D "cn=admin,dc=fuel_domain" -w r00tme'
alias ldapmodify='ldapmodify -D "cn=admin,dc=fuel_domain" -w r00tme'
alias ldapadd='ldapadd -D "cn=admin,dc=fuel_domain" -w r00tme'


Organization

Добавить организацию Обратить внимание - dn: dc=customer_organization,dc=fuel_domain - порядок важен. dc В КОТОРЫЙ добавляется должен быть последним.

# 04_customer_organization
dn: dc=customer_organization,dc=fuel_domain
dc: customer_organization
o: Example Organization
objectClass: dcObject
objectClass: organization

Добавить организацию:

ldapadd  < 04_customer_organization

Результат:

ldapadd  < 04_customer_organization
adding new entry "dc=customer_organization,dc=fue_domain"
ldap_add: Server is unwilling to perform (53)
	additional info: no global superior knowledge

root@node-3:~/ldap# ldapadd  < 04_customer_organization
adding new entry "dc=customer_organization,dc=fuel_domain"


Manager Role

#  05_manager
dn: cn=Manager,dc=customer_organization,dc=fuel_domain
cn: Manager
description: LDAP administrator
objectClass: organizationalRole
objectClass: top
roleOccupant: dc=customer_organization,dc=fuel_domain
ldapadd < 05_manager
adding new entry "cn=Manager,dc=customer_organization,dc=fuel_domain"

Organization Units People and Groups

# 06_people
dn: ou=People,dc=customer_organization,dc=fuel_domain
ou: People
objectClass: top
objectClass: organizationalUnit
# 07_groups
dn: ou=Group,dc=customer_organization,dc=fuel_domain
ou: Group
objectClass: top
objectClass: organizationalUnit
ldapadd  < 06_people
adding new entry "ou=People,dc=customer_organization,dc=fuel_domain"

root@node-3:~/ldap# ldapadd  < 07_groups
adding new entry "ou=Group,dc=customer_organization,dc=fuel_domain"



Для того что бы авторизовать клиентов нужны специальные пользователи которые смогут читать пароли. Для них создадим отдельную группу

dn: cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain
cn: nssproxy
objectClass: top
objectClass: posixGroup
gidNumber: 801
description: Network Service Switch Proxy

Users

Служебные пользователи

Для того что бы не делать анонимных запросов я создаю для каждого из своих серверов своего пользователя nssproxy-node1
Отдельный юнит для этих пользователей

dn: ou=service_users,dc=customer_organization,dc=fuel_domain
ou: service_users
objectClass: top
objectClass: organizationalUnit
dn: cn=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
uid: nssproxy-node1
gecos: Network Service Switch Proxy User
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa
shadowLastChange: 15140
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/false
uidNumber: 801
gidNumber: 801
homeDirectory: /home/nssproxy

... и т д

dn: cn=nssproxy-node4,ou=service_users,dc=customer_organization,dc=fuel_domain
uid: nssproxy-node4
gecos: Network Service Switch Proxy User
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa
shadowLastChange: 15140
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/false
uidNumber: 801
gidNumber: 801
homeDirectory: /home/nssproxy

"Живые Люди"

Добавить пользователя. Обратить внимание - пароль такой же как в /etc/shadow
(Как его генерировать я не знаю пока)

dn: uid=sirmax,ou=People,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: sirmax
cn: Max Mazur
sn: Mazur
givenName: Mazur
title: Max Mazur
telephoneNumber: +38 067 341 80 70
mobile: +38 067 341 80 70
postalAddress: AddressLine1$AddressLine2$AddressLine3
userPassword: {CRYPT}$6$DS/mzad5$EB.cNCLE7KB7OCPK1nU6aEA8HnQDLY1FPd3KaWPVqaNBtWhmh/4cOUgD1I8tQSFu41yy7jMXDrg9TDqlAbuLX.
labeledURI: http://wiki.sirmax.noname.com.ua/
loginShell: /bin/bash
uidNumber: 9999
gidNumber: 9999
homeDirectory: /home/sirmax/
description: This is an example user
ldapadd < 08_user1
adding new entry "uid=sirmax,ou=People,dc=customer_organization,dc=fuel_domain"

Groups

2 группы

  • группа пользователя
  • группа fuel_users
dn: cn=sirmax,ou=Group,dc=example_organization,dc=fuel
changetype: add
cn: fuel users
objectClass: posixGroup
gidNumber: 9999
description: Fuel Users
memberUid: sirmax
dn: cn=fuel_users,ou=Group,dc=example_organization,dc=fuel
changetype: add
cn: fuel users
objectClass: posixGroup
gidNumber: 109999
description: Fuel Users
memberUid: sirmax

Добавить:

ldapadd < 09_group_for_user1
adding new entry "cn=sirmax,ou=Group,dc=customer_organization,dc=fuel_domain"

ldapadd  < 10_group_fuel_users
adding new entry "cn=fuel_users,ou=Group,dc=customer_organization,dc=fuel_domain"

Настройка клиента

http://wiki.sirmax.noname.com.ua/index.php/LDAP_Linux_Auth_Client

Запись сессии

Для записи сессии используем утилиту sudosh2

 dpkg -i  <path>/sudosh2_2.0.1-1_amd64.deb
mkdir /var/log/sudosh; 
chmod a+w /var/log/sudosh
chmod +r /etc/sudosh.conf

SUDO

Добавить разрешения в файл sudoers
/etc/sudoers

%fuel_users ALL=(ALL:ALL) ALL


Подробно про sudo: https://wiki.archlinux.org/index.php/Sudo_%28%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%29


SUDO LDAP

Файл sudoers на самом деле может храниться в LDAP
Co стороны LDAP-сервера требуется более детальная настройка

  • Добавить схему для sudo
  • Добавить объекты


Добавление схемы

Операция не совсем тривиальная - в пакете ldap-sudo поставляется старая схема и просто так ее залить на сервер не получиться. Требуется конвертация.

  • Создать временный файл "конфигурации slapd". В моем примере это /root/slapd.conf с одной строкой:
# cat /root/slapd.conf
include ./sudo.OpenLDAP

sudo.OpenLDAP - это файл скопированный из пакета ldap-sudo, /usr/share/doc/sudo-ldap/schema.OpenLDAP
Запустить конвертацию: создать директорию для будущих конфигов и сгенерировать их

# создаём директорию
mkdir testdir
# запускаем slaptest
slaptest -f slapd.conf -F testdir

В результате в testdir будет создано дерева конфигурации.
Интересующая нас схема расположена в файле testdir/cn=config/cn=sudo

# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
# CRC32 75e9d97b
dn: cn={0}sudo
objectClass: olcSchemaConfig
cn: {0}sudo
olcAttributeTypes: {0}( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s).
 who may  run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMa
 tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {1}( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s).
 who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMat
 ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {2}( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Comma
 nd(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1
 466.115.121.1.26 )
olcAttributeTypes: {3}( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s)
  impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1
 .4.1.1466.115.121.1.26 )
olcAttributeTypes: {4}( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Option
 s(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115
 .121.1.26 )
olcAttributeTypes: {5}( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'Use
 r(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466
 .115.121.1.26 )
olcAttributeTypes: {6}( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Gr
 oup(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14
 66.115.121.1.26 )
olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Sta
 rt of time interval for which the entry is valid' EQUALITY generalizedTimeMat
 ch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
  )
olcAttributeTypes: {8}( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End.
 of time interval for which the entry is valid' EQUALITY generalizedTimeMatch.
 ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
olcAttributeTypes: {9}( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an int
 eger to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrd
 eringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
olcObjectClasses: {0}( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer En
 tries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ s
 udoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotB
 efore $ sudoNotAfter $ description ) )
structuralObjectClass: olcSchemaConfig
entryUUID: aaaded3e-af4b-1035-8f99-f94b551aa988
creatorsName: cn=config
createTimestamp: 20160516004836Z
entryCSN: 20160516004836.159008Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20160516004836Z


Тут dn: cn={0}sudo - взято из имени файла. Если файл со схемой назывался по-другому, то и имя будет другое.


Файл требуется привести к следующему виду:

dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo
olcAttributeTypes: {0}( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s).
 who may  run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMa
 tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {1}( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s).
 who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMat
 ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {2}( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Comma
 nd(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1
 466.115.121.1.26 )
olcAttributeTypes: {3}( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s)
  impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1
 .4.1.1466.115.121.1.26 )
olcAttributeTypes: {4}( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Option
 s(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115
 .121.1.26 )
olcAttributeTypes: {5}( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'Use
 r(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466
 .115.121.1.26 )
olcAttributeTypes: {6}( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Gr
 oup(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14
 66.115.121.1.26 )
olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Sta
 rt of time interval for which the entry is valid' EQUALITY generalizedTimeMat
 ch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
  )
olcAttributeTypes: {8}( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End.
 of time interval for which the entry is valid' EQUALITY generalizedTimeMatch.
 ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
olcAttributeTypes: {9}( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an int
 eger to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrd
 eringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
olcObjectClasses: {0}( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer En
 tries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ s
 udoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotB
 efore $ sudoNotAfter $ description ) )

diff:

< # AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
< # CRC32 75e9d97b
< dn: cn={0}sudo
---
> dn: cn=sudo,cn=schema,cn=config
5c3
< cn: {0}sudo
---
> cn: sudo
41,47d38
< structuralObjectClass: olcSchemaConfig
< entryUUID: aaaded3e-af4b-1035-8f99-f94b551aa988
< creatorsName: cn=config
< createTimestamp: 20160516004836Z
< entryCSN: 20160516004836.159008Z#000000#000#000000
< modifiersName: cn=config

А именно: указать правильный dn и удалить{0}. Удаление {0} означает что LDAP сам назначит номер в последовательности, а не перепишет существующую запись.
Тут подробно:

Добавление объектов

Установить sudo с поддержкой ldap и необходимые утилиты и схемы

apt-get  install  sudo-ldap

Бекап настроек sudo

cp /etc/sudoers /root/sudoers

Распаковать утилиту для конвертации файла sudoers а объекты LDAP

zcat /usr/share/doc/sudo-ldap/sudoers2ldif.gz > /root/sudoers2ldif
chmod +x sudoers2ldif

Конвертация

SUDOERS_BASE=ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain  ./sudoers2ldif sudoers  > sudoers.ldif

Переменная SUDOERS_BASE=ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain определяет в каком OU/DOMAIN помещать объекты


Загрузить конфигурацию в LDAP

ldapadd < sudoers.ldif
adding new entry "cn=defaults,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"

adding new entry "cn=root,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"

adding new entry "cn=%admin,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"

adding new entry "cn=%sudo,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"

adding new entry "cn=%fuel_users,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"

Ссылки


PAM

PAM vs NSS

http://serverfault.com/questions/538383/understand-pam-and-nss

http://skeletor.org.ua/?p=464

http://pro-ldap.ru/tr/zytrax/ch6/slapd-config.html

https://wiki.archlinux.org/index.php/LDAP_authentication


RUS http://www.bog.pp.ru/work/LDAP.html http://pro-ldap.ru/tr/zytrax/ch6/slapd-config.html http://xgu.ru/wiki/man:ldapmodify https://rtfm.co.ua/openldap-migraciya-s-slapd-conf-na-cnconfig-olc/

http://www.slashroot.in/how-are-passwords-stored-linux-understanding-hashing-shadow-utils