LDAP Linux Auth

Материал из naname.com.ua
Перейти к навигацииПерейти к поиску


Введение

Соглашения и умолчания

Везде в документе приняты следующие соглашения:

  • пароль, если не указан - r00tme
  • все пароли заведомо простые так как использовались для отладки. В реальной инсталляции рекомендую использовать более сложные пароли.
  • изначально настройка не безопасна (используется "админская" учетная запись, и перенастройка на более безопасную конфигурацию описываетсяв отдельной секции.
  • использование шифрования описывается в отдельной секции, изначальная настройка не использует шифрование.
  • OS: Ubuntu 14.04
  • Вся настройка делается для конкретной цели и ОС установлена Fuel-ом (Base OS) для OpenStack и конфигурация может отличаться (незначительно) от обычной установки Ubuntu.

Для простоты и скорости работы я создаю алиасы для утилит, что бы не вписывать логин и пароль каждый раз.
По этой причине команды указаны БЕЗ пароля.

alias ldappasswd='ldappasswd -D "cn=admin,dc=fuel_domain" -w r00tme'
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'


Если требуется ввести другой пароль то команда обычно предваряется символом \ (unalias), например

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

Репликация

В моей инсталляции фигурируют 2 сервера, сначала настраивается 1 потом дополняется репликацией.
Для простоты я использую алиасы через /etc/hosts

10.20.0.6       ldap2
10.20.0.3       ldap1

Прокси для Active-Backup конфигурации - на виртуальном IP который (не реализовано) будет перемещаться между нодами. (В примере - перенос осуществляется в ручном режиме)

10.20.0.100       ldap

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

В статье встечаются ссылки на утилиту sudosh - это утилита для записи сессии пользователя. Отмечу что в моей конфигурации она установлена и используется, потому на нее иногда будут ссылки

 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

LDAP Server Installation

"Тихая" установка (на ldap 1)

DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils

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


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

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

Create database

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

0002_createDatabase.ldif
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

Изначально я даю полный доступ всем на все, изменю его позже.

В строке цифра 2 в строке dn: olcDatabase={2}hdb,cn=config обозначает что это 2-я база, ту что существует можно как удалить так и оставить "на потом"

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

mkdir -p /var/lib/ldap_fuel_domain/
chown openldap:openldap /var/lib/ldap_fuel_domain/
ldapadd  -Y EXTERNAL -H ldapi:/// <  0002_createDatabase.ldif
adding new entry "olcDatabase={2}hdb,cn=config"

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

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

В логах:

apparmor="DENIED" operation="mknod" profile="/usr/sbin/slapd" name="/var/lib/ldap_fuel_domain/DUMMY" pid=26365 comm="slapd" requested_mask="c" denied_mask="c" fsuid=107 ouid=107

Исправить:

/etc/apparmor.d/usr.sbin.slapd
##
  /var/lib/ldap*/ rwk,
  /var/lib/ldap** rwk,

и перезапустить apparmor

 /etc/init.d/apparmor  restart

Some info:

Populate Database

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

  • domain
 0010_create_comain.ldiff
dn: dc=fuel_domain
objectClass: top
objectClass: dcObject
objectClass: organization
o: fuel_users
  • domain_admin
0011_fuel_domain_admin.ldiff
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:/// <  0010_create_comain.ldiff
<PRE>
<PRE>
adding new entry "dc=fuel_domain"
ldapadd  -Y EXTERNAL -H ldapi:/// <  0011_fuel_domain_admin.ldiff
adding new entry "cn=admin,dc=fuel_domain"

Check connection

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

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

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

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

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

Fix permmissions

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

0022_fix_database_permissions.ldif
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
olcAccess: {1}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fuel_domain" write by * none
olcAccess: {2}to dn.base="" by * read
olcAccess: {3}to * by dn="cn=admin,dc=fuel_domain" write by * read
ldapmodify  -Y EXTERNAL  -H ldapi:/// < 0021_fix_database_permissions.ldif
modifying entry "olcDatabase={2}hdb,cn=config"

Download configuration and check it

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

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

Результат

На этом шаге - рабочий LDAP сервер с минимальными настройками и без шифрования.

Шифрование

Настройка шифрования вынесена на отдельную страницу

На данный момент настроено шифрование.

Репликация

Перед началом настройки репликации - настроить на обоих серверах шифрования. Конфигурация аналогичная за исключением сертификата и хостнейма


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

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');

Если нужно шифрование то

 apt-get install php5-sasl

И конфигурация будет выглядеть так:

$servers->setValue('server','host','ldaps://127.0.0.1:636');
$servers->setValue('server','port',0);

В файле /etc/ldap/ldap.conf должны быть правильные настройки

TLS_CACERT      /etc/ssl/certs/rootca.crt
TLS_REQCERT     allow
TIMELIMIT       15
TIMEOUT         20

Populate LDAP

Customers_Organization

Контейнер для всех остальных объектов

0000_Customers_Organization
dn: dc=customer_organization,dc=fuel_domain
dc: customer_organization
o: Example Organization
objectClass: dcObject
objectClass: organization

Groups

Контейнер для групп и для пользователей.

0001_Groups
dn: ou=Group,dc=customer_organization,dc=fuel_domain
ou: Group
objectClass: top
objectClass: organizationalUnit

dn: ou=People,dc=customer_organization,dc=fuel_domain
ou: People
objectClass: top
objectClass: organizationalUnit

User sirmax (мой пользователь)

Первый пользователь и его группа, который сможет логиниться на ноды.

0002_User_sirmax
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: /usr/bin/sudosh
uidNumber: 9999
gidNumber: 9999
homeDirectory: /home/sirmax
description: This is me :)


