Библиотека сайта rus-linux.net
Разработка модулей PAM, часть 2
Оригинал: Writing PAM Modules, Part TwoАвтор: Jennifer Vesperman
Дата публикации: 23 Мая 2013 г.
Перевод: А.Панин
Дата перевода: 20 Февраля 2013 г.
Аббревиатура PAM расшифровывается как Pluggable Authentication Modules (система подключаемых модулей аутентификации) и используется для обозначения системы, позволяющей приложениям осуществлять независимую аутентификацию. Приложение, работающее с PAM, использует стек модулей PAM для осуществления аутентификации, открытия и закрытия сессий и проверки работоспособности учетной записи.
Данная статья является второй частью серии из трех статей о разработке модулей PAM. В первой части была приведена необходимая для разработки модулей информация, а в третьей будут рассмотрены критические функции, которые должен предоставлять каждый модуль. В данной же статье приводятся описания функций, которые придется использовать автору модуля.
Пакеты и файлы
В данных статьях приводится описание приложения на языке C++, так как большинство масштабируемых приложений разрабатывается с применением именно этого языка и его отличия от языка C, хотя они и существуют, не являются значительными. Вы можете разрабатывать совместимые с системой Linux PAM модули, используя любой язык программирования в том случае, если он позволяет вам осуществлять вызовы необходимых функций языка C.
Для начала вам необходимо установить заголовочные файлы для разработки. В системе Debian это делается с помощью команды apt-get install libpam0g-dev
. Эта команда позволяет установить необходимые файлы исходного кода, разместив их в тех директориях, где компилятор g++ сможет их найти.
Вам будет необходимо включить заголовочный файл в в файл исходного кода вашего модуля при помощи директивы #include <security/pam_modules.h>.
При компиляции вам будет необходимо осуществить связывание модуля с файлами библиотеки libpam
. В моем файле makefile
для этого используется строка: g++ -omodule_name -lpam sourcefile
.
#define PAM_SM_ACCOUNT #define PAM_SM_AUTH #define PAM_SM_PASSWORD #define PAM_SM_SESSION
Установка и получение значений элементов PAM
Большая часть необходимой модулю информации может быть получена или передана с помощью элементов PAM. Эти элементы относятся к определенным сессиям PAM и идентифицируются с помощью хэндлов. Хэндл PAM передается каждой из основных функций модуля в качестве параметра.
pam_set_item()
и pam_get_item()
для передачи или получения данных с помощью элементов PAM.
extern int pam_set_item(pam_handle_t *pamh, int item_type, const void *item); extern int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item);
Доступные типы элементов PAM могут быть разделены на группы.
- PAM_SERVICE
- Имя приложения в рамках системы PAM, не обязательно то имя приложения, которое видит пользователь.
- PAM_CONV
- Работа со структурой обмена данными (Смотрите следующий раздел).
- PAM_FAIL_DELAY
- Указатель на функцию
PAM_FAIL_DELAY
. Некоторые приложения производят замену версии данной функции из PAM.
- PAM_USER
- Имя пользователя, под которым производится аутентификация. Обычно безопаснее использовать функцию
pam_get_user()
, чем осуществлять запрос имени напрямую. - PAM_USER_PROMPT
- Приглашение, которое модуль должен использовать при запросе имени пользователя.
- PAM_RUSER
- Идентификатор пользователя, запрашивающего аутентификацию, обычно имя пользователя, вызвавшего приложение.
- PAM_RHOST
- Имя узла для системы, с которой происходит запрос аутентификации.
- PAM_TTY
- Имя терминала (для консольных приложений) или значение переменной
$DISPLAY
(для приложений с графическим интерфейсом). Вы можете получить имя терминала с помощью функцииttyname()
.
- PAM_AUTHTOK
- Данные аутентификации. Элемент должен игнорироваться всеми модулями кроме модулей для аутентификации и смены пароля и использоваться только совместно с функциями
pam_sm_authenticate()
иpam_sm_chauthtok()
. - PAM_OLDAUTHTOK
- Предыдущие данные аутентификации. Элемент должен использоваться только совместно с функцией
pam_sm_chauthtok()
в модулях для работы с паролями.
Кроме статуса PAM_SUCCESS
, функции для работы с элементами PAM могут также возвращать статусы PAM_SYSTEM_ERR
, PAM_PERM_DENIED
, PAM_BUF_ERR
или PAM_BAD_ITEM
.
Функция обмена данными
Приложение может выводить сообщение, используя неограниченное количество форматов. Сообщения приложений с графическим интерфейсом разительно отличаются от сообщений приложений с интерфейсом командной строки, а оба этих вида сообщений в свою очередь отличаются от сообщений зашифрованной сессии HTTP или сессии FTP.
Система PAM освобождает разработчика от проблем форматирования сообщений, требуя от приложения реализации функции обмена данными (conversation function). Эта функция передает сообщения от модуля и знакомит пользователя с ними, а также передает ответы пользователя модулю.
pam_get_item(pamhandle, PAM_CONV, &item)
позволяет получить указатель на структуру обмена данными. Эта структура состоит из указателя на функцию обмена данными conv
и указателя appdata_ptr
, который приложение может использовать для обмена данными с модулем.
struct pam_conv { int (*conv)(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); void *appdata_ptr; };
Модуль использует описанную функцию для передачи сообщений пользователю. Модуль может передавать единовременно как одно сообщение, так и группу сообщений. Приложение должно определить, будут ли сообщения показаны пользователю группой или по отдельности.
pam_message
, предназначенные для хранения строк сообщений, которые должны быть выведены приложением. Указателем на этот массив является параметр msg
, при этом каждая структура содержит и сообщение и спецификатор форматирования сообщения. Параметр num_msg
задает длину массива сообщений.
struct pam_message { int msg_style; const char *msg; };
- PAM_ERROR_MSG
- Вывод сообщения об ошибке.
- PAM_PROMPT_ECHO_OFF
- Получение строки с подавлением вывода.
- PAM_PROMPT_ECHO_ON
- Получение строки без подавления вывода.
- PAM_TEXT_INFO
- Вывод сообщения.
Приложение должно предоставить массив структур pam_response
в ответ на запрос. Модуль должен предоставить указатель, значение которого должно быть изменено приложением таким образом, чтобы он указывал на массив этих структур. Да, взаимодействие происходит с помощью запутанных путей. Указатель, используемый для этой цели модулем, представлен параметром resp
.
struct pam_response { char *resp; int resp_retcode; };
Переменная resp_retcode
в структуре ответа на данный момент не используется и обычно ее значение устанавливается равным 0.
Следует отметить, что указатель appdata_ptr
является последним параметром функции - это важно. Приложение может использовать указатель appdata_ptr
для передачи с помощью функции данных, которые ему могут потребоваться, поэтому убедитесь в том, что вы используете именно этот указатель.
Кроме статуса PAM_SUCCESS
, функция обмена данными также может возвращать статус PAM_CONV_ERR
.
Получение имени пользователя
Получение имени пользователя может представлять сложный процесс - сначала должен использоваться соответствующий элемент PAM, после этого вызываться функция обмена данными и задаваться подходящее приветствие для запроса имени пользователя. К счастью, система PAM может выполнить эту работу за вас с помощью функции pam_get_user()
.
pam_get_user
вместо того, чтобы выполнять эту работу самостоятельно. Это проще, понятнее при чтении кода и в случае изменения процесса получения имени пользователя, вам не придется делать ровным счетом ничего!
extern int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt);
Не освобождайте память, зарезервированную для хранения данных пользователя. Последующий вызов функции pam_get_user()
или вызов функции pam_end()
сделают это за вас.
Значение возвращаемого статуса PAM_SUCCESS
очевидно. Другими возвращаемыми статусами являются PAM_CONV_ERR
, указывающий на то, что имя пользователя не может быть получено, и PAM_CONV_AGAIN
.
В том случае, если вы получили статус PAM_CONV_AGAIN
, верните управлению приложению с помощью передачи статуса PAM_INCOMPLETE
, а при следующем вызове функции pam_get_user()
с данным хэндлом PAM вы сможете получить данные.
Сохранение и получение данных
Автор модуля не может предсказать то, как модуль будет загружен, поэтому вы должны избегать использования статических переменных. Функции для сохранения и получения данных позволяют ассоциировать данные с хэндлом PAM. Данные, сохраненные с помощью данной функции, будут доступны другим модулям, но не приложению.
Параметр cleanup
позволяет задать специальную функцию корректного освобождения зарезервированной для хранения данных памяти. В случае, если такой функции не требуется, может использоваться значение NULL.
В качестве значения параметра error_status
могут объединяться с помощью логического "ИЛИ" значения PAM_DATA_REPLACE
для указания последующему вызову на необходимость замены данных и PAM_DATA_SILENT
для того, чтобы функция освобождения ресурсов не оставляла записей в системном журнале и не отправляла сообщений пользователю.
pam_get_data()
должна вернуть PAM_NO_MODULE_DATA
.
Управление переменными окружения
Система Linux-PAM поддерживает работу отдельного окружения, ассоциированного с текущим хэндлом PAM. После создания окружение не содержит переменных.
- extern const char *pam_getenv(pam_handle_t *pamh, const char *name);
- Возвращает значение заданной переменной окружения Linux-PAM или NULL в случае неудачи.
- extern const char * const *pam_getenvlist(pam_handle_t *pamh);
- Возвращает указатель на текущий список переменных окружения Linux-PAM, предназначенный только для чтения.
- extern int pam_putenv(pam_handle_t *pamh, const char *name_value);
- Позволяет установить сбросить или удалить заданную переменную окружения. Аргумент
name_value
является строкой с завершающим нулевым значением (в представлении языка C). Поддерживаемые форматы:- name=value
- Устанавливает значение переменной 'name' равным 'value'
- name=
- Устанавливает значение переменной 'name' равным пустой строке
- name
- Удаляет переменную 'name'
Безопасная работа с памятью
Любые участки памяти, которые ваш модуль не будет впоследствии освобождать, должны резервироваться с помощью функции std::malloc()
из стандартной библиотеки языка C. Операторы new
и delete
могут также использоваться, но только для участков памяти, которые вы будете освобождать самостоятельно.
Заключительные слова
Данная статья является второй частью серии из трех статей по разработке модулей PAM. В первой части рассматривались теоретические основы функционирования системы PAM и принципы работы, которые должны быть реализованы в рамках модуля. В третьей части серии приводится описание функций, которые обязан предоставлять каждый модуль, а также обсуждение вопросов безопасности и кодов ответов.
Дополнительные ресурсы