PAM:驗證奇才

tication t、session session

PAM,即Pluggable Authentication Modules(可插入式身份驗證模組)最初是由Sun公司發明的,Sun把它作為一種驗證用戶身份的靈活方法。它通過提供一些動態程式庫和一套統一的API,將系統提供的服務和該服務的認證方式分開,使得系統管理員可以靈活地根據需要給不同的服務配置不同的認證方式而無需更改服務程式,同時也便於向系 統中添加新的認證手段。PAM最初是集成在Solaris中,目前已移植到其它系統中,如Linux、SunOS、HP-UX 9.0等。

多年以來,UNIX環境下的身份驗證機制一直就是簡單地把用戶同他們在/etc/passwd檔案里的配置項關聯起來而已。後來,因為需要有更強的安全性,而且要支持更大範圍的驗證機制(像智慧卡),所以對靈活性更好的驗證方法的需求也就應運而生。某些PAM LDAP模組對全局的驗證目錄集中執行驗證。

Linux-PAM

所有完善的Linux發行版本都帶Linux-PAM,它和Sun公司PAM標準目前的實現沒有關係。PAM的概念很簡單:需要驗證功能的程式只需要知道有一個模組可以用來替它們執行驗證功能就行了。PAM的設定保證了模組可以隨時添加、刪除和重新配置—對於編譯工具程式的時候就被連結進來(甚至原本就有)的模組來說,沒必要這樣做。這種結構的效果就是,PAM已經成為系統管理員極其強大的工具。

PAM模組是通過/etc/pam.d目錄下的檔案來進行配置的。這個目錄下針對每種服務的檔案所包含的配置項都有如下形式:

module-type control-flag module-path arguments

module-type欄位可以取的值有auth、account、session或者password。auth確定用戶是誰,還可能確定他是哪一個組的成員。account實行不基於身份驗證的決策,比如根據一天中的時間來訪問。session實現了在提供給用戶服務的前後需要完成的任務。最後,password用於要求用戶提供驗證信息(比如口令)的情況。

control-flag欄位有4個可能的取值:required、requisite、sufficient和optional。required和optional最常用,它們分別表示:為了程式繼續執行模組必須取得成功,或者模組成功與否沒有關係。

第3個和第4個欄位是動態載入模組對象的路徑和參數。如果路徑的第1個字元是/,它就被當作是一個絕對路徑。否則,這個欄位的內容就被追加到默認路徑/lib/security的後面。

PAM是上述口令複雜性難題的解決方案之一。pam_cracklib模組能夠強制要求口令符合最低強度要求。具體要求則變化多端,所以要使用 grep找到正確的配置檔案。例如,要保證用戶口令不能被John the Ripper破解(參考20.10.3節了解有關它的更多知識),Fedora上的/etc/pam.d/system-auth應該包括:

password required pam_cracklib.so retry=3 minlen=12 difok=4

有了這幾行,PAM就會把用戶提出的新口令同破解字典和規則集進行對照(這要求有系統庫libcrack,還有一個系統字典/usr/lib /cracklib_dict.*)。如果用戶的口令不符合cracklib的要求,那么螢幕上就會出現像“The password is too simple(口令太簡單)”這樣的出錯信息。

cracklib的參數規則很複雜,不過下面是對上述特定配置的解釋。

參數retry=3指出用戶在輸入一個強口令的時候必須輸入三遍。

參數minlen=12指出口令的最短長度。大寫字母、數字和標點符號由庫特殊處理,從而減小了這個最短長度。參數為minlen=12時,用戶能有的最短口令實際為8個字元,不是12個字元,但是用戶設定一個8字元口令時必須包括所有4種字元類型。

參數difok=4指出新口令至少要有4個字元不會出現在老口令中。

現代Linux發行版本包含並且默認使用pam_cracklib模組,但通常不啟用口令複雜性規則。

PAM模組有數十種。您可以從http://www.kernel.org/pub/linux/libs/pam下載專門的模組以及它們的文檔。

PAM的結構

系統管理員通過PAM配置檔案來制定認證策略,即指定什麼服務該採用什麼樣的認證方法;應用程式開發者通過在服務程式中使用PAM API而實現對認證方法的調用;而PAM服務模組(service 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版本起,支持一種新的語法,具體可參看LinuxPAM文檔。
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。如果名為xxxx的服務所對應的配置檔案/etc/pam.d/xxxx不存 在,則該服務將使用默認的配置檔案/etc/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/ passwd和/etc/shadow進行認證;通過了pam_unix_auth模組的認證之後,還要繼續用pam_listfile模組來檢查該用戶是否出現在檔案/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 password),其它密碼為次密碼(secondary passwords,可能有多個)。主密碼用來對次密碼進行加密。在主密碼認證通過後,認證模組利用主密碼將加密過的次密碼(也稱為 mapped password)解密,並對次密碼進行認證。
註:如果使用了一次性密碼的機制,就不使用密碼映射。

所有服務模組必須支持如下4個映射選項(在第四部分已經簡單解釋過):

1、use_first_pass

這個選項指示本模組不能提示用戶輸入密碼,而是使用已有的密碼,即從第一個向用戶提示輸入密碼的模組那裡取得密碼,並對該密碼進 行認證。

2、try_first_pass

這個選項指示本模組首先嘗試使用已有的密碼,即從第一個向用戶提示輸入密碼的模組那裡取得密碼,並對該密碼進行認證。如果密碼認 證失敗,則再提示用戶輸入密碼。

3、use_mapped_pass

這個選項指示本模組不能向用戶提示輸入密碼,而應使用映射過的密碼,即利用主密碼將加密過的次密碼解密出來並進行認證。

4、try_mapped_pass

這個選項指示本模組首先嘗試使用映射過的密碼,即利用主密碼將加密過的次密碼解密出來並進行認證。如果密碼認證失敗,則再提示用 戶輸入密碼。

密碼映射的例子:

下面是/etc/pam.conf中關於login服務的配置。這裡login共有3種認證機制:Kerberos、UNIX和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

/* 回調函式 */
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組的用戶有超級用戶的存取許可權

相關詞條

熱門詞條

聯絡我們