可插拔认证模块-PAM


可插拔认证模块(PAM)是一种将多个低级认证方案集成到高级应用程序编程接口(API)中的机制,可以让依赖于身份验证的程序独立于底层的身份验证方案编写。PAM 最初由太阳微系统(SUN)在1995年10月的开放软件基金会的请求意见稿(RFC)86.0中提出。它被用作通用桌面环境的身份验证框架。作为独立的开源基础结构,PAM 于1996年8月在 Linux PAM 项目中首次出现在 Red Hat Linux 3.0.4中。当前操作系统中,AIX、DragonFlyBSD、FreeBSD、HP-UX、Linux、macOS、NetBSD 和 Solaris 均支持PAM,下文还会介绍在 Linux 下派生出的 Linux-PAM。
由于不存在规范 PAM 行为的中心标准,后来有人尝试将 PAM 标准化为 X/Open UNIX 标准化过程的一部分,从而产生了X/Open Single Sign-on(XSSO)标准。 该标准尚未获得批准,但是其草案可供后来的PAM实现(例如OpenPAM)参考。
由于大多数 PAM 实现本身都不与远程客户端交互,PAM 本身无法实现 Kerberos(Unix环境中最常见的SSO类型)。这导致SSO被合并为可能的XSSO标准的“主要认证”部分,并且出现了诸如SPNEGO和 SASL 之类的技术。这种功能上的缺乏也是 SSH 自己实现身份验证机制协商的原因。
在大多数PAM实现中,pam_krb5只能获取票据授权票据(TGT),这涉及到提示用户输入凭据,并且仅用于SSO环境中的初始登录。如要在不提示用户再次输入凭据的前提下,获取特定应用程序的服务票证,则必须对该应用程序进行特定的编码以支持 Kerberos,这是因为 pam_krb5 本身无法获取服务票证(尽管有些 PAM-KRB5 版本正试图解决该问题)。
PAM 为管理员提供了很大的灵活性来为系统设置身份验证策略,对开发人员和管理员而言是有用的系统,原因如下:
1. 提供一种常见身份验证方案,可用于各种应用。
2. 为系统管理员提供了对身份验证的显著灵活性和控制力。
3. 提供单个全文档库,允许开发人员编写程序,而无需创建自己的身份验证方案。
Linux PAM(Pluggable Authentication Modules)是一个系统级用户认证框架,其将程序开发与认证方式进行分离,程序在运行时调用附加的“认证”模块完成自己的工作,本地系统管理员通过配置选择要使用哪些认证模块。其采用C语言开发并在GPL或BSD协议下授权使用。
Linux-PAM separates the tasks of authentication into four independent management groups:
1.account modules check that the specified account is a valid authentication target under current conditions. This may include conditions like account expiration, time of day, and that the user has access to the requested service.
2.authentication modules verify the user's identity, for example by requesting and checking a password or other secret. They may also pass authentication information on to other systems like a keyring.
3.password modules are responsible for updating passwords, and are generally coupled to modules employed in the authentication step. They may also be used to enforce strong passwords.
4.session modules define actions that are performed at the beginning and end of sessions. A session starts after the user has successfully authenticated.
PAM 是在运行过程中被动态链接使用的。更改对于已通过身份验证的用户无效;调试 PAM 的一种方法是最好在测试机器上本地登录并进行开发,保持会话不断运行,同时检查另一个控制台上另一个用户的结果。
PAM 手册 pam(8) 和 pam.d(5) 中描述了配置文件的标准规范,手册分四部分:账户,认证,密码和会话管理,同时还包括了配置项的可选内容。此外在目录 /usr/share/doc/Linux-PAM/index.html 包含多种指导文档,包括了每种标准模块的 man 手册。

