Существует ли способ корректной аутентификации пользователя в рамках пользовательского сеанса PAM?
В настоящее время я пишу свой собственный модуль аутентификации PAM, который позволяет пользователю входить в систему через внешний токен. Этот токен должен быть сгенерирован до того, как пользователь сможет войти в систему с помощью моего модуля. Поэтому я хотел бы вернуться к аутентификации PAM по умолчанию, когда токена нет, и продолжить работу с моим кодом, как только пользователь аутентифицируется.
Возможно ли это как-то? В псевдокоде мой модуль выглядит так:
pam_sm_authenticate() {
if (first_login) {
code_copied_from_pam_unix_to_authenticate_user();
// do something else here?
} else {
custom_auth();
}
}
В качестве быстрого решения я скопировал код из модуля pam_unix Linux в свой собственный, и он работает. Однако это не очень удовлетворительно, так как требует много дополнительных библиотек и будет работать только до тех пор, пока pam_unix не изменится. Я бы предпочел открыть еще один сеанс PAM внутри своего сеанса, но у меня это не работает.
решение1
Не позволяйте вашему коду выполнять всю логику: сначала используйте PAM и его конфигурацию, чтобы убедиться, что ваш модуль работает в наилучших условиях (т. е. не требует копирования pam_unix
кода).
Для начала позвольте мне предложить еще один псевдокод для вашего модуля:
pam_sm_authenticate() {
if (first_login) return PAM_CRED_INSUFFICIENT;
else custom_auth();
}
Здесь я считаю,первый входбыть случаем недостаточности учетных данных. Я сообщаю PAM, что модуль дает сбой, поскольку у него нет всего необходимого для полной аутентификации пользователя. Теперь, предположив, что ваш модуль называется my_module
, возможная конфигурация будет такой:
auth [cred_insufficient=ok success=done default=2] my_module.so
auth [success=ok default=1] pam_unix.so
auth sufficient my_module.so
auth requisite pam_deny.so
Вот подробности:
Сначала запрос проходит через
my_module
. Здесь есть несколько возможностей:- Первый вход: ваш модуль вернул
PAM_CRED_INSUFFICIENT
. Этот случайпойманныйс помощью PAM (черезcred_insufficient
), в этом случае он настроен на отметку цепочки как успешной (ok
), нопродолжать идти. - Это был не первый вход, вы прошли
custom_auth()
и он был успешным (он вернулсяPAM_SUCCESS
). В этом случае мы ставим точку в цепочке (done
):доступ предоставлен. - Это был не первый вход в систему, и
custom_auth()
он не завершился хорошо (PAM_AUTH_ERR
или другие внутренние ошибки). В этом случае пропустите следующие 2 строки (default=2
). Цепочка переходит прямо вpam_deny
, что всегда приводит к ошибке:доступ запрещен.
- Первый вход: ваш модуль вернул
В первом сценарии цепочка продолжается до
pam_unix
. Здесь есть две возможности:- Аутентификация UNIX прошла успешно. Это отмечает цепочку как успешную (
ok
) ипереходит к следующему модулю. - Аутентификация UNIX не удалась. Следующий модуль пропускается (
default=1
), и цепочка заканчивается наpam_deny
:доступ запрещен.
- Аутентификация UNIX прошла успешно. Это отмечает цепочку как успешную (
Если вы достигли третьей строки, это означает, что
my_module
закончилось сPAM_CRED_INSUFFICIENT
первым разом, и что этоpam_unix
удалось. Ваш модуль снова вызывается (// do something else here?
) какsufficient
. Снова две возможности:- На этот раз ваш модуль справился успешно:доступ предоставлен.
- Модуль снова дает сбой, но уже по другой причине, нежели недостаточность учетных данных:доступ запрещен.
Вы также можете захотеть выполнить пользовательский кодпосле аутентификации UNIX, даже если это не удалось. Чтобы сделать это, измените вторую строку на:
auth [success=ok default=bad] pam_unix.so
Это заставит цепочку пройти my_module
еще раз, несмотря ни на что, но цепочка будет отмечена какнеуспешный. Даже если ваш модуль завершится успешно, цепочка даст сбой.
Вы также можете захотеть, чтобы ваш модуль знал, сколько раз мы вызывали его в цепочке: отличайте первый вызов my_module
от второго. Это можно легко сделать с помощью аргументов:
auth [cred_insufficient=ok success=done default=2] my_module.so
auth [success=ok default=1] pam_unix.so
auth sufficient my_module.so second_time
auth requisite pam_deny.so
Здесь второму вызову pam_sm_authenticate
будет передан аргумент (через argv
и argc
), который должен вам помочьнайтиваш модуль в цепочке во время выполнения. Конечно, вашего firstLogin
условия должно быть достаточно, чтобы сделать такое различие.