dn: cn=sirmax,ou=Group,dc=customer_organization,dc=fuel_domain
changetype: add
cn: sirmax
objectClass: posixGroup
gidNumber: 9999
description: Fuel Users
memberUid: sirmax

Group Fuel_Users

Группа пользователей которая используется для sudo

0004_GroupFuelUsers
dn: cn=fuel_users,ou=Group,dc=customer_organization,dc=fuel_domain
changetype: add
cn: fuel_users
objectClass: posixGroup
gidNumber: 109999
description: Fuel Users
memberUid: sirmax

ServiceOU and Sudoers

Создать контейнеры для сервисных объектов и поместить в него контейнер для sudo.


0005_ServiceOU_and_Sudoers
dn: ou=services,dc=customer_organization,dc=fuel_domain
ou: Services
objectClass: top
objectClass: organizationalUnit
description: Group all services under this OU

dn: ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: organizationalUnit
description: sudo
objectClass: top

ServieUsersOU

Контейнер для служебных пользователей

0006_ServieUsersOU
dn: ou=service_users,dc=customer_organization,dc=fuel_domain
ou: service_users
objectClass: top
objectClass: organizationalUnit

nssproxy_group

Группа для служебных пользователей, пользователям этой группы будет разрешено читать хеши пароля и пользователи этой группы используются для nss, pam и ldap-sudo

0007_nssproxy_group
dn: cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain
cn: nssproxy
objectClass: groupOfNames
objectClass: top
member: uid=nssproxy-node1,ou=service_users,dc=customer_organization,dc=fuel_domain
member: uid=nssproxy-node2,ou=service_users,dc=customer_organization,dc=fuel_domain
member: uid=nssproxy-node3,ou=service_users,dc=customer_organization,dc=fuel_domain
member: uid=nssproxy-node4,ou=service_users,dc=customer_organization,dc=fuel_domain

0008_nssProxyUsers

Служебные пользователи (4 по числу серверов)

0008_nssProxyUsers
dn: uid=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
objectClass: organizationalPerson
objectClass: inetOrgPerson
userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa
cn: node1
sn: node1
shadowLastChange: 15140
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/false
uidNumber: 801
gidNumber: 801
homeDirectory: /home/nssproxy


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


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


dn: uid=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
objectClass: organizationalPerson
objectClass: inetOrgPerson
userPassword: {SSHA}RsAMqOI3647qg1gAZF3x2BKBnp0sEVfa
cn: node4
sn: node4
shadowLastChange: 15140
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/false
uidNumber: 804
gidNumber: 801
homeDirectory: /home/nssproxy