The high-level steps taken when a locally-defined user logs into a text-based console:
1. The login application prompts for a user name and password, then makes a libpam authentication call to ask, "Is this user who they say they are?" The pam_unix module is responsible for checking the local account authentication. Other modules may also be checked, and ultimately the result is passed back to the login process.
2. The login process next asks, "Is this user allowed to connect?", then makes an account call to libpam. The pam_unix module checks for things like whether the password has expired. Other modules might check host or time-based access control lists. An overall response is handed back to the process.
3. If the password has expired, the application responds. Some applications simply fail to log in the user. The login process prompts the user for a new password.
4. To get the password verified and written to the correct location, the login process makes a password call to libpam. The pam_unix module writes to the local shadow file. Other modules may also be called to verify the password strength.
5. If the login process is continuing at this point, it is ready to create the session. A session call to libpam results in the pam_unix module writing a login timestamp to the wtmp file. Other modules enable X11 authentication or SELinux user contexts.
6. On logout, when the session is closed, another session call can be made to libpam. This is when the pam_unix module writes the logout timestamp to the wtmp file.
PAM 配置文件说明(RPM系统)
/usr/lib64/security
A collection of PAM libraries that perform various checks. Most of these modules have man pages to explain the use case and options available.
/etc/pam.d
A collection of configuration files for applications that call libpam. These files define which modules are checked, with what options, in which order, and how to handle the result. These files may be added to the system when an application is installed and are frequently edited by other utilities.
Since there are several checks done by all applications, these files may also have include statements to call other configuration files in this directory. Most shared modules are found in the system-auth file for local authentication and the password-auth file for applications listening for remote connections.
/etc/security
A collection of additional configuration files for specific modules. Some modules, such as pam_access and pam_time, allow additional granularity for checks. When an application configuration file calls these modules, the checks are completed using the additional information from its corresponding supplemental configuration files. Other modules, like pam_pwquality, make it easier for other utilities to modify the configuration by placing all the options in a separate file instead of on the module line in the application configuration file.
/var/log/secure
Most security and authentication errors are reported to this log file. Permissions are configured on this file to restrict access.
man pam
This man page describes the overall process, including the types of calls and a list of files involved.
man pam.conf
This man page describes the overall format and defines keywords and fields for the pam.d configuration files.
man -k pam_
This search of man pages lists pages available for modules installed.
PAM 配置文件格式
每个 PAM 配置文件包含一组指令,这些指令定义模块(身份验证配置区域)以及其中的任何控制或参数。这些指令都具有简单的语法,可识别模块用途(接口)和模块的配置设置。
module_interface control_flag module_name module_arguments
在 PAM 配置文件中,模块接口是定义的第一个字段。例如:
auth required pam_unix.so
PAM配置文件通常分为四列:
第一列代表模块类型或接口
"类型"(type | interface)可分为四种(auth,account,password,session)之一。若在类型前加上"-"(减号)前缀,则表示即使模块不存在,也不会影响认证结果,更不会将此事件记录到日志中,对于那些可有可无的模块来说,这一特性非常有用。
第二列代表控制标记
"控制标志"(control-flag)用于控制模块在流程栈中的行为。该字段有两种语法,一种是简单语法,一种是复杂语法,用于描述 PAM 认证流程的执行规则。
第三列代表模块路径(名称)
"模块路径"(module-path | name)表示模块的文件系统路径,既可以是绝对路径,也可以是相对路径(相对于 /lib/security/ 或 /lib64/security/ 目录),模块文件名一般都符合 pam_*.so 格式。注意,当第二个字段(控制标志)的值是"include"或"substack"时,相对路径表示相对于 /etc/pam.d/ 或 /usr/lib/pam.d/ 目录的路径。
第四列代表模块参数
"模块参数"(module-arguments)用于控制模块的行为,它是一组用空格分隔的参数列表,每个模块能够使用的参数各不相同,详见后文"常用模块"小节。如果想在某个参数中使用空格,那么必须在该参数外围加上中括号(字符串中的"["无需转义,但"]"必须转义为"\]")。例如 passwd=mada [query=select user_name from internet_service where user_name='%u' and password=PASSWORD('%p')]
注意,配置文件中的任何语法错误都会导致认证过程失败,同时失败信息将会被记录到系统日志(syslog)中。
流程栈
所谓"流程栈"是指执行步骤和规则,非常类似于程序逻辑的概念,它体现在配置文件自上而下的执行顺序中。"栈"就像是一段可以嵌套的程序逻辑,通过"substack"关键字,可以在一个栈(父栈)中嵌入另一个栈(子栈)。 PAM 流程栈的执行规则由配置文件中的第二个字段"控制标志"(control-flag)决定,可以把"控制标志"想象成逻辑控制语法。该字段有两种语法,一种是简单语法,一种是复杂语法。
1)PAM的模块类型
Linux-PAM有四种模块类型,分别代表四种不同的任务,它们是:
认证管理(auth),账号管理(account),会话管理(session)和密码(password)管理,一个类型可能有多行,它们按顺序依次由PAM模块调用。
2)第二列:PAM的控制标记
PAM使用控制标记来处理和判断各个模块的返回值。
规定如何处理PAM模块鉴别认证的结果,简而言之就是鉴别认证成功或者失败之后会发生什么事,如何进行控制。单个应用程序可以调用多种底层模块,通常称为“堆叠”。对应于某程序按照配置文件中出现顺序执行的所有模块成为“堆”,堆中的各模块的地位与出错时的处理方式由control_flag栏的取值决定,他的四种可能的取值分别为required、requisite、sufficient、optional 或 include。
3)模块路径
模块路径.即要调用模块的位置. 如果是64位系统,一般保存在/lib64/security,如: pam_unix.so,同一个模块,可以出现在不同的类型中.它在不同的类型中所执行的操作都不相同.这是由于每个模块,针对不同的模块类型,编制了不同的执行函数。
4)模块参数
模块参数,即传递给模块的参数。参数可以有多个','之间用空格分隔开,如:password required pam_unix.so nullok obscure min=4 max=8 md5。
PAM 接口基本上是该特定模块可以执行的身份验证流程栈式操作类型。可用的模块类型接口有四种,分别对应于身份验证和授权过程的不同方面(每行只能指定一种接口类型,如果程序需要多种接口的话,可在多行中分别予以规定):
auth - 此模块接口验证用户。例如,它请求并验证密码的有效性。带有此接口的模块也可以设置凭据,如组成员资格。表示鉴别类接口模块类型用于检查用户和密码,并分配权限;这种类型的模块为用户验证提供两方面服务。让应用程序提示用户输入密码或者其他标记,确认用户合法性;通过他的凭证许可权限,设定组成员关系或者其他优先权。
account - 此模块接口验证是否允许访问。例如,它会检查用户帐户是否已过期,或者是否允许用户在特定时刻登录。表示账户类接口,主要负责账户合法性检查,确认帐号是否过期,是否有权限登录系统等;这种模块执行的是基于非验证的帐号管理。他主要用于限制/允许用户对某个服务的访问时间,当前有效的系统资源(最多可以多少用户),限制用户位置(例如:root只能通过控制台登录)。
多数情况下auth和account会一起用来对用户登录和使用服务的情况进行限制,这样的限制会更加完整。比如下面是一个具体的例子:login是一个应用程序。Login要完成两件工作——首先查询用户,然后为用户提供所需的服务,例如提供一个shell程序。通常Login要求用户输入名称和密码进行验证。当用户名输入的时候,系统自然会去比对该用户是否是一个合法用户,是否在存在于本地或者远程的用户数据库中。如果该账号确实存在,那么是否过期。这些个工作是由account接口来负责。
如果用户满足上述登录的前提条件,那么它是否具有可登录系统的口令,口令是否过期等。这个工作就要由auth接口来负责了,他通常会将用户口令信息加密并提供给本地(/etc/shadow)或者远程的(ldap,kerberos等)口令验证方式进行验证。如果用户能够登录成功,证明auth和account的工作已经完成。但整个验证过程并没有完全结束。因为还有一些其他的问题没有得到确认。例如,用户能够在服务器上同时开启多少个窗口登录,用户可以在登录之后使用多少终端多长时间,用户能够访问哪些资源和不能访问哪些资源等等。也就是说登录之后的后续验证和环境定义等还需要其他的接口。这就是下面要提到的两组接口:
password - 此模块接口用于更改用户密码。口令类接口,控制用户更改密码的全过程。也就是有些资料所说的升级用户验证标记。
session - 此模块接口配置和管理用户会话。使用此界面的模块还可以执行允许访问所需的其他任务,例如挂载用户的主目录和使用户的邮箱可用。会话类接口。实现从用户登录成功到退出的会话控制;处理为用户提供服务之前/后需要做的些事情。包括:开启/关闭交换数据的信息,监视目录等,设置用户会话环境等。也就是说这是在系统正式进行服务提供之前的最后一道关口。
单个模块可以提供任何或所有模块接口,例如 pam_unix.so 提供所有四个模块接口。
模块名称(如 pam_unix.so)为 PAM 提供包含指定模块接口的库名称;目录名称会被省略,因为应用程序链接到适当的 libpam 版本,它可以找到模块的正确版本。
调用时,所有 PAM 模块都会生成成功或失败的结果。控制标志告诉 PAM 如何使用结果。可以按特定顺序列出(堆叠)模块,控制标志则决定特定模块的成功或失败对于向用户验证服务的整体目标而言有多重要。有几个简单标记,它只使用关键字来设置配置:
required - 模块结果必须成功才能进行身份验证才能继续。如果此时测试失败,则只有在所有模块测试引用该接口完成之前,才会通知用户。表示该行以及所涉及模块的成功是用户通过鉴别的必要条件。换句话说,只有当对应于应用程序的所有带required标记的模块全部成功后,该程序才能通过鉴别。同时,如果任何带required标记的模块出现了错误,PAM并不立刻将错误消息返回给应用程序,而是在所有模块都调用完毕后才将错误消息返回调用他的程序。
说白了,就是必须将所有的模块都执行一次,其中任何一个模块验证出错,验证都会继续进行,并在执行完成之后才返回错误信息。这样做的目的就是不让用户知道自己被哪个模块拒绝,通过一种隐蔽的方式来保护系统服务。就像设置防火墙规则的时候将拒绝类的规则都设置为drop一样,以致于用户在访问网络不成功的时候无法准确判断到底是被拒绝还是目标网络不可达。
requisite - 模块结果必须成功才能继续身份验证。但是,如果测试在此时失败,用户会立即收到一个显示第一个 failed 或 requisite 模块测试的消息。与required相仿,只有带此标记的模块返回成功后,用户才能通过鉴别;不同之处在于其一旦失败就不再执行堆中后面的其他模块,并且鉴别过程到此结束,同时也会立即返回错误信息。与上面的required相比,似乎要显得更光明正大一些。
sufficient - 如果模块失败,则忽略该模块结果。但如果模块标记足够成功,并且没有以前的模块标记失败,则不需要其他结果,用户会被验证到该服务。表示该行以及所涉及模块验证成功是用户通过鉴别的充分条件。也就是说只要标记为sufficient的模块一旦验证成功,那么PAM便立即向应用程序返回成功结果而不必尝试任何其它模块。即便后面的层叠模块使用了requisite或者required控制标志也是一样。当标记为sufficient的模块失败时,sufficient模块会当做 optional对待。因此拥有sufficient标志位的配置项在执行验证出错的时候并不会导致整个验证失败,但执行验证成功之时则大门敞开。所以该控制位的使用务必慎重。
optional - 模块结果会被忽略。在没有其他模块引用 接口时,只有在成功进行身份验证时,才会将模块标记为可选。其表示即便该行所涉及的模块验证失败用户仍能通过认证。在PAM体系中,带有该标记的模块失败后将继续处理下一模块。也就是说即使本行指定的模块验证失败,也允许用户享受应用程序提供的服务。使用该标志,PAM框架会忽略这个模块产生的验证错误,继续顺序执行下一个层叠模块。
include - 与其他控制不同,这与处理模块结果无关。此标志拉取配置文件中与给定参数匹配的所有行,并将它们作为参数附加到模块。表示在验证过程中调用其他的PAM配置文件。在RHEL系统中有相当多的应用通过完整调用/etc/pam.d/system-auth来实现认证而不需要重新逐一去写配置项。这也就意味着在很多时候只要用户能够登录系统,针对绝大多数的应用程序也能同时通过认证。
另外还有一种比较复杂的格式为value = action的语法来设置控制标志,标志之间会以空格分开。格式如下:
value1 = action1 value2 = action2 ……
其中value可以是下列Linux PAM库的返回值:
success、open_err、symbol_err、service_err、system_err、buf_err、perm_denied、auth_err、cred_insufficient、authinfo_unavail、user_unknown、maxtries、new_authtok_reqd、acct_expired、session_err、cred_unavail、cred_expired、cred_err、no_module_data、conv_err、authtok_err、authtok_recover_err、authtok_lock_busy、authtok_disable_aging、 try_again、ignore、abort、authtok_expired、module_unknown、bad_item和default。
最后一个(default)能够用来设置上面的返回值无法表达的行为。
actionN可以是一个非负整数或者是下面的记号之一:ignore、ok、done、bad、die和reset。如果是非负整数J,就表示需要忽略后面J个同样类型的模块。通过这种方式,系统管理者可以更加灵活地设置层叠模块,模块的层叠路径由单个模块的反应决定。
关于这几个记号的详细解释:
ignore:如果使用层叠模块,那么这个模块的返回值将被忽略,不会被应用程序知道。
bad:他表示这个返回码应该被看作是模块验证失败的标志。如果这个模块是层叠模块的第一个验证失败的模块,那么他的状态值就是整个层叠模块验证的状态值和结果。
die:终止层叠模块验证过程,立刻返回到应用程序。
ok:告诉PAM这个模块的返回值将直接作为所有层叠模块的返回值。也就是说,如果这个模块前面的模块返回状态是PAM_SUCCESS,那这个返回值就会覆盖前面的返回状态。注意:如果前面的模块的返回状态表示模块验证失败,那么不能使用这个返回值再加以覆盖。
done:终止后续层叠模块的验证,把控制权立刻交回应用程序。
reset:清除所有层叠模块的返回状态,从下一个层叠模块重新开始验证。
模块接口指令可以堆叠或放在另一个模块上,从而能将多个模块一起用于一个用途。
注意:
如果模块的 control 标志使用了 sufficient 或 requisite 值,则列出模块的顺序对身份验证过程非常重要。利用堆栈管理员可以先存在特定条件,然后才能允许用户进行身份验证。例如 setup 工具通常使用几个堆栈的模块,如其 PAM 配置文件中所示:
# cat /etc/pam.d/setup
auth sufficient pam_rootok.so
auth include system-auth
account required pam_permit.so
session required pam_permit.so
auth sufficient pam_rootok.so - 此行使用 pam_rootok.so 模块来检查当前用户是否为 root,方法是验证其 UID 是否为 0。如果此测试成功,则不会查询其他模块并执行 命令。如果此测试失败,则使用下一个模块。
auth 包括 system-auth - 此行包含 /etc/pam.d/system-auth 模块的内容,并处理此内容进行验证。
account required pam_permit.so - 此行使用 pam_permit.so 模块来允许 root 用户或在控制台中登录的任何人都重新引导系统。
session required pam_permit.so - 此行与会话设置相关。使用 pam_permit.so,它会确保 setup 实用程序不会失败。
PAM 使用参数将信息传递至某些模块的身份验证期间可插拔模块。例如,pam_pwquality.so 模块检查密码的强度程度,并可取几个参数。在以下示例中,force _for_root 指定即使 root 用户的密码也必须成功通过强度检查,然后重试定义用户将收到三个输入强密码的机会:
password requisite pam_pwquality.so enforce_for_root retry=3
无效的参数通常会被忽略,否则不会影响 PAM 模块的成功或失败。但一些模块可能会在无效的参数中失败。大多数模块向 journald 服务报告错误。
示例
下面的两个小例子用于反面示例:
首先是下面两行配置:
/etc/pam.d/system-auth
auth required pam_unix.so try_first_pass nullok
auth optional pam_permit.so
pam_unix(8) 说明如下:“本认证 (pam_unix.so)用于检查用户密码作为认证。默认情况不允许密码为空的用户进入”。而 pam_permit.so 允许密码为空的情况。如果将 rerquired 和 optional 交换位置,则两种情况都将允许无密码登录。
第二种情况恰好相反,在 /etc/pam.d/login 中的pam_nologin.so 默认配置创建如下文件:
# touch /etc/nologin
将导致只有 root 用户可以登录(部分Linux默认允许 root 用户登录)。要让普通用户可以登录,则需要删除该文件,可能是从创建它的控制台。
又一例简单的 PAM 配置
#%PAM-1.0
auth required pam_securetty.so
auth required pam_unix.so nullok
auth required pam_nologin.so
account required pam_unix.so
password required pam_pwquality.so retry=3
password required pam_unix.so shadow nullok use_authtok
session required pam_unix.so
第一行是注释,由行首处的 hash 标记(#)表示。
第二行(共四个堆栈)三个模块进行登录身份验证。
auth required pam_securetty.so - 此模块可确保如果用户尝试以 root 身份登录,如果该文件存在,则 /etc/securetty 文件中列出了用户正在登录的 TTY。
如果 TTY 没有列在文件中,则任何尝试以 root 身份登录都会失败,并显示 Login incorrect 信息。
auth required pam_unix.so nullok - 此模块提示用户输入密码,然后使用存储在 /etc/passwd 中的信息检查密码(如果存在的话),以及 /etc/shadow。
参数 nullok 指示 pam_unix.so 模块允许空白密码。
auth required pam_nologin.so - 这是最终身份验证步骤。它将检查 /etc/nologin 文件是否存在。如果存在并且用户不是 root,则身份验证会失败。
注意:
在本例中会检查所有三个 auth 模块,即使第一个 auth 模块失败。这可以防止用户在什么阶段知道其身份验证失败。这种在攻击者手中的知识让他们可以更容易地推断出如何破解系统。
帐户所需的 pam_unix.so - 此模块执行任何必要的帐户验证。例如,如果启用了 shadow 密码,pam_unix.so 模块的帐户接口检查帐户是否已过期,或者用户是否在允许的宽限期中更改了密码。
password required pam_pwquality.so retry=3 - 如果密码已过期,pam_pwquality.so 模块的密码组件会提示输入新密码。然后它会测试新创建的密码,看它是否能由基于字典的密码破解程序轻松确定。参数 retry=3 指定测试第一次失败,则用户有另外两个机会来创建强密码。
password required pam_unix.so shadow nullok use_authtok - 如果程序使用 pam_unix.so 模块 的密码 接口更改用户的密码,则指定此行。
参数 shadow 指示模块在更新用户密码时创建影子密码。
参数 nullok 指示模块允许用户从空白密码更改其密码,否则 null 密码被视为帐户锁定。
这一行上的最后一个参数 use_authtok 提供了堆栈 PAM 模块时顺序的重要性的好示例。此参数指示模块不要提示用户输入新密码。相反,它接受之前 password 模块记录的任何密码。这样,所有新密码都必须传递 pam_pwquality.so 测试安全密码,然后才能被接受。
session required pam_unix.so - 最后一行指示 pam_unix.so 模块的会话接口来管理会话。此模块将用户名和服务类型记录到每个会话的开头和结尾处的 /var/log/secure 中。此模块可通过与其他会话模块堆栈来获取额外的功能来补充。
最新版本:1.5
官方主页:http://www.linux-pam.org/
由于不存在规范 PAM 行为的中心标准,后来有人尝试将 PAM 标准化为 X/Open UNIX 标准化过程的一部分,从而产生了X/Open Single Sign-on(XSSO)标准。 该标准尚未获得批准,但是其草案可供后来的PAM实现(例如OpenPAM)参考。
由于大多数 PAM 实现本身都不与远程客户端交互,PAM 本身无法实现 Kerberos(Unix环境中最常见的SSO类型)。这导致SSO被合并为可能的XSSO标准的“主要认证”部分,并且出现了诸如SPNEGO和 SASL 之类的技术。这种功能上的缺乏也是 SSH 自己实现身份验证机制协商的原因。
在大多数PAM实现中,pam_krb5只能获取票据授权票据(TGT),这涉及到提示用户输入凭据,并且仅用于SSO环境中的初始登录。如要在不提示用户再次输入凭据的前提下,获取特定应用程序的服务票证,则必须对该应用程序进行特定的编码以支持 Kerberos,这是因为 pam_krb5 本身无法获取服务票证(尽管有些 PAM-KRB5 版本正试图解决该问题)。
PAM 为管理员提供了很大的灵活性来为系统设置身份验证策略,对开发人员和管理员而言是有用的系统,原因如下:
1. 提供一种常见身份验证方案,可用于各种应用。
2. 为系统管理员提供了对身份验证的显著灵活性和控制力。
3. 提供单个全文档库,允许开发人员编写程序,而无需创建自己的身份验证方案。
Linux PAM(Pluggable Authentication Modules)是一个系统级用户认证框架,其将程序开发与认证方式进行分离,程序在运行时调用附加的“认证”模块完成自己的工作,本地系统管理员通过配置选择要使用哪些认证模块。其采用C语言开发并在GPL或BSD协议下授权使用。
Linux-PAM separates the tasks of authentication into four independent management groups:
1.account modules check that the specified account is a valid authentication target under current conditions. This may include conditions like account expiration, time of day, and that the user has access to the requested service.
2.authentication modules verify the user's identity, for example by requesting and checking a password or other secret. They may also pass authentication information on to other systems like a keyring.
3.password modules are responsible for updating passwords, and are generally coupled to modules employed in the authentication step. They may also be used to enforce strong passwords.
4.session modules define actions that are performed at the beginning and end of sessions. A session starts after the user has successfully authenticated.
PAM 是在运行过程中被动态链接使用的。更改对于已通过身份验证的用户无效;调试 PAM 的一种方法是最好在测试机器上本地登录并进行开发,保持会话不断运行,同时检查另一个控制台上另一个用户的结果。
PAM 手册 pam(8) 和 pam.d(5) 中描述了配置文件的标准规范,手册分四部分:账户,认证,密码和会话管理,同时还包括了配置项的可选内容。此外在目录 /usr/share/doc/Linux-PAM/index.html 包含多种指导文档,包括了每种标准模块的 man 手册。

The high-level steps taken when a locally-defined user logs into a text-based console:
1. The login application prompts for a user name and password, then makes a libpam authentication call to ask, "Is this user who they say they are?" The pam_unix module is responsible for checking the local account authentication. Other modules may also be checked, and ultimately the result is passed back to the login process.
2. The login process next asks, "Is this user allowed to connect?", then makes an account call to libpam. The pam_unix module checks for things like whether the password has expired. Other modules might check host or time-based access control lists. An overall response is handed back to the process.
3. If the password has expired, the application responds. Some applications simply fail to log in the user. The login process prompts the user for a new password.
4. To get the password verified and written to the correct location, the login process makes a password call to libpam. The pam_unix module writes to the local shadow file. Other modules may also be called to verify the password strength.
5. If the login process is continuing at this point, it is ready to create the session. A session call to libpam results in the pam_unix module writing a login timestamp to the wtmp file. Other modules enable X11 authentication or SELinux user contexts.
6. On logout, when the session is closed, another session call can be made to libpam. This is when the pam_unix module writes the logout timestamp to the wtmp file.
PAM 配置文件说明(RPM系统)
/usr/lib64/security
A collection of PAM libraries that perform various checks. Most of these modules have man pages to explain the use case and options available.
/etc/pam.d
A collection of configuration files for applications that call libpam. These files define which modules are checked, with what options, in which order, and how to handle the result. These files may be added to the system when an application is installed and are frequently edited by other utilities.
Since there are several checks done by all applications, these files may also have include statements to call other configuration files in this directory. Most shared modules are found in the system-auth file for local authentication and the password-auth file for applications listening for remote connections.
/etc/security
A collection of additional configuration files for specific modules. Some modules, such as pam_access and pam_time, allow additional granularity for checks. When an application configuration file calls these modules, the checks are completed using the additional information from its corresponding supplemental configuration files. Other modules, like pam_pwquality, make it easier for other utilities to modify the configuration by placing all the options in a separate file instead of on the module line in the application configuration file.
/var/log/secure
Most security and authentication errors are reported to this log file. Permissions are configured on this file to restrict access.
man pam
This man page describes the overall process, including the types of calls and a list of files involved.
man pam.conf
This man page describes the overall format and defines keywords and fields for the pam.d configuration files.
man -k pam_
This search of man pages lists pages available for modules installed.
PAM 配置文件格式
每个 PAM 配置文件包含一组指令,这些指令定义模块(身份验证配置区域)以及其中的任何控制或参数。这些指令都具有简单的语法,可识别模块用途(接口)和模块的配置设置。
module_interface control_flag module_name module_arguments
在 PAM 配置文件中,模块接口是定义的第一个字段。例如:
auth required pam_unix.so
PAM配置文件通常分为四列:
第一列代表模块类型或接口
"类型"(type | interface)可分为四种(auth,account,password,session)之一。若在类型前加上"-"(减号)前缀,则表示即使模块不存在,也不会影响认证结果,更不会将此事件记录到日志中,对于那些可有可无的模块来说,这一特性非常有用。
第二列代表控制标记
"控制标志"(control-flag)用于控制模块在流程栈中的行为。该字段有两种语法,一种是简单语法,一种是复杂语法,用于描述 PAM 认证流程的执行规则。
第三列代表模块路径(名称)
"模块路径"(module-path | name)表示模块的文件系统路径,既可以是绝对路径,也可以是相对路径(相对于 /lib/security/ 或 /lib64/security/ 目录),模块文件名一般都符合 pam_*.so 格式。注意,当第二个字段(控制标志)的值是"include"或"substack"时,相对路径表示相对于 /etc/pam.d/ 或 /usr/lib/pam.d/ 目录的路径。
第四列代表模块参数
"模块参数"(module-arguments)用于控制模块的行为,它是一组用空格分隔的参数列表,每个模块能够使用的参数各不相同,详见后文"常用模块"小节。如果想在某个参数中使用空格,那么必须在该参数外围加上中括号(字符串中的"["无需转义,但"]"必须转义为"\]")。例如 passwd=mada [query=select user_name from internet_service where user_name='%u' and password=PASSWORD('%p')]
注意,配置文件中的任何语法错误都会导致认证过程失败,同时失败信息将会被记录到系统日志(syslog)中。
流程栈
所谓"流程栈"是指执行步骤和规则,非常类似于程序逻辑的概念,它体现在配置文件自上而下的执行顺序中。"栈"就像是一段可以嵌套的程序逻辑,通过"substack"关键字,可以在一个栈(父栈)中嵌入另一个栈(子栈)。 PAM 流程栈的执行规则由配置文件中的第二个字段"控制标志"(control-flag)决定,可以把"控制标志"想象成逻辑控制语法。该字段有两种语法,一种是简单语法,一种是复杂语法。
1)PAM的模块类型
Linux-PAM有四种模块类型,分别代表四种不同的任务,它们是:
认证管理(auth),账号管理(account),会话管理(session)和密码(password)管理,一个类型可能有多行,它们按顺序依次由PAM模块调用。
2)第二列:PAM的控制标记
PAM使用控制标记来处理和判断各个模块的返回值。
规定如何处理PAM模块鉴别认证的结果,简而言之就是鉴别认证成功或者失败之后会发生什么事,如何进行控制。单个应用程序可以调用多种底层模块,通常称为“堆叠”。对应于某程序按照配置文件中出现顺序执行的所有模块成为“堆”,堆中的各模块的地位与出错时的处理方式由control_flag栏的取值决定,他的四种可能的取值分别为required、requisite、sufficient、optional 或 include。
3)模块路径
模块路径.即要调用模块的位置. 如果是64位系统,一般保存在/lib64/security,如: pam_unix.so,同一个模块,可以出现在不同的类型中.它在不同的类型中所执行的操作都不相同.这是由于每个模块,针对不同的模块类型,编制了不同的执行函数。
4)模块参数
模块参数,即传递给模块的参数。参数可以有多个','之间用空格分隔开,如:password required pam_unix.so nullok obscure min=4 max=8 md5。
PAM 接口基本上是该特定模块可以执行的身份验证流程栈式操作类型。可用的模块类型接口有四种,分别对应于身份验证和授权过程的不同方面(每行只能指定一种接口类型,如果程序需要多种接口的话,可在多行中分别予以规定):
auth - 此模块接口验证用户。例如,它请求并验证密码的有效性。带有此接口的模块也可以设置凭据,如组成员资格。表示鉴别类接口模块类型用于检查用户和密码,并分配权限;这种类型的模块为用户验证提供两方面服务。让应用程序提示用户输入密码或者其他标记,确认用户合法性;通过他的凭证许可权限,设定组成员关系或者其他优先权。
account - 此模块接口验证是否允许访问。例如,它会检查用户帐户是否已过期,或者是否允许用户在特定时刻登录。表示账户类接口,主要负责账户合法性检查,确认帐号是否过期,是否有权限登录系统等;这种模块执行的是基于非验证的帐号管理。他主要用于限制/允许用户对某个服务的访问时间,当前有效的系统资源(最多可以多少用户),限制用户位置(例如:root只能通过控制台登录)。
多数情况下auth和account会一起用来对用户登录和使用服务的情况进行限制,这样的限制会更加完整。比如下面是一个具体的例子:login是一个应用程序。Login要完成两件工作——首先查询用户,然后为用户提供所需的服务,例如提供一个shell程序。通常Login要求用户输入名称和密码进行验证。当用户名输入的时候,系统自然会去比对该用户是否是一个合法用户,是否在存在于本地或者远程的用户数据库中。如果该账号确实存在,那么是否过期。这些个工作是由account接口来负责。
如果用户满足上述登录的前提条件,那么它是否具有可登录系统的口令,口令是否过期等。这个工作就要由auth接口来负责了,他通常会将用户口令信息加密并提供给本地(/etc/shadow)或者远程的(ldap,kerberos等)口令验证方式进行验证。如果用户能够登录成功,证明auth和account的工作已经完成。但整个验证过程并没有完全结束。因为还有一些其他的问题没有得到确认。例如,用户能够在服务器上同时开启多少个窗口登录,用户可以在登录之后使用多少终端多长时间,用户能够访问哪些资源和不能访问哪些资源等等。也就是说登录之后的后续验证和环境定义等还需要其他的接口。这就是下面要提到的两组接口:
password - 此模块接口用于更改用户密码。口令类接口,控制用户更改密码的全过程。也就是有些资料所说的升级用户验证标记。
session - 此模块接口配置和管理用户会话。使用此界面的模块还可以执行允许访问所需的其他任务,例如挂载用户的主目录和使用户的邮箱可用。会话类接口。实现从用户登录成功到退出的会话控制;处理为用户提供服务之前/后需要做的些事情。包括:开启/关闭交换数据的信息,监视目录等,设置用户会话环境等。也就是说这是在系统正式进行服务提供之前的最后一道关口。
单个模块可以提供任何或所有模块接口,例如 pam_unix.so 提供所有四个模块接口。
模块名称(如 pam_unix.so)为 PAM 提供包含指定模块接口的库名称;目录名称会被省略,因为应用程序链接到适当的 libpam 版本,它可以找到模块的正确版本。
调用时,所有 PAM 模块都会生成成功或失败的结果。控制标志告诉 PAM 如何使用结果。可以按特定顺序列出(堆叠)模块,控制标志则决定特定模块的成功或失败对于向用户验证服务的整体目标而言有多重要。有几个简单标记,它只使用关键字来设置配置:
required - 模块结果必须成功才能进行身份验证才能继续。如果此时测试失败,则只有在所有模块测试引用该接口完成之前,才会通知用户。表示该行以及所涉及模块的成功是用户通过鉴别的必要条件。换句话说,只有当对应于应用程序的所有带required标记的模块全部成功后,该程序才能通过鉴别。同时,如果任何带required标记的模块出现了错误,PAM并不立刻将错误消息返回给应用程序,而是在所有模块都调用完毕后才将错误消息返回调用他的程序。
说白了,就是必须将所有的模块都执行一次,其中任何一个模块验证出错,验证都会继续进行,并在执行完成之后才返回错误信息。这样做的目的就是不让用户知道自己被哪个模块拒绝,通过一种隐蔽的方式来保护系统服务。就像设置防火墙规则的时候将拒绝类的规则都设置为drop一样,以致于用户在访问网络不成功的时候无法准确判断到底是被拒绝还是目标网络不可达。
requisite - 模块结果必须成功才能继续身份验证。但是,如果测试在此时失败,用户会立即收到一个显示第一个 failed 或 requisite 模块测试的消息。与required相仿,只有带此标记的模块返回成功后,用户才能通过鉴别;不同之处在于其一旦失败就不再执行堆中后面的其他模块,并且鉴别过程到此结束,同时也会立即返回错误信息。与上面的required相比,似乎要显得更光明正大一些。
sufficient - 如果模块失败,则忽略该模块结果。但如果模块标记足够成功,并且没有以前的模块标记失败,则不需要其他结果,用户会被验证到该服务。表示该行以及所涉及模块验证成功是用户通过鉴别的充分条件。也就是说只要标记为sufficient的模块一旦验证成功,那么PAM便立即向应用程序返回成功结果而不必尝试任何其它模块。即便后面的层叠模块使用了requisite或者required控制标志也是一样。当标记为sufficient的模块失败时,sufficient模块会当做 optional对待。因此拥有sufficient标志位的配置项在执行验证出错的时候并不会导致整个验证失败,但执行验证成功之时则大门敞开。所以该控制位的使用务必慎重。
optional - 模块结果会被忽略。在没有其他模块引用 接口时,只有在成功进行身份验证时,才会将模块标记为可选。其表示即便该行所涉及的模块验证失败用户仍能通过认证。在PAM体系中,带有该标记的模块失败后将继续处理下一模块。也就是说即使本行指定的模块验证失败,也允许用户享受应用程序提供的服务。使用该标志,PAM框架会忽略这个模块产生的验证错误,继续顺序执行下一个层叠模块。
include - 与其他控制不同,这与处理模块结果无关。此标志拉取配置文件中与给定参数匹配的所有行,并将它们作为参数附加到模块。表示在验证过程中调用其他的PAM配置文件。在RHEL系统中有相当多的应用通过完整调用/etc/pam.d/system-auth来实现认证而不需要重新逐一去写配置项。这也就意味着在很多时候只要用户能够登录系统,针对绝大多数的应用程序也能同时通过认证。
另外还有一种比较复杂的格式为value = action的语法来设置控制标志,标志之间会以空格分开。格式如下:
value1 = action1 value2 = action2 ……
其中value可以是下列Linux PAM库的返回值:
success、open_err、symbol_err、service_err、system_err、buf_err、perm_denied、auth_err、cred_insufficient、authinfo_unavail、user_unknown、maxtries、new_authtok_reqd、acct_expired、session_err、cred_unavail、cred_expired、cred_err、no_module_data、conv_err、authtok_err、authtok_recover_err、authtok_lock_busy、authtok_disable_aging、 try_again、ignore、abort、authtok_expired、module_unknown、bad_item和default。
最后一个(default)能够用来设置上面的返回值无法表达的行为。
actionN可以是一个非负整数或者是下面的记号之一:ignore、ok、done、bad、die和reset。如果是非负整数J,就表示需要忽略后面J个同样类型的模块。通过这种方式,系统管理者可以更加灵活地设置层叠模块,模块的层叠路径由单个模块的反应决定。
关于这几个记号的详细解释:
ignore:如果使用层叠模块,那么这个模块的返回值将被忽略,不会被应用程序知道。
bad:他表示这个返回码应该被看作是模块验证失败的标志。如果这个模块是层叠模块的第一个验证失败的模块,那么他的状态值就是整个层叠模块验证的状态值和结果。
die:终止层叠模块验证过程,立刻返回到应用程序。
ok:告诉PAM这个模块的返回值将直接作为所有层叠模块的返回值。也就是说,如果这个模块前面的模块返回状态是PAM_SUCCESS,那这个返回值就会覆盖前面的返回状态。注意:如果前面的模块的返回状态表示模块验证失败,那么不能使用这个返回值再加以覆盖。
done:终止后续层叠模块的验证,把控制权立刻交回应用程序。
reset:清除所有层叠模块的返回状态,从下一个层叠模块重新开始验证。
模块接口指令可以堆叠或放在另一个模块上,从而能将多个模块一起用于一个用途。
注意:
如果模块的 control 标志使用了 sufficient 或 requisite 值,则列出模块的顺序对身份验证过程非常重要。利用堆栈管理员可以先存在特定条件,然后才能允许用户进行身份验证。例如 setup 工具通常使用几个堆栈的模块,如其 PAM 配置文件中所示:
# cat /etc/pam.d/setup
auth sufficient pam_rootok.so
auth include system-auth
account required pam_permit.so
session required pam_permit.so
auth sufficient pam_rootok.so - 此行使用 pam_rootok.so 模块来检查当前用户是否为 root,方法是验证其 UID 是否为 0。如果此测试成功,则不会查询其他模块并执行 命令。如果此测试失败,则使用下一个模块。
auth 包括 system-auth - 此行包含 /etc/pam.d/system-auth 模块的内容,并处理此内容进行验证。
account required pam_permit.so - 此行使用 pam_permit.so 模块来允许 root 用户或在控制台中登录的任何人都重新引导系统。
session required pam_permit.so - 此行与会话设置相关。使用 pam_permit.so,它会确保 setup 实用程序不会失败。
PAM 使用参数将信息传递至某些模块的身份验证期间可插拔模块。例如,pam_pwquality.so 模块检查密码的强度程度,并可取几个参数。在以下示例中,force _for_root 指定即使 root 用户的密码也必须成功通过强度检查,然后重试定义用户将收到三个输入强密码的机会:
password requisite pam_pwquality.so enforce_for_root retry=3
无效的参数通常会被忽略,否则不会影响 PAM 模块的成功或失败。但一些模块可能会在无效的参数中失败。大多数模块向 journald 服务报告错误。
示例
下面的两个小例子用于反面示例:
首先是下面两行配置:
/etc/pam.d/system-auth
auth required pam_unix.so try_first_pass nullok
auth optional pam_permit.so
pam_unix(8) 说明如下:“本认证 (pam_unix.so)用于检查用户密码作为认证。默认情况不允许密码为空的用户进入”。而 pam_permit.so 允许密码为空的情况。如果将 rerquired 和 optional 交换位置,则两种情况都将允许无密码登录。
第二种情况恰好相反,在 /etc/pam.d/login 中的pam_nologin.so 默认配置创建如下文件:
# touch /etc/nologin
将导致只有 root 用户可以登录(部分Linux默认允许 root 用户登录)。要让普通用户可以登录,则需要删除该文件,可能是从创建它的控制台。
又一例简单的 PAM 配置
#%PAM-1.0
auth required pam_securetty.so
auth required pam_unix.so nullok
auth required pam_nologin.so
account required pam_unix.so
password required pam_pwquality.so retry=3
password required pam_unix.so shadow nullok use_authtok
session required pam_unix.so
第一行是注释,由行首处的 hash 标记(#)表示。
第二行(共四个堆栈)三个模块进行登录身份验证。
auth required pam_securetty.so - 此模块可确保如果用户尝试以 root 身份登录,如果该文件存在,则 /etc/securetty 文件中列出了用户正在登录的 TTY。
如果 TTY 没有列在文件中,则任何尝试以 root 身份登录都会失败,并显示 Login incorrect 信息。
auth required pam_unix.so nullok - 此模块提示用户输入密码,然后使用存储在 /etc/passwd 中的信息检查密码(如果存在的话),以及 /etc/shadow。
参数 nullok 指示 pam_unix.so 模块允许空白密码。
auth required pam_nologin.so - 这是最终身份验证步骤。它将检查 /etc/nologin 文件是否存在。如果存在并且用户不是 root,则身份验证会失败。
注意:
在本例中会检查所有三个 auth 模块,即使第一个 auth 模块失败。这可以防止用户在什么阶段知道其身份验证失败。这种在攻击者手中的知识让他们可以更容易地推断出如何破解系统。
帐户所需的 pam_unix.so - 此模块执行任何必要的帐户验证。例如,如果启用了 shadow 密码,pam_unix.so 模块的帐户接口检查帐户是否已过期,或者用户是否在允许的宽限期中更改了密码。
password required pam_pwquality.so retry=3 - 如果密码已过期,pam_pwquality.so 模块的密码组件会提示输入新密码。然后它会测试新创建的密码,看它是否能由基于字典的密码破解程序轻松确定。参数 retry=3 指定测试第一次失败,则用户有另外两个机会来创建强密码。
password required pam_unix.so shadow nullok use_authtok - 如果程序使用 pam_unix.so 模块 的密码 接口更改用户的密码,则指定此行。
参数 shadow 指示模块在更新用户密码时创建影子密码。
参数 nullok 指示模块允许用户从空白密码更改其密码,否则 null 密码被视为帐户锁定。
这一行上的最后一个参数 use_authtok 提供了堆栈 PAM 模块时顺序的重要性的好示例。此参数指示模块不要提示用户输入新密码。相反,它接受之前 password 模块记录的任何密码。这样,所有新密码都必须传递 pam_pwquality.so 测试安全密码,然后才能被接受。
session required pam_unix.so - 最后一行指示 pam_unix.so 模块的会话接口来管理会话。此模块将用户名和服务类型记录到每个会话的开头和结尾处的 /var/log/secure 中。此模块可通过与其他会话模块堆栈来获取额外的功能来补充。
最新版本:1.5
官方主页:http://www.linux-pam.org/