Как использовать OpenLDAP в ОС Debian GNU/Linux
1.Вместо введенияВ этой статье пойдет речь о том, как в пользовательских приложениях настраивать и использовать сервер, утилиты и библиотеку OpenLDAP, обеспечивающие доступ к Службе директорий и операцией с ней. 1.2. Что такое LDAP и какие ошибки следует избегать при его использованииСлужба Директорией является специализированной базой данных, предназначенной для поиска и отображения, в дополнение к уже имеющимся базовым функциям просмотра и обновления. Самой яркой одной из таких базовых функций является Служба Переключения Имен(Name Named Switch — NSS), которая используется для просмотра и модификации учётных записей пользователей NSS баз данных: group, passwd и их теневых паролей shadow. Поэтому используя протокол LDAP можно осуществлять расширение этой службы за счёт централизованной аутентификации пользователей в локальной вычислительной сети(ЛВС) или в объеме корпоративной вычислительной сети(КВС), являющейся порой совокупностью нескольких ЛВС. Сегодня, вокруг использования этого протокола началось полное сумасшествие. Начинают хранить все что можно вплоть до службы DHСP, осуществляющей ретрансляцию MAC-адреса и IP-адреса, службы имен DNS и т.д., что не столь востребовано клиентом локальной сети, потому что служба LDAP обращается к ним локально, только на сервере. Конечно же, если не идет речь о большой КВС, где такой подход может быть востребован из-за большего количества серверов. А для небольшой организации имеющий несколько десятков ПЭВМ(и менее), образующих ЛВС, где порой в качестве сервера такой сети может выступать одна из них, это будет весьма громоздкое решение. Аббревиатура LDAP происходит от Lightweight Directory Access Protocol, который переводится с английского как Легковесный протокол доступа к директории. Как следует из имени, он является облегчённым протоколом доступа к директориям сервисов на основе директорий протокола X.500. LDAP выполняется через TCP/IP протокол или другие соединения ориентированные на передачу данных. Этот протокол описывается в RFC 4510 в "Lightweight Directory Access Protocol (LDAP) Technical Specification Road Map". Протокол в ОС Debian GNU/Linux реализуется сервером slapd, являющийся автономно работающим LDAP демоном, который производит доступ к каталогу через любой порт стека TCP/IP протоколов, по-умолчанию номер которого установлен равным 389. Количество баз данных(каталогов) не лимитируется. Для того, чтобы сервер slapd знал об этих каталогах необходимо их указать в файле /etc/ldap/slapd.conf. При использовании openldap версии 2.3 и выше помните, что в нем теперь существует возможность хранить конфигурацию сервера в формате ldif-записи. Поэтому не удивляйтесь, если в директории /etc/ldap/ не найдете slapd.conf, потому что по умолчанию установлен метод динамической конфигурации данных(dynamic config backend). Если Вы ещё не успели освоить его, можно использовать старый способ конфигурации через файл slapd.conf. Библиотека LDAP является клиентом сервера slapd и используется приложениями для выполнения запросов связанных с созданием и изменением данных в LDAP каталогах через одноимённый протокол. 2. Установка требуемого программного обеспеченияВ ОС Debian GNU/Linux для нормальной работы сервиса LDAP нужно установить следующие пакеты, реализующие поддержку OpenLDAP:
Для установки этих пакетов в ОС Debian GNU/Linux, версии 6.0.5 и выше с кодовым обозначением "Squeeze", необходимо выполнить,
Рекомендую пропустить настройку slapd во время установки, потому что настройку этого пакета мы проведем позднее. На все задаваемые вопросы отвечайте просто нажатием клавиши enter. 3. Обработка ошибок в OpenLdapПомните статью Как использовать библиотеку XML в ОС Debian GNU/Linux, в ней мы создавали файл ldapsi-msg.xml, а потом в нем же искали код ошибки LDAP, чтобы вывести в диалоге ldap-error. Это код ошибки автор будет использовать в приложении ldap-users-admin, чтобы получать расширенную информацию о случившихся ошибках во время использования API-функций библиотеки libldap и/или протокола LDAP. Перечисленные коды ошибок можно условно разделить на две группы: результат выполнение API-функций и самого протокола LDAP. У автора нет желания переписывать LD_ERRNO(3) и он надеется, что читатель сам сможет разобраться с помощью этой справочной страницы какие коды к какой из двух групп относятся и что они обозначают. Единственно, что хочу сказать, что ситуации во время работы приложения бывают разные и поэтому необходимо учитывать такие вещи как коды ошибок, позволяющие уберечь свою программу от неправильной интерпретации событий. Коды ошибок берутся из переменной errno библиотеки С(GLIBC), которая объявлена в <errno.h> и устанавливается немедленно во время использования семейств функций ldap_init(3), ldap_bind(3) и т.д. Разве, что кроме асинхронных функций, таких как ldap_search_ext(3) и ldap_modify_ext(3), которые используют ldap_result(), для получения кода ошибки LDAP. Дело в том, что члены маркера клиентского соединения с LDAP сервером закрыты для публичного доступа. Он декларируется структурой struct ldap как пользовательский тип LDAP, содержащей поле ld_errno, значение которого потом с помощью макроса LDAP_SET_ERRNO присваивается переменной errno библиотеки С. Поэтому всегда в коде программы нужно включать через дерективу#include заголовочный файл <errno.h> . Единственное, что могу посоветовать, когда будете использовать переменную errno, то это использовать LDAP_API_RESULT(n), который определяет относится данная ошибка к API или протоколу, а так же, если выполнение API-функций завершилось успешно. Обычно в коде используют функцию ldap_perror(), особо не заморачиваясь на счёт написания каких-то там XML-файлов, содержащих коды ошибок LDAP, когда эта функция сама все вернет, остаётся только ей передать маркер LDAP соединения и дело в шляпе. Автор использовал файл, как пример ldapsi-msg.xml для наглядности работы библиотеки XML и будет он использовать эту часть в проекте ldap-users-admin, не смотря на громоздкость решения. Вам же рекомендую обходиться этой функцией для экономии времени и сил. 4. Настраиваем сервер slapdКогда вы устанавливали пакет slapd, автор этой статьи вас просил пропустить настройку slapd, которую мы с вами произведем сейчас. Для этого, давайте вызовем dpkg-reconfigure, который перенастраивает уже установленные пакеты. В качестве единственного параметра мы укажем пакет slapd, вследствии чего, будут заданы вопросы по настройке пакета. Их, как вы увидете, будет больше чем во время инсталляции этого пакета apt-get, поэтому автор и просил вас оставить его настройку на потом.
После чего будет осуществлена настройка slapd и нам останеться лишь ответить на следующие вопросы:
Учтите, что в таблице для DNS Domain name и Name of Organization указаны настройки для моей ПЭВМ, у вас же должно быть что-то другое, но если вам лень что-то придумывать самим можете использовать их. Как показала практика расхождение имени реального домена DNS и указанного в DNS Domain name роли не играет, впрочем как и Name of Organization. Но, лучше избегать таких расхождений, чтобы избегать неприятностей в будущем, в общем вам решать самим. Теперь переходим к настройке нашего с вами каталога "dc=engine,dc=local", который соответствует тому, что вы вводили в DNS Domain name. Эти настройки храняться в файле /etc/ldap/slapd.conf и относятся к базе данных #1. Поэтому открывайте этот файл в текстовом редакторе, которому вы отдаете свои предпочтения, и спускайтесь на первую строку парметров базы данных #1. Ниже приводится дамп фрагмента файле /etc/ldap/slapd.conf, а жирным цветом на что вам нужно обратить внимание.
Как видно из дампа файла /etc/ldap/slapd.conf, который можно было бы и не открывать, все устанавливается автоматически, но чтобы не было в будущем проблем, когда мы будем устанавливать libpam-ldap и libnss-ldap вы должны обратить внимание на следующие дерективы.
Не забудте после изменения переменной directory копировать содержимое из /var/lib/ldap в /srv/ldap . 5.Инициализация соединения с сервером LDAPПосле того, как мы с вами настроили и запустили сервер LDAP, в роли которого у нас выступает демном slapd, мы можем перейти к инициализации соединения c сервером. Что будем делать через вызов функции ldap_init(). Эта функция создает маркер LDAP, но не откроет само соединение. Это событие случится позднее, когда будет сделана первая операция. Ниже представлен протип функции
Функции в первом аргументе host пердается имя узла, на котором запущен сервер. В втором аргументе port — номер порта. По умолчанию, мы всегда должны назначать номер порта равным 389, который выделила "Администрация адресного пространства Интернет"(IANA). Функция ldap_init() возвращает указатель на маркер LDAP или вместо него нулевой указатель. В этом случае рекомендую завершить процедуру инициализации соединения с сервером LDAP. Откладывая соединение с сервером LDAP на потом, мы с вами пользуемся этим моментом и устанавливаем версию протокола LDAP через ldap_set_option(). Помните, когда нас при повторной настройке сервера спрашивали "Allow LDAPv2 protocol?", мы c вами отвечали "No".Так вот, поэтому мы должны передать опцию LDAP_VERSION3. Если же вы ответили "Yes" то, тогда вы должны передать опцию LDAP_VERSION2, которая указывает использовать вторую версию протокола LDAP. Взглянем на прототип функции.
А первом аргументе ld мы передаем маркер LDAP, который ранее создали функцией ldap_init(). В втором аргументе option мы передаем код опции, а в третьем — её значение. Третий аргумент является указателем разыменованного типа, который использует тип void. Такой тип указателя используется потому, что значение передаваемые опции может иметь различную размерность. Поэтому, здесь используется такой трюк с обобщенным указателем, которым является invalue . Сам часто использую такие указатели, когда имеется неоднозначность в размерности передавемых по нему переменных. В нашем случаем, мы будем передавать в втором аргументе option код опции LDAP_OPT_PROTOCOL_VERSION, а для передачи значения, типа int, равное LDAP_VERSION3 или LDAP_VERSION2 в зависимости от того какую версию протокола LDAP мы выбрали. Функция ldap_set_option() возвращает значение LDAP_OPT_SUCCESS в случае успешного завершения. Иначе, она вернет LDAP_OPT_ERROR, которая означает, что произошла ошибка.
Все, что мы сделали с помощью ldap_init(), так это просто зафрахтовали соединение с сервером LDAP и выделили память под маркер LDAP. Соединение будет произведено тогда, когда мы введем rootdn от лица которого оно будет создано. Потому что в текущей конфигурации LDAP сервера мы имеем одну такую персону, указанную в rootdn как admin.engine.local . Это производится на стадии связывания через ldap_bind() или ldap_bind_s(). Так же можно использовать ldap_simple_bind() или ldap_simple_bind_s(), если вы не планируете использовать соединения с использованием SASL (Simple Authentication and Security Layer) без криптографической поддержки. SASL — простая аутентификация и слой безопасности, являщиесятся методом для добавления поддержки аутентификации в протоколы соeдинения, в нашем случае, таким протоколом является LDAP. Тут SASL вставляется между протоколом и соединением, что позволяет обеспечить безопасную передачу данных, к числу которых относится пароль администратора LDAP, хранящийся в rootdn. Если убрать этот пароль, то любой желающий сможет изменять учетные записи пользователей и групп, которыми управляет программа ldap-users-admin. В версии этой программы будет использован простая аутентификация(Simple authentication) SASL, которая не защищает передаваемый пароль, поэтому он имеют риск быть разоблаченным. Следовательно использоваться API-функции ldap_sasl_bind() и ldap_sasl_bind_s(), использующие криптографическую пакет Cyrus-SASL, не будут использованы в настоящей версии программы ldap-users-admin.
Первым аргументом во всех четырех функциях является маркер LDAP, который передается по указателю ld. Вторым аргументом является указатель who, по-которому будем передовать rootdn в принятой нотации, как cn=admin,dc=engine,dc=local. В третьем аргументе — cred или passwd передаем пароль, который присваивали учетной записи администратору во время настройки сервера LDAP. В четвертом параметре в ldap_bind()/ldap_bind_s() передаем код метода аутентификации механизма SASL. Задачей этих функций является связывать пароли переданного в password или cred c паролем, который находится в userPassword узла DN, которым в нашем случае является rootdn. Функции оканчивающиеся на _s в случае ошибки возвращают код ошибки errno, описанный в ldap_error(3), в том числе и LDAP_SUCCESS, который соответствует успешному завершению API-функции. Теперь мы можем внести в наш предыдущий код правки, чтобы создать соединение с сервером LDAP.
Как вы можете увидеть, в коде произошли значительные изменения, которые связанные с добавлением ldap_simple_bind_s(), ldap_unbind_s() и обертки-функции ldap_disconnect_server(). Эту функцию необходимо будет вызывать всякий раз, когда нужно завершить соединение с сервером LDAP. Если вы этого не сделаете, то не будет освобождена память, выделяемая под маркер LDAP, который описывает соединения с LDAP-сервером. Это всегда нужно делать, т.к. если сервер при завершении процесса разорвет соединение по сигналу BROKEN_PIPE, а выделенную память, кроме как ldap_unbind() или ldap_unbind_s(), никто не освободит, вы просто рискуете столкнуться с банальной утечкой памяти. Функции ldap_disconnect_server() не производит обработку ошибок. Если функция ldap_unbind_s() не смогла завершить соединение с LDAP-сервером, что делать в этом случае, оставляю на ваш умотрение. Поэтому эта функция ничего не возвращает, а только выводит ошибку на stderr через ldap_perror().Как вы увидели, у нас изменилось число аргументов функции ldap_connect_server() и её прототип в целом. К ранее уже используемым аргументам hostname, port и proto_ver добавились who и password. В предыдущей записи аргументов в определении функции использовалась "новая запись". В ней аргументы функции перечисляются вместе с типом в одной последовательности через запятую ','. Такой способ записи принято называть "старая запись". В ней в скобках после имени функции следуют только имена параметров, а после скобок объявление типов аргументов функции. В аргументе who мы передаем узел DN, по которому будет производится связывание с LDAP-сервером, а в аргументе password — пароль, который находится в userPassword узла DN. Если у вас возникают проблемы со связыванием и ldap_bind(), к примеру, возвращает Invalid credentials (49), проверте пару узел DN и его пароль с помощью утилиты ldapsearch из пакета ldap-utils. Где в дополнительном аргументе опции "-b" должен быть указан узел DN, согласно принятой нотации записи DN в протоколе LDAP.
Что будет соответствовать использованию функции ldap_connect_server() следующим образом
Соответственно, "localhost" является именем узла на котором запущен LDAP сервер, а LDAP_PORT — определённой в <ldap.h> по умолчанию номер порта, который равен 389. Два последние указателя являются нулевыми. Таким способом через ldapsearch можно проверить не только возможность связывания с узлом DN без пароля, но и по паролю, как показано ниже.
Что будет соответствовать использованию функции ldap_connect_server() следующим образом
Дополнительно к имени узла и номеру порта, на котором весит сервер LDAP, добавился узел DN и пароль, по которому произойдет связывание с LDAP-сервером. 6. Использование LDAP вместе с службой переключения именВ своих двух статьях про учетные записи пользователей, группы и теневые пароли рассказывал, как используется Служба переключения имён, Name Switch Service(NSS), и как производятся операции с этими учётными записями, которые используются во время авторизации пользователя, разграничения прав доступа или запуска программы(процесса) от его лица. Мы помним, что все эти записи доступны только локально, что исключает возможности организации групп пользователей в ЛВС, что не совсем удобно, если планируется использовать сетевую распределенную программу в локальной сети, где потребуется удаленный доступ к NSS, такая как программа Автоматизированного учёта приёма пациентов в Медицинском центре Тем самым средством удаленного доступа является NSS-модуль для использования LDAP как сервера имен, который предоставляет пакет libnss-ldap. Он позволяет соединить несоединимое, а именно LDAP-сервер и Службу переключению имен, известную как NSS(Name Service Switch). С помощью этого модуля можно подсоединить учётные записи пользователей и групп хранящиеся в базе данных LDAP-сервера, как будто они храняться в локакальных базах данных group, passwd и shadow службы NSS. Поэтому не раздумывая устанавливаем пакет libnss-ldap.
По-мимо пакета libnss-ldap, будут установлены пакеты libpam-ldap и nscd, речь о которых пойдет ниже. Кроме того, во время установки этих пакетов будут заданы вопросы по их конфигурации, которые рекомендую пока пропустить, потому что эти пакеты все равно прийдется настраивать позднее с помощью dpkg-reconfigure. При конфигурировании пакета libnss-ldap нужно запретить специальные привелегии LDAP для root. Если они были заданы, то нужно произвести конфигурацию этих пакетов снова.
Теперь нужно изменить порядок просмотра баp данных в службой имен. Для чего необходимо отредактировать файл /etc/nsswitch.conf .
На этом с настройкой пакета libnss-ldap все, а теперь мы можем перейти к созданию учетных записей пользователей и групп. Как писал об этом уже ранее, пользователи и их теневых паролей храняться в базах данных passwd, а на нашем сервере они будут хранится в ou=People,dc=engine,dc=local, а группы пользователей в ou=Group,dc=engine,dc=local . Теперь отвлечемся на теорию о представлении данных в LDAP раз мы их уже коснулись. LDAP-сервер содержит данные составляющие дерево каталагов(или директорий) информации, directory information tree (DIT). Такая модель представления информации базируется на записях, которые содержат наборы атрибутов, различаемые по Отличительному имени, Distinguished Name(DN). Такие DN используются для обеспечения однозначности при обращении к записи. Каждый из атрибутов записи имеет тип и один или несколько значений. Типы представляются обычно мнемоническими строками. У нас в нашей модели DIT будет использоваться два типа записей ou и cn. В libnss-ldap дерево разбивается на две ветви DN ou=Group и DN ou=People, которые свою очередь имеют дочерние DN c тип cn и содержащие атрибутами учетных записей групп пользователей, самих пользователей и теневых паролей. Давайте взглянем на само дерево. Как видно из дерева, которое использует libnss-ldap для хранения учётных записей пользователей, их групп и их теневых паролей, оно разветвляется на узле dc=engine на два подграфа:
Атрибуты узлов DN, тип CN, для пользователей и их теневых паролей являются:
Для узлов DN, тип CN, групп пользователей, указан только два атрибута gidNumber уникальный номер группы и cn — символьного имени группы. Он же задает имя узла DN. Автору этой статьи известно, как минимум ещё об одном атрибуте, который задает члены этой группы. Думаю, что как его использовать, вы изучите самостоятельно. Теперь перейдем от теории к практики и создадим с начала группы root и ldap_users. Для чего будем пользоваться утилитой ldapadd(1). Эта утилита, на сегодня, требует, чтобы ей на стандартный вход через опцию -f передавался ldif-файл, содержащие в себе узлы DN. В нашем случае, это будет ou=Group,dc=engine,dc=local, cn=root,ou=Group,dc=engine,dc=local(группа суперпользователя) и cn=user,ou=Group,dc=engine,dc=local(группа обычных пользователей) c соответствующими атрибутами, которые мы рассматривали только что. Предвижу такую ситуацию, когда уникальный номер 1000, уже занят другой группой. Поэтому предлагаю вашему вниманию скрипт get_groupsgid.sh, который рассчитает вам уникальный номер для группы ldap_users.
Ниже привожу результат работы скрипта, который показал, что максимальный номер группы равен 1022. Это значит, как минимум, начиная с номера 1022, и как максимум до номера 65534, который занимает nogroup, мы можем использовать для группы ldap_users.
Теперь после, того как нам стал известен gidNumber для группы пользователей ldap_users, мы можем смело написать ldif-файл nss-groups.ldif.
Только что написанный файл nss-groups.ldif мы добавляем к директории dc=engine,dc=local дочерние, которые являются её узлами, а именно подграф с вершиной ou=Group,dc=engine,dc=local. Корневой директорией, как мы помним, у нас является dc=engine,dc=local. Остальные узлы у нас относятся к структурной части организации или подразделения, Organizational Unit(ou), которая обычно состоит из общепринятых имён,Common names(cn). А вот какого типа записей содержит DN задается через objectClass, или иначе говоря, каждый DN представляет собой объект или набор атрибутов, которые ему соответствуют. Мало того, атрибут objectClass определяет какие другие атрибуты должен иметь объект. Мало того, если мы указываем в атрибуте objectClass, то мы указываем к какому классу объекту принадлежит DN, мы должны не забывать, что ему на LDAP-сервере должна быть определена соответствующая схема. Так к классу объекту posixGroup,posixAccount, или shadowAccount будет соответствовать схема nis.schema, которая определяется на LDAP-сервере через директиву include в его конфигурационном файле /etc/ldap/slapd . По-мимо отношений объекта к службе NSS, наш объект имеет обязательный класс объекта top, который указывает на то, что этот объект может иметь дочерние объекты и являться им родительским.
Теперь, точно так же как и для ou=Group,dc=engine,dc=local создаем файл nss-users.ldif добавления узлов, а именно подграф с вершиной ou=People,dc=engine,dc=local, как мы помним эта вершина будет содержать DN c учётными записями пользователей. Поэтому, сначала мы получим максимальный номер идентификатора пользователя, чтобы уникальные идентификаторы локальных пользователей не вступали в противоречие с раздаваемыми с LDAP сервера. Поэтому предлагаю вашему вниманию скрипт get_usersuid.sh, который рассчитает вам уникальный номер для группы users.
Ниже привожу результат работы скрипта, который показал, что максимальный номер пользователя равен 1009. Это значит, как минимум, начиная с номера 1009, и как максимум до номера 65534, который занимает пользователь nobody, мы можем использовать для наших пользователей my_user и other_user
Теперь напишем ldif-файл для того, чтобы добавить выше означанных пользователей на LDAP-сервер. Мы напишем ldif-файл nss-users.ldif, который создаст подграф с вершинной ou=People,dc=engine,dc=local и DN c пользователями Super User, My user и Other user.
Завершаем возню с DN пользователями и заливаем файл nss-users.ldif на LDAP-сервер.
Остается внести изменения в /etc/nsswitch.conf и попробывать выполнить getent group и getent passwd, только не забудте перезапустить сеанс после внесения изменений в файл /etc/nsswitch.conf.
В редакторе gedit вносим изменения в файл /etc/nsswitch.conf базы данных passwd,group,shadow службы NSS.
После того, как настроили libnss-ldap мы можем приступить к настройки libpam-ldap, но перед этим рекомендую создать загрузочную флешку, а уже, затем мучить PAM-модули. Это потребуется, в том случае, если вы сделаете ошибку и не сможете войти в систему из-за ошибок в настройках PAM-модулей. Сначало настраиваем пакет libpam-ldap через dpkg-reconfigure, который попросит ответить вас на следующие вопросы, которые привожу ниже с рекомендуемыми ответами
После чего, вносим изменения в общие файлы PAM-цепочек, имеющие префикс common и находящиеся в /etc/pam.d. common-auth
common-account
common-session
common-password
После чего, должны изменить пароль учетной записи root через passwd(1).
Теперь мы должны перегрузить наш компьютер на котором настраивали libpam-ldap. Иначе, вы не сможете изменить пароль у пользователей my_user, other_user. 6. Модель единого пользователя для ЛВСЭта модель оперирует двумя пространствами учетных записей — глобальным и локальным. Глобальное пространство учетных записей пользователей применимо на всех узлах ЛВС, которыми являются сервер и его клиенты. Почему клиенты? Потому что учетные записи пользователей находятся на сервере и распределяются по узлам ЛВС через клиент-серверное соединение, которое образуется между клиентом(libnss-ldap) и LDAP-сервером(демон slapd). Потому глобальное пространство состоит из учетных записей, которые хранятся на LDAP-сервере в директории "ou=People,dc=engine,dc=local" и раздаются по клиентам ЛВС. К локальному же пространству относятся все учетные записи, которые находяться в базе passwd службы NSS. Данный пример использования LDAP-сервера, которым является демон slapd, и связки LDAP-NSS-PAM, которую реализуют libnss-ldap и libpam-ldap, позволяет сосуществовать двум пространствам и производить в них необходимые изменения для обеспечения жизнедеятельности ЛВС и самих узлов в ней, которыми являются компьютеры рабочих станций и сервер с установленным на них ОС Debian GNU/Linux. В этих учетных записях обычно храняться пользователи от лица которых запускаются демоны(службы) для устранения возможности несанкционированного доступа и пользователи с суперпользователем root, которых вы, ранее, создавали сами или во время инсталляции ОС Debian GNU/Linux. В используемом мной варианте настройки связки LDAP-NSS-PAM лежит именно модель единого пространства пользователя, которое является глобальное пространством учётных записей пользователей. Оно это пространство сосуществует вместе с локальным пространством учетных записей пользователей. Поэтому было бы разумно назначить разные диапазоны уникальных идентификаторов пользователей и их групп, что в принципе мы и сделали, когда находили с помощью скриптов get_groupsgid.sh и get_usersuid.sh минимальные уникальные идентификаторы для учётной записи пользователя(uid) и группы(gid) в базе passwd службы NSS. Потом, мы их увеличивали на единицу, тем самым делая эти идентификаторы минимальным числом для создания учётных записей пользователей и групп на LDAP-сервере. Локальное и глобальное пространство пользователя должно пересекаться только в двух точках или в двух учетных записях пользователей root и nobody, но последнюю не обязательного указывать на сервере LDAP, потому что она есть на каждом узле ЛВС, в том числе и сервере. Так, что же нужно дублировать? Только учетную запись пользователя root, т.к. он имеет вход в систему, а первым куда за учетными записями пользователя будет обращаться механизм аутентфикации PAM, так это к учетным записям на сервере LDAP, а не к локальной базе passwd службы NSS. Даже не смотря на то, что в NSS обращение к LDAP серверу стоит на последнем месте. 7. Операции с учетными записями групп и пользователей на LDAP-сервереКогда мы создавали соединение с сервером LDAP в аргументе rootdn, к функции ldap_simple_bind_s(), мы указывали cn=admin,dc=engine,dc=local, а следом за ним передавали пароль или вместо него нулевой указатель. Тем самым, нам разрешалось читать и/или вносить изменения в записи корневого каталога dc=engine,dc=local, которым является первая база LDAP-сервера с которым мы установили соединение. В используемых, здесь настройках безопасности доступа к информационным директориям LDAP-сервер, использован тот же принцип, что и в NSS службе для баз данных passwd, group и shadow. Соответственно, без пароля, или передачей нулевого указателя соответствующему аргументу функции ldap_simple_bind_s(), мы имеем только право чтения, а с паролем чтения и записи. Операции над записями информационных директорий LDAP деляться на синхронные и асинхронные. Но, это деление производится не по функциональному признаку, т.е. по типу действий с данными в записях информационных директорий LDAP, а по тому, как и каким образом Вы собираетесь их использовать. Любая синхронная операция подразумевает, что вы дожидаетесь результат операции, а асинхронная операция, что в данный момент он вас не интерисует или этот результат вам некогда ждать по причине временных издержек. В нашей схеме безопасности, хоть это не правильно, мы разделим операции над записями информационных директорий LDAP по функциональному признаку на синхронные и асинхронные. К синхронным операциям относятся добавление, удаление и модификации. В общем, все функции, которые требуют в нашей схеме безопасности LDAP сервера пароль. Но, это не значит, что нельзя его снять и использовать эти операции без пароля. По этому, первыми их рассмотрим. 7.2. Синхронные операцииПочему вдруг решил использовать синхронные функции для добавления, удаления или модификации записей информационных директроий LDAP? Потому что эти операции требуют гарантированного выполнения и, соответсвенно, если возникают нештатные ситуации они тут же обрабатываются, а не потом, когда поезд уже ушел. Особенно, это нужно учитывать в операциях с учетными записями пользователей, групп и теневых паролей для службы NSS. Иначе, потом можно получить не работающую систему в которой не возможно не только создать сессию пользователя, но и запустить программу из-за чехарды с владельцами и их группами. Первой мы рассмотрим функцию ldap_modify_ext_s(), которая позволяет модифицировать не только записи, но и сами информационные директории LDAP. Хочу сразу обратить внимание на тех, кто использовал это фукнция ранее, что ldap_modify_s() была запрещена для использования в новом коде и используется только для обеспечения обратной совместимости с старами версиями программного обеспечения.
В первом аругменте ld передается маркер LDAP, в втором аргументе dn в символьной нотации DN-узел LDAP-директории, в котором будем модифицировать записи в передаваемом третьем аргументе mods, являющийся двухмерный массивом указателей, заканчивающейся нулевым-указателем. В этом массиве передаются LDAPMod-структуры, котрая представлена ниже
Поле структуры mod_op используется для указания типа операции, на которые должен указывать один из определяющих её макросов LDAP_MOD_ADD, LDAP_MOD_DELETE или LDAP_MOD_REPLACE. Поля mod_type и mod_values(modv_strvals или modv_bvals) указывают модифицируемые типы аттрибутов и вмести с ним null-завершаемый двухмерный массив значений для добавления, удаления или изменения соответсвенно. Поле mod_next используется только LDAP-сервером и должен быть игнорирован клиентом, в роли которого выступает ваша программа. Если вам необходимо указать не значение, состоящее из строки символов, к примеру имя пользователя или его имя входа в систему, а добавить его фотографию или аудиозапись с его голосом, вы должны установить LDAP_MOD_BVALUES в mod_op через логическое ИЛИ вместе одной из операций, указанных ранее(например LDAP_MOD_REPLACE). В этом случае, вы должны использовать указатель на духмерный массив mod_bvalues(modv_bvals) взамен указателя на двухмерный массива mod_values(modv_strvals), которые оба содержат NULL-завершаемые массивы, состоящих из структур bervals так, как это определено в <lber.h>. Для LDAP_MOD_ADD модификаций, данные значения добавляются к записи и при необходимости с созданием атрибута. Для LDAP_MOD_DELETE модификаций, данные значения удаляются из записи и удалается атрибут, если в нем не осталось значений. Если весь атрибут был удален, то поле mod_values должно быть обнулено NULL-указателем. Для LDAP_MOD_REPLACE-модификаций, атрибут будет иметь перечисленные значения после модификации, которые могут быть созданы, если это потребуется. Все модификации исполняются в том порядке, в каком они были указаны. Два последних аргумента sctrls и cctrls функции ldap_modify_ext_s() предназначаются для контроля за обменом между клиентом и сервером, но пока не ясно как их использовать мы будем их обнулять. Функция в случае ошибки возвращает код ошибки errno, описанный в ldap_error(3), в том числе и LDAP_SUCCESS, который соответствует успешному завершению этой API-функции. Функция ldap_mods_free() может использоваться для освобожения выделенной памяти в общей куче, а не стеке, нуль-завершаемых массивов, которые мы передовали по указателю mod_values(modv_strvals или modv_bvals) в структуре LDAPMod, соответственно передаем в первом аргументе mod. Если второй аргумент freemods содержит не нулевое значение, то функция ldap_mods_free() будет пытаться освобободить память, выделенную под двойной указатель. |
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Copyright © 2010 rjaan as Andrey Rjavskov(Rzhavskov) <rjaan@yandex.ru> <arjavskov@gmail.com> |