我正在尝试编写一些使用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 :(得分:1)
正在发生的事情是,0
中appData
的值为convCallback
,这是错误发生的地方 - 回复数据为空,这意味着错误会话,导致PAM_AUTHTOK_RECOVERY_ERR
返回值。这是基于读取PAM-Linux源代码的当前代码中的support.c
文件。
好的,有几个问题。
初始化后无法重新分配对话appdata_ptr值 - 在调用pam_start
后,指针的值应视为常量。你应该传递一个永远不会改变的值。如果您选中了对话功能,则会注意到appData
的值为0
。
这一点)。
考虑到这两点,我稍微改变了您的代码,以解决您的问题(再次,这是简化的代码):
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;
};