PAM(Pluggable Authentication Modules )是由Sun提出的一種認證機制。它通過提供一些
動態鏈接庫和一套統一的API,將系統提供的服務 和該服務的認證方式分開,使得系統管理
員可以靈活地根據需要給不同的服務配置不同的認證方式而無需更改服務程序,同時也便於
向系 統中添加新的認證手段。
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
s

五、密碼映射(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組的用戶有超級用戶
的存取權限

參考資料:

1、DCE/OSF-RFC 86.0
2、Linux-PAM documentation & source code
3、Sun Solaris PAM documentation
創作者介紹

Amin's Note

Aminzai 發表在 痞客邦 PIXNET 留言(0) 人氣()