Unix上的PAM

PAM最初是集成在Solaris中,目前已移植到其它系统中,如Linux、SunOS、HP-UX 9.0等。 

一、PAM的结构 

PAM的整个框架结构如下图所示: 


系统管理员通过PAM配置文件来制定认证策略,即指定什么服务该采用什么样的认证方法;应 
用程序开发者通过在服务程序中使用PAM API而实现对认证方法的调用;而PAM服务模块(se 
rvice module)的开发者则利用PAM SPI(Service Module API)来编写认证模块(主 要是 
引出一些函数pam_sm_xxxx(  供libpam调用),将不同的认证机制(比如传统的UNIX认证方 
法、Kerberos等)加入到系统中;PAM核 心库(libpam)则读取配置文件,以此为根据将服 
务程序和相应的认证方法联系起来。 
二、PAM支持的四种管理界面: 

1、认证管理(authentication management) 
主要是接受用户名和密码,进而对该用户的密码进行认证,并负责设置用户的一些秘密 
信息。 
2、帐户管理(account management) 
主要是检查帐户是否被允许登录系统,帐号是否已经过期,帐号的登录是否有时间段的 
限制等等。 
3、密码管理(password management) 
主要是用来修改用户的密码。 
4、会话管理(session management) 
主要是提供对会话的管理和记账(accounting)。 

三、PAM的文件: 

/usr/lib/libpam.so.* PAM核心库 
/etc/pam.conf或者/etc/pam.d/ PAM配置文件 
/usr/lib/security/pam_*.so 可动态加载的PAM service module 
对于RedHat,其目录不是/usr/lib,而是/lib。 

四、PAM的配置: 

PAM的配置是通过单个配置文件/etc/pam.conf。RedHat还支持另外一种配置方式,即通过配 
置目录/etc/pam.d/,且这种的优先级要高于单 个配置文件的方式。 

1、使用配置文件/etc/pam.conf 

该文件是由如下的行所组成的: 
service-name module-type control-flag module-path arguments 

service-name 服务的名字,比如telnet、login、ftp等,服务名字“OTHER”代表所有没有 
在该文件中明确配置的其它服务。 
module-type 模块类型有四种:auth、account、session、password,即对应PAM所支持的 
四种管理方式。同一个服务可以调用多个 PAM模块进行认证,这些模块构成一个stack。 
control-flag 用来告诉PAM库该如何处理与该服务相关的PAM模块的成功或失败情况。它有四 
种可能的 值:required,requisite,sufficient,optional。 
required 表示本模块必须返回成功才能通过认证,但是如果该模块返回失败的话,失败 
结果也不会立即通知用户,而是要等到同一stack 中的所有模块全部执行完毕再将失败结果 
返回给应用程序。可以认为是一个必要条件。 
requisite 与required类似,该模块必须返回成功才能通过认证,但是一旦该模块返回 
失败,将不再执行同一stack内的任何模块,而是直 接将控制权返回给应用程序。是一个必 
要条件。注:这种只有RedHat支持,Solaris不支持。 
sufficient 表明本模块返回成功已经足以通过身份认证的要求,不必再执行同一stack 
内的其它模块,但是如果本模块返回失败的话可以 忽略。可以认为是一个充分条件。 
optional表明本模块是可选的,它的成功与否一般不会对身份认证起关键作用,其返回 
值一般被忽略。 
对于control-flag,从Linux-PAM-0.63版本起,支持一种新的语法,具体可参看Linux 
PAM文档。 
module-path 用来指明本模块对应的程序文件的路径名,一般采用绝对路径,如果没有给出 
绝对路径,默认该文件在目录/usr/lib/security下 面。 
arguments 是用来传递给该模块的参数。一般来说每个模块的参数都不相同,可以由该模块 
的开发者自己定义,但是也有以下几个共同 的参数: 
debug 该模块应当用syslog(  将调试信息写入到系统日志文件中。 
no_warn 表明该模块不应把警告信息发送给应用程序。 
use_first_pass 表明该模块不能提示用户输入密码,而应使用前一个模块从用户那里 
得到的密码。 
try_first_pass 表明该模块首先应当使用前一个模块从用户那里得到的密码,如果该 
密码验证不通过,再提示用户输入新的密码。 
use_mapped_pass 该模块不能提示用户输入密码,而是使用映射过的密码。 
expose_account 允许该模块显示用户的帐号名等信息,一般只能在安全的环境下使用 
,因为泄漏用户名会对安全造成一定程度的威 胁。 

2、使用配置目录/etc/pam.d/(只适用于RedHat Linux) 

该目录下的每个文件的名字对应服务名,例如ftp服务对应文件/etc/pam.d/ftp。如果名为x 
xxx的服务所对应的配置文件/etc/pam.d/xxxx不存 在,则该服务将使用默认的配置文件/et 
c/pam.d/other。每个文件由如下格式的文本行所构成: 
module-type control-flag module-path arguments 
每个字段的含义和/etc/pam.conf中的相同。 

3、配置的例子 

例一:用/etc/pam.conf配置默认的认证方式。 

下面的例子将拒绝所有没有在/etc/pam.conf中明确配置的服务。OTHER代表没有明确配置的 
其它所有服务,pam_deny模块的作用只是简 单地拒绝通过认证。 
OTHER auth required /usr/lib/security/pam_deny.so 
OTHER account required /usr/lib/security/pam_deny.so 
OTHER password required /usr/lib/security/pam_deny.so 
OTHER session required /usr/lib/security/pam_deny.so 


例二:通过/etc/pam.d/rsh文件配置rsh服务的认证方式。 

rsh服务认证用户时,先使用/etc/hosts.equiv和.rhosts文件的认证方式,然后再根据/etc 
/nologin文件的存在与否来判断是否允许该用户使用 rsh,最后使用password database来认 
证用户。 

auth required /lib/security/pam_rhosts_auth.so 
auth required /lib/security/pam_nologin.so 
account required /lib/security/pam_pwdb.so 
session required /lib/security/pam_pwdb.so 


例三:通过/etc/pam.conf配置ftpd的认证方式。 

下面是ftpd服务利用PAM模块进行用户认证的三个步骤。首先用pam_ftp模块检查当前用户是 
否为匿名用户,如果是匿名用户,则 sufficient控制标志表明无需再进行后面的认证步骤, 
直接通过认证;否则继续使用pam_unix_auth模块来进行标准的unix认证,即用/etc/ passw 
d和/etc/shadow进行认证;通过了pam_unix_auth模块的认证之后,还要继续用pam_listfil 
e模块来检查该用户是否出现在文件/etc/ ftpusers中,如果是则该用户被deny掉。 
ftpd auth sufficient /usr/lib/security/pam_ftp.so 
ftpd auth required /usr/lib/security/pam_unix_auth.so use_first_pass 
ftpd auth required /usr/lib/security/pam_listfile.so / 
onerr=succeed item=user sense=deny file=/etc/ftpuser 


五、密码映射(password-mapping) 

密码映射允许用户在不同的认证机制下使用不同的密码,其中有一个主密码(primary pass 
word),其它密码为次密码(secondary passwords,可能有多个)。主密码用来对次密码进 
行加密。在主密码认证通过后,认证模块利用主密码将加密过的次密码(也称为 mapped pa 
ssword)解密,并对次密码进行认证。 
注:如果使用了一次性密码的机制,就不使用密码映射。 

所有服务模块必须支持如下4个映射选项(在第四部分已经简单解释过): 

1、use_first_pass 

这个选项指示本模块不能提示用户输入密码,而是使用已有的密码,即从第一个向用户提示 
输入密码的模块那里取得密码,并对该密码进 行认证。 

2、try_first_pass 

这个选项指示本模块首先尝试使用已有的密码,即从第一个向用户提示输入密码的模块那里 
取得密码,并对该密码进行认证。如果密码认 证失败,则再提示用户输入密码。 

3、use_mapped_pass 

这个选项指示本模块不能向用户提示输入密码,而应使用映射过的密码,即利用主密码将加 
密过的次密码解密出来并进行认证。 

4、try_mapped_pass 

这个选项指示本模块首先尝试使用映射过的密码,即利用主密码将加密过的次密码解密出来 
并进行认证。如果密码认证失败,则再提示用 户输入密码。 

密码映射的例子: 

下面是/etc/pam.conf中关于login服务的配置。这里login共有3种认证机制:Kerberos、UN 
IX和RSA认证,两个required控制标志表明用户必 须通过Kerberos认证和UNIX认证才能使用 
login服务,optional选项则说明RSA认证是可选的。首先用户输入主密码进行Kerberos认 证 
;use_mapped_pass选项指示UNIX认证模块利用主密码将用于UNIX认证的次密码解密出来并对 
该次密码进行认证;try_first_pass选项 指示RSA认证模块先使用第一个模块(即Kerberos 
模块)的密码作为进行认证的密码,当对该密码认证失败时才提示用户输入用于RSA认 证的 
次密码。 
login auth required pam_kerb_auth.so debug 
login auth required pam_unix_auth.so use_mapped_pass 
login auth optional pam_rsa_auth.so try_first_pass 

六、PAM API 

1、框架API: 

任何一个支持PAM的服务程序在进行认证时必须以pam_start(  开始进行初始化,最后以pam 
_end(  结束以便进行清理工作。 

2、认证管理API: 

pam_authenticate(  对用户名/密码进行认证。 
pam_setcred(  用来修改用户的秘密信息。 

3、帐户管理API: 

pam_acct_mgmt(  检查帐户本身是否有权限登录系统、帐户是否过期、帐户是否有登录时间 
限制等。 

4、密码管理API: 

pam_chauthtok(  修改用户的密码。 

5、会话管理API: 

一个会话以pam_open_session(  开始,最后以pam_close_session(  结束。 

6、其它: 

pam_get_item(  、pam_set_item(  用来读写PAM事务(transaction)的状态信息。 
pam_get_data(  、pam_set_data(  用来取得和设置PAM模块及会话的相关信息。 
pam_putenv(  、pam_getenv(  、pam_getenvlist(  用来读写环境变量。 
pam_strerror(  返回相关的错误信息。 
例子程序(摘自Sun的白皮书): 

下面的例子使用PAM API写了一个简单的login服务程序(注:这不是个完整的程序,所以省 
略了对pam_close_session的调用)。 

#include <security/pam_appl.h> 

/* 回调函数 */ 
static int login_conv(int num_msg, struct pam_message **msg, struct pam_response 
**response, void *appdata_ptr); 
struct pam_conv pam_conv = {login_conv, NULL}; 
pam_handle_t *pamh; /* 进行认证的PAM句柄 */ 

void main(int argc, char *argv[], char **renvp) 

/* 初始化,并提供一个回调函数 */ 
if ((pam_start("login", user_name, &pam_conv, &pamh)) != PAM_SUCCESS) 
login_exit(1); 

/* 设置一些参数 */ 
pam_set_item(pamh, PAM_TTY, ttyn); 
pam_set_item(pamh, PAM_RHOST, remote_host); 

while (!authenticated && retry < MAX_RETRIES) 

status = pam_authenticate(pamh, 0); /* 密码认证管理,检查用户输入 
的密码是否正确 */ 
authenticated = (status == PAM_SUCCESS); 


if (status != PAM_SUCCESS) 

fprintf(stderr,"error: %s/n", pam_strerror(pamh, status)); /* 显示错误原 
因 */ 
login_exit(1); 


/* 通过了密码认证之后再调用帐户管理API,检查用户帐号是否已经过期 */ 
if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) 

if (status == PAM_AUTHTOK_EXPIRED) 

status = pam_chauthtok(pamh, 0); /* 过期则要求用户更改密码 */ 
if (status != PAM_SUCCESS) 
login_exit(1); 



/* 通过帐户管理检查之后则打开会话 */ 
if (status = pam_open_session(pamh, 0) != PAM_SUCCESS) 
login_exit(status); 

/* 设置用户组 */ 
setgid(pwd->pw_gid); 

/* 
* Initialize the supplementary group access list before 
* pam_setcred because PAM modules might add groups 
* during the pam_setcred call 
*/ 
initgroups(user_name, pwd->pw_gid); 

status = pam_setcred(pamh, PAM_ESTABLISH_CRED); 
if (status != PAM_SUCCESS) 
login_exit(status); 

/* 设置真实的用户ID(或者有效的用户ID)*/ 
setuid(pwd->pw_uid); 

pam_end(pamh, PAM_SUCCESS); /* PAM事务的结束 */ 


/* 
此处可用来实现与login有关的其它内容 
*/ 


/* 出错则清理现场并退出 */ 
static void login_exit(int exit_code) 

if (pamh) 
pam_end(pamh, PAM_ABORT); 
exit(exit_code); 



/* 这个回调函数被PAM认证模块调用以便显示错误信息或者或者用来取得用户输入,采用图 
形界面的服务程序则应使用图形界面来取得 用户输入或显示提示信息*/ 
int login_conv(int num_msg, struct pam_message **msg, struct pam_response **resp 
onse, void *appdata_ptr) 

while (num_msg--) 

switch (m->msg_style) 

case PAM_PROMPT_ECHO_OFF: 
r->resp = strdup(getpass(m->msg)); 
break; 
case PAM_PROMPT_ECHO_ON: 
(void) fputs(m->msg, stdout); 
r->resp = malloc(PAM_MAX_RESP_SIZE); 
fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); 
/* add code here to remove /n from fputs */ 
break; 
case PAM_ERROR_MSG: 
(void) fputs(m->msg, stderr); 
break; 
case PAM_TEXT_INFO: 
(void) fputs(m->msg, stdout); 
break; 
default: 
log_error(); 
break; 


return (PAM_SUCCESS); 


七、PAM SPI 

当服务程序(ftpd、telnetd等)调用PAM API函数pam_xxx(  时,由PAM 框架(libpam)根 
据该服务在/etc/pam.conf文件中的配置调用指 定的PAM模块中对应的SPI函数pam_sm_xxx( 
)。如下: 




API函数的名字为pam_xxx(  ,对应的SPI函数的名字为pam_sm_xxx(  ,即每个服务模块需要 
引出相应的函数以供libpam调用。为方便对 照,再列一下。 


API 对应的 SPI 

帐号管理 pam_acct_mgmt(   pam_sm_acct_mgmt(   

认证管理 pam_authenticate(   pam_ sm_authenticate(   

密码管理 pam_chauthtok(   pam_ sm_chauthtok(   

会话管理 pam_open_session(   pam_ sm_open_session(   

会话管理 pam_close_session(   pam_ sm_close_session(   

认证管理 pam_setcred(   pam_ sm_setcred(   




八、常用的PAM服务模块 

下面是Linux提供的PAM模块列表(只是其中一部分): 

模块文件 模块功能描述 相关配置文件 

pam_access 提供logdaemon风格的登录控制 /etc/security/access.conf 

pam_chroot 提供类似chroot命令的功能 


pam_cracklib 对密码的强度进行一定的检查 库文件libcrack和字典文件 
/usr/lib/cracklib_dict 

pam_deny 总是无条件地使认证失败 

pam_env 设置或取消环境变量 /etc/security/pam_env.conf 

pam_filter 对输入输出流进行过滤 filters 

pam_ftp.so 对匿名ftp用户进行认证 

pam_group 当用户在指定的终端上请求指定的 /etc/security/group.conf 
服务时赋予该用户相应的组权限 

pam_issue 在提示用户输入用户名之前显示 /etc/issue 
/etc/issue文件的内容 

pam_krb4 对用户密码进行Kerberos认证 相应的Kerberos库文件 

pam_lastlog 在用户登录成功后显示关于 /var/log/lastlog 
用户上次登录的信息,并维护 
/var/log/lastlog文件。 

pam_limits 限制用户会话所能使用的系统资源 /etc/security/limits.conf 

pam_listfile 根据指定的某个文件决定是否 例如/etc/ftpusers 
允许或禁止提供服务 

pam_mail 检查用户的邮箱中是否有新邮件 /var/spool/mail/xxxx 

pam_mkhomedir 为用户建立主目录 /etc/skel/ 

pam_motd 显示/etc/motd文件的内容 /etc/motd 

pam_nologin 根据/etc/nologin文件的存在与否 /etc/nologin 
来决定用户认证是否成功 

pam_permit 总是无条件地使认证成功 


pam_pwdb 作为pam_unix_xxxx模块的一个替代。/etc/pwdb.conf 
使用Password Database通用接口 
进行认证。 

pam_radius 提供远程身份验证拨入用户服务 
(RADIUS)的认证 


pam_rhosts_auth 利用文件~/.rhosts和 /etc/hosts.equiv和~/.rhosts 
/etc/hosts.equiv对用户进行认证。 

pam_rootok 检查用户是否为超级用户,如果 
是超级用户则无条件地通过认证。 


pam_securetty 提供标准的Unix securetty检查 /etc/securetty 

pam_time 提供基于时间的控制,比如限制 /etc/security/time.conf 
用户只能在某个时间段内才能登录 

pam_unix 提供标准的Unix认证 /etc/passwd和 /etc/shadow 

pam_userdb 利用Berkeley DB数据库来检查 Berkeley DB 
用户/密码 

pam_warn 利用syslog(  记录一条告警信息 


pam_wheel 只允许wheel组的用户有超级用户 
的存取权限 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值