为何自定义PAM模块适用于sudo却无法在ssh中显示二维码?
这是个挺典型的PAM模块适配问题,我来帮你拆解下核心原因和解决方向:
PAM栈的执行阶段不匹配
你在sudo su时能看到二维码,大概率是把模块加到了sudo对应PAM配置(比如/etc/pam.d/sudo)的auth阶段。但SSH登录的PAM流程完全不同:当你用SSH登录时,sshd的PAM配置(/etc/pam.d/sshd)可能在auth阶段优先走了公钥验证(比如pam_publickey.so或pam_sss.so),你的模块如果只挂在auth阶段,要么根本没机会执行,要么执行时终端还没和用户会话绑定,输出传不到客户端。
建议你把模块加到sshd配置的session阶段(比如写一行session optional your_qr_module.so)——session阶段是在用户会话完全建立后触发的,此时终端已经就绪,输出能正常传递到SSH客户端。TTY关联的问题
sudo su是在已有的本地终端会话里执行,PAM模块的输出直接指向当前TTY。但SSH登录过程中,模块执行时用户的TTY可能还没被正确分配或关联。如果你的模块代码里只是直接往stdout输出二维码,而没有主动获取当前会话的TTY设备(比如通过pam_get_item(pamh, PAM_TTY, &tty)),那这个输出可能会被丢到“虚空”里,根本到不了客户端。
解决思路:在模块代码里主动获取会话的TTY路径,然后直接向这个TTY设备写入二维码内容,别依赖默认的stdout。SSH服务器的输出限制配置
有些sshd配置会间接抑制PAM模块的输出:比如sshd_config里的PrintMotd no、UsePrivilegeSeparation sandbox(新版本默认配置),可能会把PAM模块的输出隔离在沙箱里;或者如果你的模块输出依赖系统Motd机制,而SSH又禁用了Motd打印,也会看不到内容。
建议检查sshd_config里的相关选项,确保没有限制PAM会话的输出;同时让模块直接写TTY,不要依赖Motd这类间接输出方式。模块的PAM类型不兼容
如果你的模块是按auth类型实现的(也就是只写了pam_sm_authenticate函数),那在SSH用公钥登录的场景下,auth阶段可能直接跳过密码验证流程,你的模块根本不会被调用。而sudo su默认会触发auth阶段的密码验证,所以模块能正常执行。
最优解是把模块改成session类型(实现pam_sm_open_session函数),这样不管SSH用哪种验证方式(密码/公钥/其他),只要用户会话建立,模块就会自动执行并输出二维码。
内容的提问来源于stack exchange,提问作者user8039956

