(1) 什么是PAM
PAM = Pluggable Authentication Modules
Basically, it is a flexible mechanism for authenticating users.
Since the beginnings of UNIX, authenticating a user has been accomplished via the user entering a password and the system checking if the entered password corresponds to the encrypted official password that is stored in /etc/passwd . The idea being that the user *is* really that user if and only if they can correctly enter their secret password.
That was in the beginning. Since then, a number of new ways of authenticating users have become popular. Including more complicated replacements for the /etc/passwd file, and hardware devices Smart cards etc..
The problem is that each time a new authentication scheme is developed, it requires all the necessary programs (login, ftpd etc...) to be rewritten to support it.
PAM provides a way to develop programs that are independent of authentication scheme. These programs need "authentication modules" to be attatched to them at run-time in order to work. Which authentication module is to be attatched is dependent upon the local system setup and is at the discretion of the local system administrator.
(2) Linux PAM 工作流程
一般Linux PAM文件的位置为:
PAM模块文件位置:/lib/security/,由于Sun对于PAM有自己的实现,Solaries放在/usr/lib/security/下面;
PAM模块配置文件位置:/etc/security/
PAM应用程序配置文件位置:/etc/pam.conf或者/etc/pam.d/
Linux下PAM认证流程如下:
+----------------+
| application: X |
+----------------+ / +----------+ +================+
| authentication-[---->--\--] Linux- |--<--| PAM config file|
| + [----<--/--] PAM | |================|
|[conversation()][--+ \ | | | X auth .. a.so |
+----------------+ | / +-n--n-----+ | X auth .. b.so |
| | | __| | | _____/
| service user | A | | |____,-----'
| | | V A
+----------------+ +------|-----|---------+ -----+------+
+---u-----u----+ | | |
| auth.... |--[ a ]--[ b ]--[ c ]
+--------------+
| acct.... |--[ b ]--[ d ]
+--------------+
| password |--[ b ]--[ c ]
+--------------+
| session |--[ e ]--[ c ]
+--------------+
假设有一个应用程序X提供了某项用户服务(上图左边部分),在服务前需要验证用户身份。则X会把认证的任务转交给PAM库,同时X提供一些回调函数 (比如从用户那里获取口令)给PAM库。PAM库(上图中间部分)查找应用程序X的配置文件/etc/pam.d/X,根据X的配置加载相关的模块(上图 中下部分,一般根据功能不同分为四类PAM模块:authentication, account, password, session),完成X所指定的操作。
对于应用程序X来说,它不需要了解用户是通过什么方式认证的,这是管理员的工作,管理员可配置X认证的方式,比如语音认证,智能卡,指纹等。PAM模块则完成实际的认证工作。
假设/etc/pam.d/X的配置如下:
auth required pam_permit.so
auth required pam_warn.so
这表明,如果X需要auth的功能,则PAM模块pam_permit.so和pam_warn.so都必须回答YES才算通过(required 设定项),pam_permit.so模块对任何用户都回答YES,pam_warn.so也是一样,它会在syslog文件写警告信息。
如果你想知道一个应用程序是否支持PAM认证,也可以通过如上的配置看出来,当然还必须看该应用程序是否有动态库链接到PAM库。
(3) 配置文件的语法
PAM配置为单一的文件/etc/pam.conf,或者多个文件/etc/pam.d/*。配置文件大小写无关,当然文件路径和模块参数是大小写相关的。
注释行以#开头,符号 \ 表示折行。
单个配置文件的配置行语法:service-name module-type control-flag module-path args
service-name: 服务名称,也就是本行配置对哪一个服务起作用,常用的服务为ftpd,rlogind,su等;
module-type:模块类型,PAM模块分为四类。auth:认证用户,授权用户的组关系(和/etc/groups无 关);account:与认证无关的帐号管理,比如基于时间或者资源使用情况或者用户的位置允许或者限制为用户提供服务;session:在给用户提供服 务前以及服务后需要做些处理,比如挂载目录,打开或者关闭用户数据交换,这些操作可通过和session模块关联,进而得到适时处理;password: 更新认证令牌,通常对于challenge/response认证方式都有一个这样的模块;
control-flag:应用程序可以配置为让多个PAM模块以栈的形式相继提供操作,每个模块操作的成功或失败,PAM库通过control- flag来决定最终的操作是否成功。当前有这么几类标志:required,每个模块都必须成功整个操作才算成功;requisite,和 required类似,不同的是一旦一个模块失败,则立即返回,不会进行后续模块的操作;sufficient:只要有一个模块成功就立即返回,整个操作 算成功,后续的模块不会被调用;optional,可选模块,成败与否不关紧要,通常Linux PAM会忽略可选模块,不过如果模块栈中没有任何模块明确表示成功或者失败,则整个栈的结果就由可选模块来决定了;include,指示PAM包含参数所 指定的配置文件;
最新的control-flag也会采用如下形式:
[value1=action1 value2=action2 ...]
valueI是如下的返回值之一: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用于设置没有明确定义返回值的情况。
actionI可以是正整数,或者下述值之一:ignore; ok; done; bad; die; reset。如果是正整数,比如J,则指示从当前模块起的下J个模块会被跳过,这允许管理员更精确地定义栈的执行路径。如果是ignore,表明本模块的 返回值不作为整个模块栈判断的依据;如果是bad,则表明本模块返回失败,如果本模块为栈中的第一个模块,则它的状态值作为整个栈来使用;如果是die, 和bad类似,不过会终止整个模块栈,PAM马上返回到应用程序;如果是ok,则表明整个栈的状态会改变为该值,除非前面的模块返回失败;如果是 done,和ok类似,不过模块栈会马上终止,PAM返回到应用程序;如果是reset,则清掉这个模块的内存状态,从下一个栈中的模块开始。
原来的四个control-flag和新的control-flag等价形式为:
required <=> [success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite <=> [success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient <=> [success=done new_authtok_reqd=done default=ignore]
optional <=> [success=ok new_authtok_reqd=ok default=ignore]
module-path:PAM模块路径,如果以/开头,则表明是绝对路径,否则是相对于PAM模块目录的路径。
args:调用模块的参数,和Linux shell命令类似。通常这些参数是和特定的模块相关的,无效的参数会被模块忽略。如果参数中包括空格,应该用方括号包围起来,比如:
squid auth required pam_mysql.so user=passwd_query passwd=mada \
db=eminence [query=select user_name from internet_service where \
user_name='%u' and password=PASSWORD('%p') and \
service='web_proxy']
被方括号包围的字符串如果含有字符[,不用做任何处理,而如果含有],则需要变成\]。形式如下:
[..[..\]..] => ..[..]..
无效的配置行会导致整个认证过程失败,syslog中同时会被记录下来。
多文件的配置文件名为服务名,配置行语法为:module-type control-flag module-path arguments
和单文件配置相比,少了服务名称。
(4) 通用的可选参数
debug
syslog中记录调试信息。
no_warn
不会给应用程序产生警告信息。
use_first_pass
从上一个模块中获取口令,而不是提示用户输入口令。如果上一个模块没有口令则认证失败。
try_first_pass
从上一个模块获取口令,如果没有则提示用户输入口令。
use_mapped_pass
在美国外的地区由于出口限制没有使用。
expose_account
鼓励模块尽量多地显示帐号信息,以看起来更友好些。
(5) 例子
作为起步,我们建立一个没有指定PAM认证时的默认处理方式,如下:
#
# default; deny access /etc/pam.conf
#
OTHER auth required pam_deny.so
OTHER account required pam_deny.so
OTHER password required pam_deny.so
OTHER session required pam_deny.so
这是对单一配置文件而言,如果是多配置文件,则文件名为other,第一列可以不要。
默认情况下拒绝所有来访者,如果系统误配了可能会把所有人拒之门外。pam_deny.so不会记日志,这使得排错更为困难。
因此,通常情况下缺省的配置方式为:
#
# default configuration: /etc/pam.conf
#
OTHER auth required pam_warn.so
OTHER auth required pam_deny.so
OTHER account required pam_deny.so
OTHER password required pam_warn.so
OTHER password required pam_deny.so
OTHER session required pam_warn.so
OTHER session required pam_deny.so
每种类型的栈增加了一个模块pam_warn.so,如果操作失败会记录日志。如果你想模仿传统的Unix认证,可采用如下配置:
#
# default; standard UN*X access
#
OTHER auth required pam_unix.so
OTHER account required pam_unix.so
OTHER password required pam_unix.so
OTHER session required pam_unix.so
对于ftp,这些是不够的,因为它还要允许匿名用户访问,因此通常配置如下:
#
# ftpd; add ftp-specifics. These lines enable anonymous ftp over
# standard UN*X access (the listfile entry blocks access to
# users listed in /etc/ftpusers)
#
ftpd auth sufficient pam_ftp.so
ftpd auth required pam_unix_auth.so use_first_pass
ftpd auth required pam_listfile.so \
onerr=succeed item=user sense=deny file=/etc/ftpusers
pam_ftp.so会在用户认证成功的情况下忽略后续的认证结果(但是后续的认证还是会操作),use_first_pass指示采用pam_ftp.so模块的口令。