如何在LightDM的PAM模块中获取非本地用户输入的密码用于API认证
问题分析与解决
核心问题1:代码中pam_get_item调用错误
你当前代码的参数传递存在错误,导致无法正确获取认证令牌。pam_get_item需要接收一个指向指针的地址来存储获取到的内容,而非空的指针指针。修正后的代码如下:
/* include PAM header files */ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { const void *authTok = NULL; int statusCode; // 获取用户名 const void *userName = NULL; statusCode = pam_get_item(pamh, PAM_USER, &userName); if (statusCode != PAM_SUCCESS || userName == NULL) { syslog(LOG_ERR, "Failed to get username: %d", statusCode); return statusCode; } // 获取认证密码 statusCode = pam_get_item(pamh, PAM_AUTHTOK, &authTok); if (statusCode != PAM_SUCCESS || authTok == NULL) { syslog(LOG_ERR, "Failed to get auth token: %d", statusCode); return statusCode; } // 使用userName和authTok调用外部API进行认证 // ... return statusCode; } int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_SUCCESS; }
核心问题2:PAM模块权限与配置问题
即使代码修正,仍可能遇到PAM_PERM_DENIED,需检查以下几点:
PAM配置顺序:打开LightDM的PAM配置文件(通常为
/etc/pam.d/lightdm),确保自定义模块处于负责收集密码的模块之后。比如依赖系统模块收集密码的配置示例:auth required pam_unix.so auth required pam_your_custom_module.so针对非本地用户,可替换
pam_unix.so为适配模块,或让自定义模块主动触发密码输入。模块文件权限:自定义PAM模块需设置正确权限,一般为
root:root所有,权限设为755或644,避免因权限不足被PAM拒绝访问。SELinux限制:若系统开启SELinux,需确保模块安全上下文符合PAM要求。可执行
chcon system_u:object_r:pam_modules_t:s0 /path/to/your/module.so调整上下文,或临时关闭SELinux测试是否为其导致的权限问题。
备选方案:主动获取密码
若依赖前置模块设置PAM_AUTHTOK不可行,可在自定义模块中主动调用pam_prompt获取用户输入:
#include <pam_appl.h> #include <syslog.h> int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { struct pam_message msg; const struct pam_message *msg_arr[1]; struct pam_response *resp = NULL; const void *userName = NULL; int statusCode; // 获取用户名 statusCode = pam_get_item(pamh, PAM_USER, &userName); if (statusCode != PAM_SUCCESS || userName == NULL) { syslog(LOG_ERR, "Failed to get username: %d", statusCode); return statusCode; } // 构造密码提示消息 msg.msg_style = PAM_PROMPT_ECHO_OFF; msg.msg = "Password: "; msg_arr[0] = &msg; // 调用pam_prompt获取密码 statusCode = pam_conv(pamh, 1, msg_arr, &resp, NULL); if (statusCode != PAM_SUCCESS || resp == NULL || resp[0].resp == NULL) { syslog(LOG_ERR, "Failed to get password via prompt: %d", statusCode); if (resp != NULL) { pam_free(pamh, resp[0].resp); pam_free(pamh, resp); } return statusCode; } // 使用userName和resp[0].resp调用外部API // ... // 清理资源 pam_free(pamh, resp[0].resp); pam_free(pamh, resp); return PAM_SUCCESS; }
内容的提问来源于stack exchange,提问作者random_user
相关产品推荐
相关产品推荐

