Как обработать возвращаемое значение PAM_AUTHTOK_RECOVERY_ERR от pam_authenticate для действительного пользователя и пароля?

Я пытаюсь написать какой-нибудь сервер, который проверяет подлинность клиентов с помощью Linux PAM. Я написал следующий класс:

class Pam
{
public:
Pam(const char *module, const char *username)
{
mConv.appdata_ptr = nullptr;
mConv.conv = &convCallback;
const int res = pam_start("system-auth", username, &mConv, &mPamHandle);
if (res != PAM_SUCCESS)
throw std::runtime_error("Failed to initialize PAM");
}

bool authenticate(char *passwd)
{
pam_response *resp = static_cast<pam_response*>(malloc(sizeof(pam_response)));
resp->resp = passwd;
resp->resp_retcode = 0;
mConv.appdata_ptr = resp;
const int res = pam_authenticate(mPamHandle, 0);
log(res);
return res == PAM_SUCCESS;
}

~Pam()
{
if (mPamHandle)
pam_end(mPamHandle, PAM_SUCCESS);
mPamHandle = nullptr;
}
private:
static int convCallback (int msgId, const pam_message **msg, pam_response **resp, void *appData)
{
*resp = static_cast<pam_response*>(appData);
return PAM_SUCCESS;
}

private:
pam_handle_t *mPamHandle = nullptr;
pam_conv mConv;
};

Который затем используется как:

Pam pam("system-auth", username);
if (pam.authenticate(passwd))
return true;
// error handling code here

Я обнаружил, что pam_authenticate возвращает PAM_AUTHTOK_RECOVERY_ERR для действительного пользователя / пароля. Возможные возвращаемые значения описаны в справочной странице и на linux-pam.org. http://www.linux-pam.org/Linux-PAM-html/adg-interface-by-app-expected.html#adg-pam_authenticate не содержат это значение вообще. Документация говорит, что это может быть возвращено pam_chauthtok, и это означает:

PAM_AUTHTOK_RECOVERY_ERR

Модуль не смог получить старый токен аутентификации.

И до сих пор неясно, что это значит в случае аутентификации. Я пытался запустить код как обычного пользователя, так и root, результат был одинаковым.

0

Решение

То, что происходит, это то, что вы видите 0 как значение appData в convCallback, откуда исходит ошибка — данные ответа пустые, что означает плохой разговор, который вызывает PAM_AUTHTOK_RECOVERY_ERR возвращаемое значение Это основано на чтении support.c файл в текущем коде для исходного кода PAM-Linux.

Хорошо, пару вопросов.

  1. Вы не можете переназначить значение диалога appdata_ptr после инициализации — значение указателя следует считать константой после вызова pam_start, Вы должны передать туда значение, которое никогда не изменится. Если бы вы проверили функцию разговора, вы бы заметили, что значение appData является 0,

  2. Вы должен Предположим, что значение, вводимое в ответ, принадлежит вызывающей подпрограмме, т. е. вам нужно будет ввести строку пароля (со всем злом, связанным с этим).

Имея это в виду, я немного изменил ваш код следующим образом, который должен решить ваши проблемы (опять же, это упрощенный код):

class Pam
{
public:
Pam(const char *module, const char *username)
{
mConv.appdata_ptr = (void *)(this);
mConv.conv = &convCallback;
const int res = pam_start(module, username, &mConv, &mPamHandle);
if (res != PAM_SUCCESS)
throw std::runtime_error("Failed to initialize PAM");
}

bool authenticate(char *passwd)
{
mPassword = passwd;
const int res = pam_authenticate(mPamHandle, 0);
log(res);
return res == PAM_SUCCESS;
}

~Pam()
{
if (mPamHandle)
pam_end(mPamHandle, PAM_SUCCESS);
mPamHandle = 0;
}
private:
static int convCallback (int msgId, const pam_message **msg, pam_response **resp, void *appData)
{
Pam *me = static_cast<Pam *>(appData);
pam_response *reply = static_cast<pam_response *>(calloc(1, sizeof(pam_response)));
reply->resp = strdup(me->mPassword);
reply->resp_retcode = 0;
*resp = reply;
return PAM_SUCCESS;
}

private:
pam_handle_t *mPamHandle = 0;
pam_conv mConv;
const char *mPassword = 0;
};
1

Другие решения


По вопросам рекламы [email protected]