使用 PAM

PAM(可插拔认证模块)是一种机制,允许不同的应用程序使用各种指定的参数进行身份验证,例如使用 passwd/shadow 文件、Kerberos 服务器、LDAP 服务器或 NT 域服务器(使用 Samba)。

使用 PAM,程序只需要为给定的登录类别(在 pam.d 文件中定义)请求身份验证,PAM 框架将负责调用提供身份验证的模块。

pamd 文件的结构

但让我们看看 pamd 文件的结构。首先,pamd 文件放置在 /etc/pam.d 中,并且它们被组织为每行一个语句。语句由 3 或 4 个标记组成。

  • 第一个标记指定执行语句的服务类型。有四种类型
    • account,用于检查用户帐户的有效性。
    • auth,使用密码或其他方式(如生物识别和智能卡设备)验证用户是否是声称的用户。
    • password,负责更改用户的密码。
    • session,涵盖诸如检查用户有效性或挂载/卸载主目录等任务,在用户会话开始前和关闭后均执行。
  • 第二个标记是控制,它告诉 PAM 如何处理指定模块的身份验证失败和成功。
    • requisite,失败会导致进程终止。
    • required,失败会导致服务失败,但在失败之前,所有其他模块都将被执行。
    • sufficient,如果之前没有 required 模块失败,则此模块的成功会导致身份验证成功。
    • optional,在这种情况下,如果这不是唯一的模块,则忽略失败或成功,在这种情况下,它的成功或失败会导致身份验证成功或失败。
  • 第三个标记是要为该服务类型执行的模块;PAM 模块是可扩展的,顾名思义,是可插拔的。结果是,存在少量默认模块和一些外部可选模块,这些模块可以针对 PAM 实现构建以定义其他身份验证方法。一些文档指出我们需要指定模块的完整路径,但这会造成问题,因为并非所有系统都将模块安装在相同的位置:Gentoo 上的 Linux-PAM 通常设置为从 /lib/security 加载它们,但例如在 AMD64 上,这将变为 /lib64/security。结果是,提供完整路径会导致 pamd 文件无法工作,正确的处理方法是只说明模块名称 - PAM 实现将负责查找模块。
  • 最后一个标记(可以包含多个项目)描述传递给模块的参数。这些是依赖于模块的。
  • pam_deny.sopam_permit.so - 它们只报告失败或成功
  • pam_rootok.so 如果用户是 root,则报告成功,否则报告失败
  • pam_nologin.so 检查 /etc/nologin 文件中是否存在阻止用户登录的原因 - 例如,当最好避免用户在受损系统上登录时使用它
  • pam_securetty.so 检查登录是否在配置文件认为安全的 tty 中完成(取决于实现)
  • pam_unix.so 是 Unix 系统的基本模块,它只使用 /etc/passwd/etc/shadow 检查用户/密码对。

还有其他模块可用于针对数据库(mysql 或 postgresql)、LDAP 目录或 NT 域(使用 samba)进行更复杂的身份验证。这在瘦客户端或胖客户端上很有用,在这些客户端上,用户对所有机器都有唯一的登录名。另一个有用的地方是服务器集群,这些服务器需要针对某些服务(例如邮件和 ftp 服务器)的单个来源进行身份验证。

但是对于桌面系统,所有不同的服务,例如邮件服务器、ftp 服务器、ssh 等,只需要以用户登录到系统的方式进行身份验证。

为了实现这一点,RedHat 为 Linux-PAM(它没有依赖其他身份验证方案的方法)开发了一个 pam_stack.so 模块,该模块接受参数 "login=<login service to use>",告诉 PAM 执行所述服务的 auth 堆栈。

不幸的是,该模块依赖于 Linux-PAM 的内部数据结构和对其他 PAM 实现无效的假设,因此它完全不可移植。它并非在所有 Linux-PAM 实现中都使用(例如,MacOS X 使用 Linux-PAM 但不提供 pam_stack.so),因此并非所有 Linux 发行版中都存在。

当 AltLinux 开发人员为控制标记添加了一个新的指令时,解决方案出现了:include。自 Linux-PAM 0.78 以来,可以使用该控制标记来执行与 required pam_stack.so 相同的操作,将模块名称替换为要模仿的登录类别的名称。

这样,而不是加载一个模块,该模块依次重新加载 pam,该选项由 PAM 实现直接解析,该实现加载另一个登录类别并负责执行它。

安装 pamd 文件

pamd 文件的正确位置是 /etc/pam.d,但手动安装并检查 pam USE 标志很棘手,并且不遵循与 initd 和 confd 文件相同的路径,因此解决方案是使用 pam eclass。

pam eclass 中,有一些函数提供了 pamd 文件的安装工具(dopamdnewpamd,其用法与类似的 do*new* 函数相同)以及 /etc/security 文件(dopamsecuritynewpamsecurity,它们需要第一个参数作为 /etc/security 中要安装文件的子目录)。这些函数组已经负责验证 pam USE 标志是否对软件包是可选的 - 如果是这样,并且该标志被禁用,则 pamd 文件将被跳过。

许多 pamd 文件只使用 system-auth 登录类中的一个或多个 auth 类型,这是提供大多数常用桌面系统上大多数服务登录功能的基本类型。为此,无需在 ${FILESDIR} 中添加 pamd 文件,可以使用 pamd_mimic_system 函数。此函数接受一系列参数 - 第一个参数是登录类别的名称(/etc/pam.d 中 pamd 文件的名称);其他参数是需要使用 system-auth 的 auth 类型。

例如,类似以下的调用

pamd_mimic_system foo auth password

安装一个 /etc/pam.d/foo 文件,其中包含

auth        include     system-auth
password    include     system-auth

它只使用 system-auth 登录类别。

安装 PAM 模块

由于 PAM 模块在不同实现上的不同目录中查找,这也取决于具有多个 ABI 的 ARCH 的 libdir 名称,因此通常不可能信任模块声明的默认目录(如果模块声明默认目录始终如此)。此问题的解决方案也在 pam eclass 中。函数 getpam_mod_dir 返回当前实现/架构要使用的正确目录。

当 PAM 模块本身不提供安装软件包的方法时,例如 Makefile 或安装脚本,还有 dopammodnewpammod 函数,它们负责将模块安装到正确的目录中。