Fix Permissions: Alow NSS Read Passwords

Добавляем группе nss права на чтение паролей/хешей паролей

0009_FixPermissionsAlowNSSReadPAsswords.ldif
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to *
  by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
  by * break
olcAccess: {1}to attrs=userPassword,shadowLastChange
  by self write
  by anonymous auth
  by dn="cn=admin,dc=fuel_domain" write.
  by group.exact="cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain" read
  by * none
olcAccess: {2}to dn.subtree="ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain"
  by dn="cn=admin,dc=fuel_domain" write.
  by group.exact="cn=nssproxy,ou=Group,dc=customer_organization,dc=fuel_domain" read
  by anonymous auth
  by * none
olcAccess: {3}to dn.base=""
  by * read
olcAccess: {4}to *
  by dn="cn=admin,dc=fuel_domain" write
  by * read

Вносить исправление через ldapi:///

ldapmodify -Y EXTERNAL  -H ldapi:/// < 0009_FixPermissionsAlowNSSReadPAsswords.ldif

Sudo Scheme

Cхема для sudo (как ее генерировать описано в отдельном разделе)

0010_SudoScheme.ldif
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 caseExactIA5SubstringsMatch 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 caseExactIA5SubstringsMatch 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 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.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 'Options(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 'User(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 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start 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: {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 integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch 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 Entries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ description ) )

Sudoers

Файл sudoers (как его генерировать описано в отдельном разделе)

0010_sudoers.ldif
dn: cn=defaults,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: sudoRole
cn: defaults
description: Default sudoOption's go here
sudoOption: env_reset
sudoOption: mail_badpass
sudoOption: secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
sudoOrder: 1

dn: cn=root,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: sudoRole
cn: root
sudoUser: root
sudoHost: ALL
sudoRunAsUser: ALL
sudoRunAsGroup: ALL
sudoCommand: ALL
sudoOrder: 2

dn: cn=%admin,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: sudoRole
cn: %admin
sudoUser: %admin
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: ALL
sudoOrder: 3

dn: cn=%sudo,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: sudoRole
cn: %sudo
sudoUser: %sudo
sudoHost: ALL
sudoRunAsUser: ALL
sudoRunAsGroup: ALL
sudoCommand: ALL
sudoOrder: 4

dn: cn=%fuel_users,ou=sudo,ou=services,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: sudoRole
cn: %fuel_users
sudoUser: %fuel_users
sudoHost: ALL
sudoRunAsUser: ALL
sudoRunAsGroup: ALL
sudoCommand: ALL
sudoOrder: 5

Сброс паролей для служебных пользователей

Пароли всем пользователям ставлю (для теста) - по номеру ноды, например для node-1 пользователь будет nssproxy-node1 с паролем '1111'

0011_setPaswordsAndCheck.sh
for N in `seq 1 4`
do
  echo user=nssproxy-node${N}
  ldappasswd -H ldaps://ldap -s ${N}${N}${N}${N} uid=nssproxy-node${N},ou=service_users,dc=customer_organization,dc=fuel_domain -D "cn=admin,dc=fuel_domain" -w 'r00tme'

  ldapsearch  -D "uid=nssproxy-node${N},ou=service_users,dc=customer_organization,dc=fuel_domain" -w ${N}${N}${N}${N} -b 'dc=fuel_domain' -H ldaps://ldap '(objectclass=*)'
done

Test user

Пользователь который добавляется для демонстрации - изначально не имеет прав sudo.

9902_User_test_user
dn: uid=test1,ou=People,dc=customer_organization,dc=fuel_domain
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: test1
cn: test1 test1
sn: test1
givenName: test1
title: test user for demo
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.test1.noname.com.ua/
loginShell: /usr/bin/sudosh
uidNumber: 9998
gidNumber: 9998
homeDirectory: /home/test1
description: This is me :)


dn: cn=test1,ou=Group,dc=customer_organization,dc=fuel_domain
changetype: add
cn: test1
objectClass: posixGroup
gidNumber: 9998
description: Fuel Users
memberUid: test1

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

Вынесено в отдельный документ:

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

SUDO

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

Ссылки


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