自制PAM模块:SSH登录时pam_sm_authenticate被调用两次的原因咨询
解答:SSH登录时PAM模块的pam_sm_authenticate被调用两次的原因与解决办法
我之前开发自定义PAM模块时也碰到过一模一样的问题!这种情况其实是SSH和PAM交互的正常特性,当然也可能和你的配置有关,下面给你拆解原因和排查方案:
主要原因
- SSH的双认证流程设计:SSH协议在登录时会优先尝试无密码认证方式(比如公钥认证),哪怕你没配置公钥登录,SSH服务端也会先走这个流程触发一次PAM调用;当无密码认证失败后,才会切换到密码认证,这时候会第二次调用PAM的authenticate函数。你可以看看
sshd_config里的PasswordAuthentication和ChallengeResponseAuthentication配置,这两个开关会影响认证阶段的数量。 - PAM栈的多阶段触发:如果你的
/etc/pam.d/sshd配置文件里有多个auth类型的条目,或者某些内置模块(比如pam_unix.so)带有try_first_pass、use_first_pass这类选项,也可能导致PAM模块被重复调用。
排查与解决步骤
开启SSH调试日志定位触发场景
修改sshd_config中的LogLevel为DEBUG3,然后重启SSH服务:sudo systemctl restart sshd之后登录时查看系统日志(通常是
/var/log/auth.log或/var/log/secure),你会清晰看到两次调用的触发来源——比如第一次是keyboard-interactive认证阶段,第二次是password阶段。检查PAM配置栈
打开/etc/pam.d/sshd,查看auth段的配置。如果你的自定义模块pam_hook.so被放在了多个auth条目里,或者和其他模块的逻辑冲突,就会重复执行。建议把自定义模块放在合适的位置,比如仅在密码认证阶段触发。在模块代码中区分调用场景
在你的pam_sm_authenticate函数里添加日志,打印调用时的flags参数和上下文:#include <syslog.h> // ... PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { pam_syslog(pamh, LOG_DEBUG, "pam_sm_authenticate called, flags: %d", flags); // 其他逻辑... }通过日志里的
flags值,你可以区分两次调用的场景(比如第一次可能带有PAM_SILENT,第二次带有PAM_PASSWORD_PROMPT),然后在代码里决定是否执行核心验证逻辑——比如只在密码认证的调用中处理用户名密码验证,其他场景直接返回PAM_SUCCESS。
额外提示
其实这种两次调用是符合SSH和PAM的规范设计的,如果你不需要处理无密码认证阶段的调用,完全可以在模块里通过状态标记或者flags判断来跳过重复逻辑,避免重复执行验证操作。
内容的提问来源于stack exchange,提问作者Omer Anisfeld




