Linux PAM 模块介绍
2020-03-20 15:39:33 阿炯

先简单的介绍一下PAM,PAM(Pluggable Authentication Modules)是由Sun提出的一种具有相当灵活性的认证机制。它通过提供一些动态链接库和一套统一的API,将系统提供的服务和该服务的认证方式分开,使得系统管理员可以灵活地根据需要给不同的服务配置不同的认证方式而无需更改服务程序,同时也便于向系统中添加新的认证手段。PAM模块是一种嵌入式模块,修改后即时生效。

如何在Linux系统中限制密码长度的同时对密码的复杂程度也进行管理,密码符合长度规则但却很简单很容易被猜出来,查了相关资料后发现了PAM中的pam_cracklib模块就是用来做密码复杂度检测的。

pam的重要文件如下:
/usr/lib/libpam.so.*  ## PAM核心库
/etc/pam.conf  ## PAM配置文件
/etc/pam.d/*  ## PAM各个模块的配置文件
/lib/security/pam_*.so  ## 可动态加载的PAM模块

PAM配置文件的每一行的格式:Module-type   Control-flag   Module-path   Arguments

模块类型控制字符  模块路径模块参数

Module-type:
auth:确定有关用户认证的两方面。1、他确认用户就是他们自己,这通过应用程序提示用户输入密码 或者其他正式身份的办法。2、这类模块会赋予成员资格。
account:处理非认证级的账号管理。典型的用法是基于一天的不同时间来限制、允许访问某服务。限制 当前可用的系统资源(最大用户数)或者限制特定用户—root只能从控制台登陆。
session:一系列有关动作,只在用户得到/失去服务时要做的事。这包括记录用户的登录/退出、挂载必要 的目录等。
password:设置密码。

Control-flag:
required:表示本模块必须返回成功才能通过认证,但是如果该模块返回失败的话,失败结果也不会立即通知用户,而是要等到同一stack中的所有模块全部执行完毕再将失败结果返回给应用程序。可以认为是一个必要条件。
requisite:与required类似,该模块必须返回成功才能通过认证,但是一旦该模块返回失败,将不再执行同一stack内的任何模块,而是直接将控制权返回给应用程序。是一个必要条件。注:Solaris不支持。
sufficient:表明本模块返回成功已经足以通过身份认证的要求,不必再执行同一stack内的其它模块,但是 如果本模块返回失败的话可以忽略。可以认为是一个充分条件。
optional:表明本模块是可选的,它的成功与否一般不会对身份认证起关键作用,其返回值一般被忽略。
include:从字面就知道什么意思了,包含另外一个配置文件。

Module-path:
Debian的PAM module存放目录默认是在/lib/security。在各个模块的配置文件里,不用写绝对路径,直接写这个默认目录下面的模块名就可以了。当然也可以写绝对路径。

Arguments:
各个模块的参数都不一样,具体的要开发者的man手册。无效参数不会对结果有影响,但是会被日志记录 下来。首先看/lib/security有没有这个模块,再使用模块名。


PAM 模块列表

PAM 内置模块
Linux PAM 内置模块
模块类型简介
pam_access.soauth,account,password,session基于来源(主机/网络/终端/$DISPLAY/服务名)的访问控制
pam_debug.soauth,account,password,session调试PAM栈
pam_deny.soauth,account,password,session无条件的拒绝访问
pam_echo.soauth,account,password,session显示文本消息
pam_env.soauth,session设置与撤销环境变量(也包括PAM变量)
pam_exec.soauth,account,password,session调用外部命令
pam_faildelay.soauth设置认证失败时的阻塞延迟
pam_faillock.soauth,account锁定连续认证失败的账户
pam_filter.soauth,account,password,session在用户与应用程序之间建立输入输出(STDIN/STDOUT)过滤器
pam_ftp.soauth可插拔的匿名FTP访问模式(不安全)
pam_group.soauth将用户额外添加到特定组中
pam_issue.soauth更改用户的提示文件(issue)
pam_keyinit.sosession在默认内核会话密钥环之外额外创建新的内核会话密钥环
pam_lastlog.soauth,account,session显示账户的上次登录时间、锁定长期不登录的帐户
pam_limits.sosession设置会话的资源限制
pam_listfile.soauth,account,password,session基于各种属性(tty|user|rhost|ruser|group|shell)执行访问控制
pam_localuser.soauth,account,password,session仅允许本地用户(/etc/passwd)访问
pam_loginuid.sosession设置进程的 loginuid 属性(主要用于审计目的)
pam_mail.soauth,session提示用户有新邮件
pam_mkhomedir.sosession在开始会话前创建用户的家目录
pam_motd.sosession显示"今日消息"(motd)
pam_namespace.sosession为会话设置私有名字空间
pam_nologin.soauth,account禁止非 root 账户登录
pam_permit.soauth,account,password,session无条件的允许访问(小心使用)
pam_pwhistory.sopassword防止重复使用旧密码
pam_rhosts.soauth使用 rlogin/rsh 网络访问认证(/etc/hosts.equiv 与 ~/.rhosts)
pam_rootok.soauth,account,password仅在 UID=0 时验证成功
pam_securetty.soauth仅允许 root 从指定的"安全"设备登录
pam_selinux.sosession设置默认的 SELinux 安全上下文
pam_sepermit.soauth,account根据 SELinux 的开关状态决定是否通过认证
pam_setquota.sosession在开始会话时设置或修改磁盘限额
pam_shells.soauth,account检查登录shell的有效性(是否列于 /etc/shells 之中)
pam_stress.soauth,account,password,session模拟失败表现
pam_succeed_if.soauth,account,password,session测试账号自身的属性以实现条件分支逻辑
pam_time.soaccount根据时间段决定是否允许访问
pam_timestamp.soauth,session缓存成功的认证以避免频繁的反复认证
pam_tty_audit.sosession开启或关闭TTY审计(内核默认不审计TTY上的输入)
pam_umask.sosession设置本次会话中的 umask 值
pam_unix.soauth,account,password,session传统UNIX密码验证(/etc/passwd 与 /etc/shadow)
pam_userdb.soauth,account使用 Berkeley DB 数据库验证用户名/密码
pam_usertype.soauth,account,password,session根据 /etc/login.defs 中的设置检查已认证用户的类型(系统账户/普通账户)
pam_warn.soauth,account,password,session向系统日志中记录详细的PAM信息(服务名,终端,用户,远程用户,远程主机)
pam_wheel.soauth,account仅允许 wheel 组成员获得 root 权限
pam_xauth.sosession在用户之间转发 xauth 密钥(cookies)

第三方模块
常见第三方模块
模块RHEL(rpm)Debian(deb)关键词
pam_fprintd.sofprintd-pamlibpam-fprintd指纹
pam_gdm.sogdmgdm3GDM(GNOME显示管理器)
pam_gnome_keyring.sognome-keyring-pamlibpam-gnome-keyringgnome-keyring(GNOME密钥管理器)
pam_cap.solibcaplibpam-capLinux Capabilities
pam_pwquality.solibpwqualitylibpam-pwquality密码复杂度
pam_user_map.somariadb-pammariadb-serverMariaDB
pam_oddjob_mkhomedir.sooddjob-mkhomediroddjob-mkhomedir创建家目录
pam_cifscreds.sopam_cifscredscifs-utilsNTLM(NT LAN Manager)
pam_oath.sopam_oathlibpam-oathOATH(一次性密码)
pam_ssh_agent_auth.sopam_ssh_agent_authlibpam-ssh-agent-authssh-agent
pam_winbind.sosamba-winbind-moduleslibpam-winbindWinbind
pam_sss.sosssd-clientlibpam-sssSystem Security Services Daemon
pam_systemd.sosystemd-pamlibpam-systemdsystemd-logind


常用的PAM模块
PAM模块结合管理类型说明
pam_unix.so

auth

提示用户输入密码,并与/etc/shadow文件相比对.匹配返回0

account检查用户的账号信息(包括是否过期等).帐号可用时,返回0.
password修改用户的密码. 将用户输入的密码,作为用户的新密码更新shadow文件
pam_shells.so

auth

account 

如果用户想登录系统,那么它的shell必须是在/etc/shells文件中之一的shell
pam_deny.so

account

auth

password

session

该模块可用于拒绝访问
pam_permit.so

auth

account

password

session

模块任何时候都返回成功.
pam_securetty.soauth如果用户要以root登录时,则登录的tty必须在/etc/securetty之中.
pam_listfile.so

auth

account

password session

访问应用程的控制开关
pam_cracklib.sopassword

这个模块可以插入到一个程序的密码栈中,用于检查密码的强度.

pam_limits.sosession定义使用系统资源的上限,root用户也会受此限制,可以通过/etc/security/limits.conf或/etc/security/limits.d/*.conf来设定



1)pam_access.so模块

pam_access.so模块主要的功能和作用是根据主机名(包括普通主机名或者FQDN)、IP地址和用户实现全面的访问控制。pam_access.so模块的具体工作行为根据配置文件/etc/security/access.conf来决定。该配置文件的主体包含了三个字段——权限、用户和访问发起方。格式上是一个用""隔开的表。
第一个字段:权限(permission),使用"+"表示授予权限,用"-"表示禁止权限。
第二个字段:用户(user),定义了用户、组以及用"@"表示的在不同主机上的同名用户和同一主机上不同名用户。
第三个字段:访问发起方(origins),定义了发起访问的主机名称、域名称、终端名称。

而且/etc/security/access.conf文件提供了很多范例供修改时参考,并且都给出了具体的说明,例如:

#禁止非root用户通过tty1访问相关服务
#-:ALL EXCEPT root:tty1

#禁止除了wheel、shutdown以及sync之外的所有用户访问相关服务
#-:ALL EXCEPT wheel shutdown sync:LOCAL

#禁止wheel用户通过.win.tue.nl之外的其它它终端访问相关服务
#-:wheel:ALL EXCEPT LOCAL .win.tue.nl

# 禁止下面的用户从任何主机登录。其它用户可以从任意地方访问相关服务
#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL

# root用户允许通过cron来使用tty1到tty6终端访问相关服务
#+ : root : cron crond :0 tty1 tty2 tty3 tty4 tty5 tty6

# 用户root允许从下面的地址访问相关服务
#+ : root : 192.168.20.1 192.168.20.4 192.168.20.9
#+ : root : 127.0.0.1

# 用户root可以从192.168.201.网段访问相关服务
#+ : root : 192.168.201.

# 用户root可以从.foo.bar.org中任何主机访问相关服务
#+ : root : .foo.bar.org

# 用户root不允许从任何主机访问相关服务
#- : root : ALL

# 用户@nis_group和foo可以从任何主机访问相关服务
#+ : @nis_group foo : ALL

# 用户john只能从127.0.0.0/24来对本机相关服务进行访问
#+ : john : 127.0.0.0/24

# 用户john可以通过ipv4和ipv6的地址对本机相关服务进行访问
#+ : john : ::ffff:127.0.0.0/127

# 用户john可以通过ipv6的地址访问本机相关服务
#+ : john : 2001:4ca0:0:101::1

# 用户john可以通过ipv6的主机IP地址来访问本机
#+ : john : 2001:4ca0:0:101:0:0:0:1

# 用户john可以通过ipv6的IP地址和掩码来访问相关服务
#+ : john : 2001:4ca0:0:101::/64

# 开放所有用户对本机所有相关服务的访问
#- : ALL : ALL

示例说明(vsftp):
如果要在网络内架设一个FTP服务器,而且在该FTP服务器上需要强制地指定某个用户只能通过某个IP地址登录,这个时候pam_access.so模块就派上用场了。假设FTP服务器是使用vsftp来构建的,具体操作是:

(1)修改FTP服务器的/etc/pam.d/vsftpd文件,在调用account接口处插入"account    required     pam_access.so"这行内容,如下:
# vim /etc/pam.d/vsftpd
#%PAM-1.0
session    optional     pam_keyinit.so    force revoke
auth       required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed
auth       required pam_shells.so
auth       include  password-auth
account    include  password-auth
account    required     pam_access.so    //添加这一行内容
session    required     pam_loginuid.so
session    include  password-auth
 
上述配置表示当针对FTP访问执行用户类接口的时候会增加pam_access.so的认证。
 
(2)修改/etc/security/access.conf配置文件,在文件底部添加下面的两行:
# vim /etc/security/access.conf
- : kevin : ALL EXCEPT 192.168.10.101
- : grace : ALL EXCEPT 192.168.10.102

前提是已经在系统上事先建立了kevin和grace两个用户,上面的配置表示:
kevin用户不能从192.168.10.101之外的任何客户端访问FTP服务器;
grace用户不能从192.168.10.102之外的任何客户端访问FTP服务器。
 
(3)修改/etc/vsftpd/vsftpd.conf文件,禁用匿名登录:
# vim /etc/vsftpd/vsftpd.conf
......
Anonymous_enable = NO
 
这样当重启vsftpd服务之后,用户kevin将只能从192.168.10.101访问ftp服务,而grace将只能从192.168.10.102访问ftp服务。所以当针对这种需求而且不想使用防火墙以及应用程序自带的认证机制的时候,通过pam_access.so可以实现所需的效果。

2)pam_listfile.so

pam_listfile.so模块的功能和pam_access.so模块类似,目标也是实现基于用户/组,主机名/IP,终端的访问控制。不过它实现的方式和pam_access.so会稍微有些不同,因为它没有专门的默认配置文件。访问控制是靠pam配置文件中的控制选项和一个自定义的配置文件来实现的。而且除了针对上述访问源的控制之外,还能够控制到ruser,rhost,所属用户组和登录shell。所以有些用户认为它的功能似乎比pam_access.so更加灵活和强大一些。

对于pam_listfile.so的配置方法,可以参考vsftpd文件中对pam的调用方式。熟悉vsftpd的人都知道,在vsftpd默认配置中,root用户是不允许通过ftp方式直接访问FTP服务器的。这个功能实际上是由/etc/vsftpd/vsftpd.conf,/etc/vsftpd/ftpusers和/etc/pam.d/vsftpd共同控制的。 因为在/etc/pam.d/vsftpd中有这样的一行配置:
# cat /etc/pam.d/vsftpd
......
auth    required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed

表示当用户试图登录FTP服务器的时候,会调用pam_listfile.so模块来验证用户是否可以登录,这里item=user表示访问控制是基于user即用户实现的。那么哪些用户可以登录呢?就是除了file选项所定义的/etc/vsftpd/ftpusers文件之外的用户,这是由另外一个选项sense=deny所决定的。而在/etc/vsftpd/vsftpd.conf中明确指定了对用户的认证需要通过/etc/pam.d/vsftpd中的配置调用pam模块:
# cat /etc/vsftpd/vsftpd.conf |grep pam_service_name
pam_service_name=vsftpd

而恰好root用户又在/etc/vsftpd/ftpusers文件中,所以这成为了制约root登录FTP服务器的一个必要条件(但不是唯一条件)。所以针对这种情况,要开放和允许root用户登录FTP的权限,至少有三种改法:
1)修改/etc/pam.d/vsftpd文件,将sense=deny改成sense=allow。这样会正好将情况反转过来,FTP服务器只允许/etc/vsftpd/ftpusers文件内的用户登录;
2)修改/etc/pam.d/vsftpd文件,注释掉调用pam_listfile.so那行。这样FTP服务器在认证用户的时候将不再考虑pam_listfile.so模块的任何限制;
3)将root从/etc/vsftpd/ftpuser文件中注释掉;

不过需要注意的是,root用户比较特殊,因为它在vsftpd配置中的限制不仅仅来自于pam,vsftpd本身的配置中也对其做了限制。当我们看/etc/vsftpd/user_list文件的时候,还将会看到这样的配置说明:
# cat /etc/vsftpd/user_list
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
........
........

表示当vsftpd.conf中userlist_deny=NO的时候,系统将只允许user_list中的用户登录FTP服务器;如果userlist_deny=YES,情况将截然相反——此时user_list变成了黑名单,里面的用户将一概不允许登录FTP服务器。所以要彻底开放root登录FTP的权限,我们还要在/etc/vsftpd/vsftpd.conf中增加userlist_deny=YES或者注释掉user_list中的root。

不过不管怎么说,vsftpd中禁用root用户的直接登录是在绝大多数FTP服务器上默认的安全措施,所以开放root权限时应该慎重。

另外除了通过pam_listfile.so实现基于用户的访问控制之外,还可以实现基于其它条件的访问控制。这个可以具体看看pam_listfile.so模块的选项就会比较清楚了,使用pam_listfile.so模块配置的格式分为五个部分:分别是item、onerr、sense、file以及apply。 其中:
a)item=[tty|user|rhost|ruser|group|shell]:定义了对哪些列出的目标或者条件采用规则,显然,这里可以指定多种不同的条件。
b)onerr=succeed|fail:定义了当出现错误(比如无法打开配置文件)时的缺省返回值。
c)sense=allow|deny:定义了当在配置文件中找到符合条件的项目时的控制方式。如果没有找到符合条件的项目,则一般验证都会通过。
d)file=filename:用于指定配置文件的全路径名称。
e)apply=user|@group:定义规则适用的用户类型(用户或者组)。

而至于file文件的写法就简单了,每行一个用户或者组名称即可。所以当需要对其它服务进行类似的访问控制的时候,就可以照葫芦画瓢。例如现在需要在SSH服务器上对ssh客户端实现基于用户的访问控制。

示例说明一:
不允许borger账号通过ssh方式登录。做法如下:

1)针对这种需求只需要更改/etc/pam.d/sshd文件,并在该文件中添加一行(一定要添加到第一行):
# vim /etc/pam.d/sshd
auth required pam_listfile.so  item=user sense=deny file=/etc/pam.d/denyusers onerr=succeed
......
 
2)创建borger账号
# useradd borger
# passwd borger
Changing password for user borger.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
 
3)建立文件/etc/pam.d/denyusers,并在文件中写入用户信息。
# echo "borger" > /etc/pam.d/denyusers
# cat /etc/pam.d/denyusers
borger
 
4)测试使用borger账号通过ssh方式登录不上了
# ssh -p22 borger@localhost
borger@localhost's password:
Permission denied, please try again.
borger@localhost's password:
 
表示用户以ssh登录必须要通过pam_listfile.so模块进行认证,认证的对象类型是用户,采用的动作是禁止,禁止的目标是/etc/pam.d/denyuser文件中所定义的用户。这样在该条目添加到该文件之后,使用borger账号从其它主机远程ssh访问服务器会出现密码错误的提示,但是使用root或者其它用户则访问能够成功!
 
再次强调,要注意pam模块使用的顺序,刚才的规则一定要添加到/etc/pam.d/sshd文件的auth的第一行之前,否则不会生效!!!

示例说明二:
仅仅允许kevin用户可以通过ssh远程登录。做法如下:
在/etc/pam.d/sshd文件中添加一条(务必添加到文件的第一行!):
auth required pam_listfile.so item=user sense=allow file=/etc/sshdusers onerr=succeed

添加两个用户kevin和grace
# useradd kevin
# passwd kevin
# useradd grace
# passwd grace

编辑file指定的文件,添加上一个用户kevin(这一步是关键)
# echo "kevin" >/etc/sshdusers    //文件/etc/sshdusers是在上面添加到/etc/pam.d/sshd中定义的

然后验证,发现使用kevin账号能正常ssh登录,使用grace账号就不能正常ssh登录了!

# ssh -p22 kevin@localhost
kevin@localhost's password:
Last login: Thu Mar 29 12:02:18 2018 from 192.168.10.206
 
# ssh -p22 grace@localhost
grace@localhost's password:
Permission denied, please try again.
 
# ssh -p22 root@localhost
root@localhost's password:
Permission denied, please try again.

注:此处如果root也使用ssh远程连接,也会受到pam_listfile.so限制的。

温馨提示:如果发生错误,Linux-PAM 可能会改变系统的安全性。这取决于你自己的选择,你可以选择不安全(开放系统)和绝对安全(拒绝任何访问)。通常,Linux-PAM 在发生错误时,倾向于后者。任何的配置错误都可能导致系统整个或者部分无法访问。配置 Linux-PAM 时,可能遇到最大的问题可能就是 Linux-PAM 的配置文件/etc/pam.d/*被删除了。如果发生这种事情,你的系统就会被锁住。有办法可以进行恢复,最好的方法就是用一个备份的镜像来恢复系统,或者登录进单用户模式然后进行正确的配置。

3)pam_limits.so模块

pam_limits.so模块的主要功能是限制用户会话过程中对各种系统资源的使用情况。缺省情况下该模块的配置文件是/etc/security/limits.conf。而该配置文件的基本格式实际上是由4个字段组成的表,其中具体限制的内容包括:
Domain            type            item                                     value
用户名/组名       软/硬限制                                                   具体值

core——core文件大小 (KB)
data——最大数据大小(KB)
fsize——最大文件大小(KB)
memlock——最大可用内存空间(KB)
nofile——最大可以打开的文件数量
rss——最大可驻留空间(KB)
stack——最大堆栈空间(KB)
cpu——最大CPU使用时间(MIN)
nproc——最大运行进程数
as——地址空间限制
maxlogins——用户可以登录到系统最多次数
locks——最大锁定文件数目

需要注意的是,如果没有任何限制可以使用"-"号,并且针对用户限制的优先级一般要比针对组限制的优先级更高。使用pam_limits.so模块的最常见的场景是在运行Oracle数据库的RHEL服务器中,因为一般Oracle数据库在安装之前,按照其官方文档的说明需要先对某些用户(Oracle)使用系统资源的情况进行限制。所以我们总是能够在Oracle数据库服务器的/etc/security/limits.conf文件中看到类似这样的配置:
# vim /etc/security/limits.conf
.......
oracle           soft    nproc   2048
oracle           hard    nproc   16384
oracle           soft    nofile  1024
oracle           hard    nofile  65536

结合上面的配置文件说明,可知Oracle数据库需要对Oracle用户使用资源的情况进行一些限制,包括:oracle用户最大能开启的进程数不超过16384,最大能打开的文件数不超过65536。

至于soft和hard的区别,不同于磁盘配额中的软限制和硬限制。普通用户可以调整自己的soft limit但最高不能超过hard limit,而且除了root以外的普通用户也不能够随意更改hard limit。该调整完成之后一般可以使用ulimit命令查看。

顺便提一下,针对nofile,这个只是基于用户层面的限制和调整方法。基于系统层面的限制和调整方法是修改/etc/sysctl.conf文件,直接改fs.file-max参数,调整之后sysctl –p生效。

示例说明:
pam_limits.so模块也可以使用在对一般应用程序使用的资源限制方面。如果需要在SSH服务器上对来自不同用户的ssh访问进行限制,就可以调用该模块来实现相关功能。例如,当需要限制用户borger登录到SSH服务器时的最大连接数(防止同一个用户开启过多的登录进程)。限制操作如下:

由于/etc/pam.d/system-auth中,默认就会通过pam_limits.so 限制用户最多使用多少系统资源
# cat /etc/pam.d/system-auth|grep limits.so
session     required      pam_limits.so
 
因此只需要在/etc/security/limits.conf文件中增加一行对borger用户产生的连接数进行限定:
# vim /etc/security/limits.conf
......
borger             hard    maxlogins       2

最后测试
从客户端以borger身份登录SSH服务器时,在客户端上可以打开两个控制台登录。但当客户端开启第三个登录窗口的时候会被服务器拒绝,但其它用户不会受到限制。

注意:这样限制的只是从客户端以ssh方式登录次数的场景,如果从shell登录,则不受限制!

4)pam_rootok.so模块

一般情况下,pam_rootok.so模块的主要作用是使uid为0的用户,即root用户能够直接通过认证而不用输入密码。pam_rootok.so模块的一个典型应用是插入到一些应用程序的认证配置文件中,当root用户执行这些命令的时候可以不用输入口令而直接通过认证。比如说"su"命令,为什么当以root用户执行"su"切换到普通用户身份的时候是不需要输入任何口令而可以直接切换过去?当我们查看一下/etc/pam.d/su文件的内容就不会奇怪了。因为该文件的第一行就是:

# cat /etc/pam.d/su
......
auth        sufficient  pam_rootok.so

而如果将该行配置注释掉的情况下,就会发现即便以root用户切换普通用户的时候仍然要求输入口令。另外一种方法,只需要将上述的"sufficient"改成"required"即可。因为这样,pam_rootok.so模块的验证通过就成为了必要条件之一。

pam_rootok.so模块的另外一个应用是在chfn命令中。Chfn命令用于改变/etc/passwd中的用户的说明字段。当以root身份执行chfn命令修改用户信息的时候是不用输入密码的。但是以普通用户身份执行chfn则需要输入密码之后才能改变自己的用户说明。这实际上也是因为在/etc/pam.d/chfn配置文件中的第一行调用了pam_rootok.so的结果。

不过这里即便将该配置中的第一行注释掉,root用户通过chfn修改自己信息的时候仍然不需要使用密码。所以恐怕效果不是很明显。究其原因主要是很多PAM模块对root用户是不会产生限制的。

示例说明(禁用用户间使用su切换命令):

su的缺点
1)不安全su工具在多人参与的系统管理中,并不是最好的选择,su只适用于一两个人参与管理的系统,毕竟su并不能让普通用户受限的使用;超级用户root密码应该掌握在少数用户手中。
2)麻烦:需要把root密码告知每个需要root权限的人。

可以在/etc/pam.d/su文件里设置禁止用户使用su命令
# vim /etc/pam.d/su
auth sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
# Uncomment the following line to require a user to be in the "wheel" group.
#auth required pam_wheel.so use_uid
...........

a)以上标红的两行是默认状态(即开启第一行,注释第二行),这种状态下是允许所有用户间使用su命令进行切换的!(或者两行都注释也是运行所有用户都能使用su命令,但root下使用su切换到其他普通用户需要输入密码;如果第一行不注释,则root使用su切换普通用户就不需要输入密码)
b)如果开启第二行,表示只有root用户和wheel组内的用户才可以使用su命令。
c)如果注释第一行,开启第二行,表示只有wheel组内的用户才能使用su命令,root用户也被禁用su命令。

5)pam_userdb.so模块

pam_userdb.so模块的主要作用是通过一个轻量级的Berkeley数据库来保存用户和口令信息。这样用户认证将通过该数据库进行,而不是传统的/etc/passwd和/etc/shadow或者其它的一些基于LDAP或者NIS等类型的网络认证。所以存在于Berkeley数据库中的用户也称为虚拟用户。

pam_userdb.so模块的一个典型用途就是结合vsftpd配置基于虚拟用户访问的FTP服务器。

相对于本地用户以及匿名用户来说,虚拟用户只是相对于FTP服务器而言才有用的用户,这些用户被严格地限定在pam_userdb数据库当中。所以虚拟用户只能访问FTP服务器所提供的资源,因而可以大大提高系统安全性。另外相对于匿名用户而言,虚拟用户必须通过用户名和密码才能够访问FTP的资源。这样也提高了对FTP用户下载的可管理性。

基于虚拟用户实现的vsftpd的原理基本上是这样一个过程:先定义一些专门针对FTP的虚拟用户,然后将用户信息加入到系统自带的数据库中(但不是passwd)从而生成一个访问FTP的虚拟用户列表,这里使用的数据库是db4也就是Berkeley DB。然后可以通过使用pam_userdb.so模块来调用该数据库存储用户信息以及实现FTP用户认证。当然同时也可以在系统中通过对配置文件的定义和划分来实现对不同虚拟用户不同类型的访问控制。

6)pam_cracklib.so模块

pam_cracklib.so是一个常用并且非常重要的PAM模块。该模块主要的作用是对用户密码的强健性进行检测。即检查和限制用户自定义密码的长度、复杂度和历史等。如不满足上述强度的密码将拒绝用户使用。pam_cracklib.so比较重要和难于理解的是它的一些参数和计数方法,其常用参数包括:

debug:将调试信息写入日志;
type=xxx:当添加/修改密码时,系统给出的缺省提示符是"New UNIX password:"以及"Retype UNIX password:",而使用该参数可以自定义输入密码的提示符,比如指定type=your own word;
retry=N:定义登录/修改密码失败时,可以重试的次数;默认是1次。
difok=N:定义新密码中必须至少有几个字符要与旧密码不同,默认是5个。但是如果新密码中有1/2以上的字符与旧密码不同时,该新密码将被接受;
diginore=N:默认当新密码有23个字符时,difok选项会被忽略。
minlen=N:定义用户密码的最小长度;
dcredit=N:定义用户密码中必须至少包含多少个数字;
ucredit=N:定义用户密码中必须至少包含多少个大写字母;
lcredit=N:定义用户密码中必须至少包含多少个小些字母;
ocredit=N:定义用户密码中必须至少包含多少个特殊字符(除数字、字母之外);
use_authtok:在某个与密码相关的验证模块后使用此选项,例如pam_unix.so验证模块。

特别要注意:
当N>0时,N代表新密码中最多可以有N个指定的字符!
当N<0时,N代表新密码中最少可以有N个指定的字符!

同时建议重启系统使之生效!

/etc/pam.d/login文件里包含了/etc/pam.d/system-auth文件的配置

# cat /etc/pam.d/login|grep system-auth
auth       include      system-auth
account    include      system-auth
password   include      system-auth
session    include      system-auth

如下看pam_cracklib.so的一个应用实例:在/etc/pam.d/system-auth中使用pam_cracklib.so来限制用户修改自己密码时必须满足一定的强健性要求。

# cat /etc/pam.d/system-auth
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so
 
account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 500 quiet
account     required      pam_permit.so
 
password    requisite     pam_cracklib.so try_first_pass retry=3 type=
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so
 
session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
 
-----------------------------------------------------------------------------
从上面使用pam_cracklib.so的策略看,要求用户修改密码时必须要满足9位,并且密码中至少要包含一个大写字母、小写字母、数字和特殊符号。但是实际上像minlen和所有credit所对应的数值可以是非0之外的正负整数,那么这些数值到底表示什么意思呢?

很多人将其简单地理解为某一类字符的位数,其实远远没有那么简单。下面对这些数值和关系做一个简短的说明:

首先要明确整个环境中密码的长度要满足下面的计算公式:
计算公式:
最小密码长度(minlen)应该小于或者等于 dcredit+ucredit+lcredit+ocredit+其它分值 (同时满足 * credit的条件)。
 
注意:
*credit=-1表示至少有一个的意思
*credit=N(N表示当满足条件的时候加N分,例如dcredit=2表示一个数字加2分,两个数字加4分)
所以这里minlen其实更准确的表述应该是mincredit。

所以在下面的例子中,当pam_cracklib.so的参数按如下方式指定:
password    requisite     pam_cracklib.so try_first_pass retry=3 minlen=12 dcredit=2 ucredit=0 lcredit=0 ocredit=0

那么当用户执行命令修改密码的时候:
$ passwd
Changing password for user borger.
Changing password for borger
(current) UNIX password:
New UNIX password:    输入密码"1\=poiuyt"   不成功 1个数字再加2分

此时密码有一个数字,2分,其它的字符每个1分,总共10分,不满足minlen的位数需求,所以该密码不能通过。
BAD PASSWORD: is too simple
New UNIX password:    输入密码"12\=poiuyt"   成功     2个数字再加2分
Retype new UNIX password:

此时密码有两个数字,4分,其它的字符每个1分,总共12分,满足minlen的位数需求,所以密码可以通过。
New UNIX password:    输入密码"1\=poiuytre"   成功     1个数字再加2分
Retype new UNIX password:

此时密码有1个数字,2分,其它的字符每个1分,总共12分,满足minlen的位数需求,所以密码可以通过。
 
因此通过上述的配置基本可以得出这样的结论:当某类credit为正数N的时候,表示密码中该类字符一个可以加N分;当某类credit为负数N的时候,表示密码中某类字符必须具备N个。时间关系我将不会一一演示。

所以当输入的密码所有的字符总分大于或者等于minlen,并且满足所有credit的要求,该密码通过;即:输入的密码长度(每个输入值都算数)+*credit(加分)>=minlen

所以pam_cracklib.so模块在系统安全管理策略和管理中的用途是非常重要和广泛的。

pam_cracklib 模块式PAM配置接口的基本模块,在Debian系统中配置文件是 /etc/pam.d/common-password 但是在Redhat系统中配置文件是 /etc/pam.d/system-auth 配置大致像这样:
password required pam_cracklib.so retry=3 minlen=6 difok=3
password required pam_unix.so md5 use_authtok

第一行是 pam_cracklib模块和设置的几个模块参数
第二行是 pam_unix模块,MD5表示采用MD5加密

pam_cracklib可以记录用户使用的历史密码,并且不允许用户重复使用旧的密码,实际上存储用户旧密码的是通过pam_unix模块实现的。第一步是建立一个空文件用来存储旧密码/etc/security/opasswd,如果你没有建立文件却使用了历史密码记录功能的话,所有的密码更新都会失败,因为pam_unix模块会报错。

opasswd就像/etc/shadow文件,因为他记录用户密码的哈希
touch /etc/security/opasswd
chown root:root /etc/security/opasswd
chmod 600 /etc/security/opasswd

一旦建立了opasswd文件,就可以在pam_unix模块后面加上参数remember=N来开始记录旧密码,remember参数记录你想记录多少旧密码,他的最大值是400,如果你设置的值超过400会当做400来对待,例如:
password required pam_cracklib.so retry=3 minlen=12 difok=4
password required pam_unix.so md5 remember=12 use_authtok

opasswd文件内容格式如下:
hal:1000:<n>:<hash1>,<hash2>,...,<hashn>

文件以':'分割,第一列是用户名,第二列是用户ID,第三列是目前记录了该用户多少个旧密码,hashN是每次密码的MD5值,opasswd在某些系统安装PAM模块时会自动建立。

密码字典检查

pam_cracklib 也可以检查用户设置的密码是不是违反系统内部的密码字典,在Debian系统中pam_cracklib的密码字典在/var/cache/cracklib目录下,而且每天晚上update-cracklib脚本会自动的rebuild密码字典。

/etc/login.defs 文件设置密码过期时间等一系列参数,注意login.defs中设置的参数只有是用系统的useradd程序新建的一个用户时才会有login.defs中设置的属性,如果是用其他机器新建的用户,则没有以上属性,不过可以试用chage命令手动添加相关属性。

chage参数如下:
-m 密码可更改的最小天数。 为零时代表任何时候都可以更改密码。
-M 密码保持有效的最大天数。
-W 用户密码到期前,提前收到警告信息的天数。
-E 帐号到期的日期。过了这天,此帐号将不可用。
-d 上一次更改的日期
-i 停滞时期。如果一个密码已过期这些天,那么此帐号将不可用。
-l 例出当前的设置。由非特权用户来确定他们的密码或帐号何时过期。

关于 opasswd

相当于old-paswwd,记录了每用户在过去的5次密码的hash值,来看其最近使用的5次密码中有没有重复使用的。

Prevent From Using Or Reuse Same Old Passwords

In Red Hat Enterprise Linux 7 (RHEL 7) the password history is stored in the file /etc/security/opasswd. You can only edit this file while logged in as the root user.

pam_unix/pam_unix2 module

This is the standard Unix authentication module. It uses standard calls from the system's libraries to retrieve and set account information as well as authentication. Usually this is obtained from the /etc/passwd and the /etc/shadow file as well if shadow is enabled.

This module provides functionality for PAM modules such as authentication, account management and more. Same module can be used to maintain a list of old passwords for every user. This is useful if you want to disallow use of old passwords. The old password list is located in the /etc/security/opasswd file.

Configuration files

You need to edit the following files:
/etc/login.defs – Shadow password suite configuration
/etc/pam.d/common-auth – OpenSuse/Suse Enterprise Linux pam config file.
/etc/pam.d/system-auth – CentOS/RHEL/Fedora/Red Hat/Scientific Linux pam config file.
/etc/pam.d/common-password – Debian / Ubuntu Linux pam config file.
/etc/security/opasswd – Store old passwords.

/etc/pam.d/common-auth

Edit/add password line and append remember=13 to prevent a user from re-using any of his or her last 13 passwords:
password sufficient pam_unix.so use_authtok md5 shadow remember=13

IF you are using pam_unix2.so, update it as follows:
password sufficient pam_unix2.so use_authtok md5 shadow remember=13

Save and close the file. Please note that the last 13 passwords for each user are saved in /etc/security/opasswd file in order to force password change history and keep the user from alternating between the same password too frequently.

Enable password aging

Edit /etc/login.defs,pam_unix.so/pam_unix2.so is configured to remember 13 passwords. User can not use the same password for at least 3 months (13*7=91 days = 3 months)

# vim /etc/login.defs
#Set the minimum number of days (PASS_MIN_DAYS=7) allowed between password changes:
### Minimum number of 7 days before a user can change the password since the last change ###
PASS_MIN_DAYS=7

Save and close the file.

If the file /etc/security/opasswd does not exist, create the file using touch or shell redirection command:
# [ ! -f /etc/security/opasswd ] && touch /etc/security/opasswd
OR
# [ ! -f /etc/security/opasswd ] && >/etc/security/opasswd

Use the following ls command to verify file permissions:
# ls -lZ /etc/security/opasswd

Linux based system will remember last 13 passwords. If user tries to use any one of the last 13 old passwords, he/she will get an error message as follows on screen:
Password has been already used. Choose another.

参考链接
Linux cracklib模块
sysadmin_pam_cracklib


7)pam_pwhistroy.so模块

pam_pwhistory.so模块也是一个常用模块,一般辅助pam_cracklib.so,pam_tally.so以及pam_unix.so等模块来加强用户使用密码的安全度。不过pam_pwhistory.so模块起的是另一类的作用,即专门为用户建立一个密码历史档案,防止用户在一定时间内使用已经用过的密码。

示例说明:(特别注意:/etc/pam.d/system-auth下的配置针对的是普通用户,在root用户下是无效的)当需要限定用户在90天之内不能重复使用以前曾经使用过的10个密码,那么具体操作方法是去修改/etc/pam.d/system-auth文件,在password接口处增加:
# vim /etc/pam.d/system-auth
......
password  required  pam_cracklib.so  retry=3  password  required  pam_pwhistory.so enforce_for_root remember=10

----------------------------------------------------------------
此时用户使用过的密码将会记录到/etc/security/opasswd文件中。但是pam_pwhistory.so并没有什么选项可以限定密码在多少天之内无法被重复使用,所以上述的90天是无法配置的。一个简单的解决方法就是当90天左右的时候,手动清空一次opasswd文件即可。

当然,如果要实现同样的功能除了pam_pwhistory.so模块之外还有其它的办法,比较常用的是pam_unix.so模块。具体方法是修改/etc/pam.d/system-auth文件,给pam_unix.so模块里加上remember=10这个选项,修改之后的配置文件为:
# vim /etc/pam.d/system-auth
.......
password required pam_unix.so md5 remember=10 use_authtok

这样系统将同样记住10个已经使用的密码。

不过此时/etc/security/opasswd文件因为记录了N个使用过的密码,所以安全性就十分关键了,所以要确保该文件只能被root用户读取和编辑:
# touch /etc/security/opasswd
# chown root:root /etc/security/opasswd
# chmod 600 /etc/security/opasswd


基于来源的访问控制 (auth,account,password,session)
pam_access.so [ debug ] [ nodefgroup ] [ noaudit ] [ accessfile=配置文件 ] [ fieldsep=分隔符 ] [ listsep=分隔符 ]


此模块能够基于账号与来源(主机/网络/终端/$DISPLAY/服务名)的组合执行访问控制。访问控制策略保存在主配置文件(accessfile)(默认=/etc/security/access.conf)与配置片段(/etc/security/access.d/*.conf)中,所有配置片段按顺序依次解析,一旦匹配成功就立即停止继续解析。为了给不同的服务分别指定不同的访问控制策略,可以明确指定 accessfile 参数,这将导致仅解析指定的主配置文件(忽略所有配置片段)。因为配置片段的优先级低于主配置文件且容易被忽略,所以不建议使用配置片段。

此模块能够通过几种不同的组合决定允许或拒绝访问,具体如下:(1)首先,按照 (user, 主机名/域名) 或 (user, IP地址/IP网段) 组合进行匹配;(2)其次,如果用户通过终端访问,那么按照 (user, tty) 组合进行匹配;(3)否则,按照 (user, $DISPLAY) 或 (user, 服务名) 组合进行匹配。一旦找到第一个匹配,就立即停止解析并返回允许或拒绝的结果。

#按照从上到下的顺序依次匹配,并且一旦匹配成功就立即返回,所以策略的顺序非常重要。

#允许 root 用户从特定服务以及特定终端(其中":0"是X终端[键盘+鼠标+屏幕])访问
+:root:cron crond :0 tty1 tty2 tty3 tty4 tty5 tty6

#允许 root 用户从特定的IP地址与网段访问
+:root:127.0.0.0/24 ::ffff:127.0.0.0/127 192.168.200.4 192.168.200.9 192.168.201.0/24 2001:4ca0:0:101::1 2001:4ca0:0:101::/64

#允许 remote 组从非本地登录
+:(remote):ALL EXCEPT LOCAL

#允许 root 组、 nis_admins 网络用户组、 admin 用户从任意来源登录
+:(root) @nis_admins admin:ALL

#允许 wheel 组从本地登录
+:(wheel):LOCAL

#允许 wheel 组中除 john 之外的其他成员从 localhost 与 localhost.localdomain 与 foo.bar.org 主机访问
+:(wheel) EXCEPT john:localhost localhost.localdomain foo.bar.org

#允许 wheel 组中除 john 与 tommy 之外的其他成员从 www.bar.org 域名访问
+:(wheel) EXCEPT john tommy:.www.bar.org

#允许 assistants 组从"192.168.5.0/24"网段内除"192.168.5.97-99"之外的其他IP地址访问
+:(assistants):192.168.5.0/24 EXCEPT 192.168.5.97 192.168.5.98 192.168.5.99

#默认兜底策略(拒绝所有来源的所有用户)
-:ALL:ALL

从上面的实例可知,配置语法非常简单,具体说来就是:以"#"号开头的行表示注释,空行将被忽略,其余每行表示一条策略,每条策略都有三个字段,字段之间的分隔符由 fieldsep 参数决定(默认为冒号":")。[提示]不要在字段分隔符两边添加空白。

第一个字段(权限)必须是"+"或"-"字符之一,分别表示允许(+)与拒绝(-)。

第二个字段(账号)有三种不同的语法:(1)关键字,"ALL"表示任意用户;(2)包含列表,表现为以 listsep 参数(默认=空格/水平制表符/逗号)作为分隔符的一系列登录名、常规用户组[用小括号包围,例如"(group)"]、网络用户组[带有"@"前缀,例如"@nis_group"];(3)排除列表,表现为 EXCEPT 表达式。[注意]为兼容老版本配置文件,默认情况下,没有使用小括号包围的登录名会在未能匹配成功时被当作用户组再次匹配。为避免这种含混不清的语法,强烈建议使用 nodefgroup 选项关闭这个坑爹的兼容性。

第三个字段(来源)有三种不同的语法:(1)关键字,"ALL"表示任意来源、"LOCAL"表示本地登录[匹配所有不含"."的字符串];(2)包含列表,表现为以 listsep 参数(默认=空格/水平制表符/逗号)作为分隔符的一系列来源,可以识别的来源形式如下:(a)终端设备名[剥除"/dev/"前缀]、(b) $DISPLAY 变量值、(c)服务名、(d)主机名与域名[域名以"."开头,例如".www.example.com"]、(e)网络主机组[以"@"开头,例如"@nis_hostgroup"]、(f)IP地址与IP网段[IP网段用"network/mask"表示,例如"192.168.5.0/24"];(3)排除列表,表现为 EXCEPT 表达式。

如果在编译 Linux PAM 时开启了审计支持,此模块还将通过系统日志(syslog)报告所有被拒绝的访问(除非使用 noaudit 选项强制关闭审计)。另外,也可以使用 debug 选项在系统日志(syslog)中输出详细的调试信息。

拒绝访问 (auth,account,password,session)
pam_deny.so


此模块没有任何选项或参数,用于无条件的拒绝访问,常用于默认配置(other)之中。
显示文本消息 (auth,account,password,session)

pam_echo.so [file=消息文件]
此模块在流程栈中一般用作 optional 条件,用于显示一些提示消息。文本中的百分号(%)是替换标记,可以识别的替换标记如下:

%H:远程主机名(PAM_RHOST)
%h:本地主机名
%s:服务名(PAM_SERVICE)
%t:正在使用的控制终端(PAM_TTY)
%U:远程用户名(PAM_RUSER)
%u:本地用户名(PAM_USER)

所有其他不能识别的替换标记都只简单的去掉前导百分号(例如"%%"将被替换为"%")。

设置与撤销环境变量 (auth,session)
pam_env.so [debug] [conffile=配置文件] [envfile=变量文件] [readenv=0|1]


此模块用于设置与撤销环境变量(也包括PAM变量,例如"PAM_RHOST")。首先,执行配置文件(conffile)(默认=/etc/security/pam_env.conf)中的指令;然后,根据 readenv 的指示(1=是[默认]|0=否)决定是否继续加载变量文件(envfile)(默认=/etc/environment)。

配置文件(conffile)用于变量的设置/撤销/修改。配置文件的语法非常简单,以井号(#)开头的行表示注释、空行将被忽略、其余的行必须符合如下格式:
变量名 [DEFAULT=[默认值]] [OVERRIDE=[指定值]]

行首的"变量名"一般使用全大写字母且不能有前导空白,可选的 DEFAULT 关键字用于设置变量的默认值(默认为空字符串)(不会覆盖变量的原有值),可选的 OVERRIDE 关键字用于强制覆盖变量的原有值。可以在"默认值/指定值"中使用 ${XXX} 语法引用(可能不存在的)环境变量、使用 @{XXX} 语法引用(可能不存在的)PAM变量。 HOME 与 SHELL 是两个特例,它们既可以是环境变量也可以是PAM变量,当用作PAM变量时, @{HOME} 与 @{SHELL} 的值实际上来源于该用户在 /etc/passwd 中登记的值(可能不等于环境变量 ${HOME} 与 ${SHELL} 的值)。注意,因为应用程序在调用此模块时,有可能尚未设置所需的环境变量,所以某些环境变量在调用此模块时可能尚不存在,例如 ${HOME} 就经常用 @{HOME} 来代替。下面是一个配置文件(conffile)实例:

#/etc/security/pam_env.conf
#为远程主机设置 REMOTEHOST 变量,并将默认值设为"localhost"
REMOTEHOST     DEFAULT=localhost OVERRIDE=@{PAM_RHOST}
#为 DISPLAY 变量设置一个合理的值
DISPLAY        DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
#其他一些常规变量
PAGER          DEFAULT=less
MANPAGER       DEFAULT=less
LESS           DEFAULT="M q e h15 z23 b80"
NNTPSERVER     DEFAULT=localhost
PATH           DEFAULT=${HOME}/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/bin/X11:/usr/bin/X11
XDG_DATA_HOME  DEFAULT=@{HOME}/share/
#一些针对特殊字符的例子(仅支持对 $ 与 @ 的转义,不支持对引号的转义)
DOLLAR         DEFAULT=\$
DOLLARDOLLAR   DEFAULT=        OVERRIDE=\$${DOLLAR}
DOLLARPLUS     DEFAULT=\${REMOTEHOST}${REMOTEHOST}
ATSIGN         DEFAULT=""      OVERRIDE=\@

变量文件(envfile)仅用于环境变量的设置。变量文件的语法非常简单,以井号(#)开头的行表示注释、空行将被忽略、其余的行必须符合 KEY=VAL 格式(若想兼容bash脚本也可以添加可选的 export 指令前缀)。

注意,因为设置PAM变量会影响其他PAM模块的行为,所以应该将此模块放在流程栈的末尾。另外,出于调试目的,还可以使用 debug 选项在系统日志(syslog)中输出详细的调试信息。

调用外部命令 (auth,account,password,session)
pam_exec.so [ debug ] [ expose_authtok ] [ seteuid ] [ quiet ] [ quiet_log ] [ stdout ] [ log=日志文件 ] [ type=模块类型 ] 外部命令 [ 参数 ... ]


此模块用于调用外部命令。子进程(外部命令)除了继承当前进程的环境变量之外,还能使用下列PAM变量:PAM_RHOST, PAM_RUSER, PAM_SERVICE, PAM_TTY, PAM_USER, PAM_TYPE(account, auth, password, open_session, close_session 之一)。注意,父进程的用户决定了外部命令(子进程)能够看到的环境变量。

使用 debug 选项可以在系统日志(syslog)中输出详细的调试信息。使用 expose_authtok 选项表示被调用的外部命令可以从标准输入(STDIN)读取密码。使用 seteuid 选项表示以调用进程(父进程)的 EUID(effective UID) 身份调用外部命令(默认=调用进程的实际UID[real UID])。使用 quiet 选项表示在外部命令出错(退出码≠0)时不显示退出状态(默认=外部命令出错时显示退出状态)。使用 quiet_log 选项表示在外部命令出错(退出码≠0)时不在日志中记录退出状态(默认=外部命令出错时在日志中记录退出状态)。当未使用 stdout 选项时,外部命令的标准输出(STDOUT)将会被记录到 log= 参数指定的日志文件(默认=/dev/null)中;当使用 stdout 选项时,则忽略 log= 参数,并将外部命令的标准输出(STDOUT)重定向至调用进程(父进程),由调用进程负责处理。可以使用 type= 参数限定仅在当前模块的类型与给定的类型(auth,account,password,session 之一)匹配时才调用外部命令。下面是一个实例:

#可用于向 /etc/pam.d/passwd 中添加的行
#在本地密码被修改的同时重建NIS数据库(以EUID身份执行 make -C /var/yp 命令)
password optional pam_exec.so seteuid /usr/bin/make -C /var/yp

传统UNIX密码验证 (auth,account,password,session)
pam_unix.so [nullresetok|nullok] [try_first_pass|use_first_pass] [nodelay] [use_authtok] [shadow] [sha256|sha512] [rounds=N] [minlen=N] [no_pass_expiry] [debug|audit] [quiet]


标准的传统UNIX密码验证(基于 /etc/passwd 与 /etc/shadow 验证和设置帐户信息)。"auth"组件用于验证密码(默认拒绝空密码访问)。"account"组件用于验证账户与密码的有效性、建议更改即将过期的密码、拒绝失效的账户与密码。"password"组件用于更新密码(默认哈希算法取决于 /etc/login.defs 文件中的 ENCRYPT_METHOD 变量)。"session"组件用于记录用户的登录与退出(/var/log/[uwb]tmp)。此模块支持下列选项:

nullresetok|nullok
仅在必须重设密码时才允许使用空密码访问(nullresetok)还是无条件允许使用空密码访问(nullok)

try_first_pass|use_first_pass
"try_first_pass"表示在提示输入密码之前首先尝试流程栈中先前模块的密码,一旦尝试成功,就直接不再提示输入密码。"use_first_pass"表示强制使用流程栈中先前模块的密码(绝不提示输入密码),如果验证失败(包括不存在先前模块的密码),那么直接拒绝访问。

nodelay
取消"auth"组件验证密码失败后的阻塞延迟(默认阻塞延迟2秒)

use_authtok
在修改密码时,强制将新密码设置为前一个 password 模块(例如 pam_passwdqc 模块)提供的密码。

shadow
明确要求使用影子密码(/etc/shadow)

sha256|sha512
保存新密码时所使用的哈希算法

rounds=N
保存新密码时循环哈希的轮数(默认=5000)

minlen=N
限制最小密码长度

no_pass_expiry
不检查密码有效期(例如当 sshd 仅使用公钥认证时可能需要使用此选项)

debug|audit
在系统日志中输出详细(debug)或超级详细(audit)的调试信息

quiet
停止向系统日志中输出与会话的开启/结束有关的消息(静默模式)

下面是一个 /etc/pam.d/login 实例:

#验证密码
auth       required   pam_unix.so
#确保账号和密码仍然处于有效期
account    required   pam_unix.so
#在更改密码前首先用 pam_passwdqc 确保新密码符合复杂性要求
password   required   pam_passwdqc.so config=/etc/passwdqc.conf
password   required   pam_unix.so use_authtok nullresetok sha512
#建立会话
session    required   pam_unix.so