目錄
第二部分 PAM開發... 7一、Pam應用程序開發... 7
1.1 pam_start() 7
1.2 pam_end() 8
1.3認證管理pam_authenticate() 8
1.4賬戶管理pam_acct_mgmt() 9
1.5會話管理pam_open_session() 10
1.6會話管理pam_close_session() 10
1.7密碼管理pam_chauthtok() 11
1.8認證管理pam_setcred() 11
二、Pam服務模塊開發... 12
2.1認證管理pam_sm_authenticate() 12
2.2賬戶管理pam_sm_acct_mgmt() 13
2.3會話管理pam_sm_open_session() 13
2.4會話管理pam_sm_close_session() 13
2.5密碼管理pam_sm_chauthtok() 14
2.6認證管理pam_sm_setcred() 14
三、Pam配置文件編輯... 14
=================================================================
第二部分 PAM開發
一、Pam應用程序開發
任何一個支持PAM的應用程序在進行認證時必須以pam_start( )開始進行初始化,最后以pam_end( )結束。1.1 pam_start()
1.2 pam_end()1.1.1參數講解點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- Int
- pam_start(
- const char *service_name,
- const char *user,
- const struct pam_conv *pam_conversation,
- pam_handle_t **pamh
- );
servic e_name1.1.2返回值講解
應用的名字,這個名字參數非常重要。
當應用程序執行驗證操作時,libpam庫會在/etc/pam.d/下尋找以service_name命名的配置文件,該配置文件中指定了相關參數,其中包括將要調用哪個動態鏈接庫進行驗證。
配置文件的格式與前面講的/etc/pam.conf的格式基本一致,只是去掉了service-name這一項,因為該配置文件的名字就是service-name。
其實linux系統中/etc/pam.conf這個配置文件在整個pam框架中已經起不到什么作用,至少在ubuntu10.04系統中是否對這個配置文件進行配置,根本什么也不影響。
前面的對/etc/pam.conf的所有介紹均適用於/etc/pam.d/目錄下的配置文件。
user
用戶名,即PAM框架所作用的用戶的名稱。說白了就是你要對哪個用戶進行pam驗證,該用戶就是此輪驗證中(pam_start——pam_end)被操作的對象。
&conv
對話函數conv,用於提供PAM與用戶或應用程序進程通信的通用方法。對話函數是必需的,因為PAM模塊無法了解如何進行通信。通信可以采用 GUI、命令行、智能讀卡器或其他設備等方式進行。這個對話函數是一個回調函數,這里只是對它的一個注冊,接下來的驗證過程中,應用程序和服務模塊之間的所有信息交互都要通過它。對話函數需要應用程序的作者自己編寫。
&pamh
PAM句柄 pamh,即 PAM 框架用於存儲有關當前操作信息的不透明句柄。成功調用 pam_start() 后將返回此句柄。要研究這個pamh,需要對pam的內部實現機制進行了解,有點復雜,暫時先不說這個。大家把它想成類似於一個socket套接字的東西就行,反正就是一個句柄而已。
PAM_ABORT
一般性的錯誤,我也不知道什么叫一般性的錯誤。
PAM_BUF_ERR
內存緩沖區錯誤,具體的我也不知道。
PAM_SUCCESS
成功建立驗證xx,反正就是成功了。
PAM_SYSTEM_ERR
系統錯誤,參數中有無效的指針。有些參數必須提供指向了真實數據的指針變量。
點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_end(
- pam_handle_t *pamh,
- int pam_status);
1.2.1參數講解1.3認證管理pam_authenticate()
pam_end()函數是整個pam驗證過程中,應用程序最后調用的函數。從此以后句柄pamh不再有效,而且所有的占用的內存將被釋放。1.2.2返回值講解
參數pamh就是pam_start()函數中創建的pamh;
參數pam_status,是應用程序在執行pam_end()函數前所執行的最后一個pam API函數的返回值。
Pam_status通常被傳遞給服務模塊的特有的一個回調函數cleanup(),這樣服務模塊就知道關閉應用程序是否成功,然后繼續執行和之前一樣的工作,即給其他應用程序提供驗證服務。
Pam_end()釋放了pam_set_item()和pam_get_item()申請的所有內存,所有對象的指針在pam_end()執行后也都不在有效。
PAM_SUCCESS
應用程序的驗證過程被成功終止。
PAM_SYSTEM_ERR
系統錯誤,例如pamt是個無效指針NULL,或者函數還在被服務模塊調用。
在pam_start()和pam_end()之間就是應用程序要執行的驗證操作。就是所謂的四個服務模塊。當然,你可以只進行其中的一項認證或者幾個認證,哪怕沒有任何驗證操作,只要您認為值得就可以。
1.4賬戶管理pam_acct_mgmt()該函數被用來驗證用戶的合法性(即令牌認證),這個用戶就是在pam_start()參數傳遞的user。User被要求提供一個密碼或者一個簡單的數字輸入。然后服務模塊中對應的pam_sm_authenticate()函數會檢測user的輸入並驗證是否合法。點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_authenticate(
- pam_handle_t *pamh,
- int flags);
1.3.1參數講解
pamh 參數pamh就是pam_start()函數中創建的pamh了(所有函數的pamh參數都相同,下面的函數將不再介紹pamh參數);1.3.2返回值講解
flags 參數flags可以被設置為0,或者設置為如下值:
PAM_SILENT
不輸出任何信息
PAM_DISALLOW_NULL_AUTHTOK
如果用戶沒有注冊,那么服務模塊應該返回PAM_DISALLOW_NULL_AUTHTOK;
PAM_ABORT
如果收到這個,應用程序應該立即調用pam_end()退出;
PAM_AUTH_ERR
user沒有被驗證;
PAM_CRED_INSUFFICIENT
由於一些原因應用程序沒有足夠的憑證來驗證用戶;
PAM_AUTHINFO_UNVAIL
服務模塊不能獲取user的驗證信息,原因可能是網絡或硬件配置錯誤;
PAM_MAXTRIES
服務模塊驗證用戶的次數達到上限,應用程序這邊不要再提交驗證請求了,也就是說不要再運行pam_ authenticate()了;
PAM_SUCCESS
用戶成功通過驗證
PAM_USER_UNKNOWN
該用戶不能夠被服務模塊識別,我估計要么是用戶名格式非法,要么是用戶沒有注冊等其他原因。
1.5會話管理pam_open_session()pam_acct_mgmt()通常被用來確認用戶賬戶是否有效。確認的內容可以包括下面的內容:點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_acct_mgmt(
- pam_handle_t *pamh,
- int flags);
令牌認證(就是pam_authenticate()實現的功能)
賬戶是否過期;
訪問權限
該函數一般在pam_authenticate()成功執行(即用戶通過驗證)之后被調用執行,所以上面內容中的第一項常可以被省略。
1.4.1參數講解
與pam_authenticate完全相同。1.4.2返回值講解
PAM_ACCT_EXPIRED
用戶已經過期失效;
PAM_AUTH_ERR
用戶令牌認證失敗;
PAM_NEW_AUTHTOK_REQD
該用戶賬戶是有效的但是認證令牌是過期的,正確的做法是回復該值要求用戶執行pam_chauthtok()來更新令牌(密碼)在用戶獲得其他服務之前。
PAM_PERM_DENIED
不允許訪問,應該就是所謂的權限控制;
PAM_SUCCESS
認證令牌被成功更新,或者是用過通過認證;
PAM_USER_UNKNOWN
該用戶不能夠被服務模塊識別;
1.6會話管理pam_close_session()該函數為已經成功通過驗證的用戶建立一個用戶會話,該會話應該在后面被函數pam_close_session()終止。點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_open_session(
- pam_handle_t *pamh,
- int flags);
1.5.1參數講解
參數 flags可以被設置為0或者下面的值:1.5.2返回值講解
PAM_SILENT
不輸任何信息;
PAM_ABORT
一般性的失敗;
PAM_BUF_ERR
內存緩沖區錯誤;
PAM_SESSION_ERR
建立會話失敗;
PAM_SUCCESS
成功建立會話;
1.7密碼管理pam_chauthtok()該函數被用來關閉pam_open_session()創建的會話。參數和返回值與pam_open_session()的參數和返回值完全相同。點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_close_session(
- pam_handle_t *pamh,
- int flags);
1.8認證管理pam_setcred()1.7.1參數講解點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_chauthtok(
- pam_handle_t *pamh,
- int flags);
PAM_SILENT1.7.2返回值講解
不輸任何信息;
PAM_CHANGE_EXPIRED_AUTHTOK
告訴服務模塊只更新過期令牌,如果不設置這個參數,應用程序要求更改所有用戶的令牌;
PAM_AUTHTOK_ERR
服務模塊未能獲得新的用戶令牌;
PAM_AUTHTOK_RECOVERY_ERR
服務模塊未能獲得舊的用戶令牌;
PAM_AUTHTOK_LOCK_BUSY
又有用戶令牌被鎖定,服務模塊不能對其進行更改;.
PAM_AUTHTOK_DISABLE_AGING
用戶令牌被至少一個服務模塊禁用了;
PAM_PERM_DENIED
沒有權限;
PAM_SUCCESS
用戶令牌被成功更新;
PAM_TRY_AGAIN
並不是所有的服務模塊都能夠更新用戶令牌,遇到這種情況,用戶令牌都不能得到更新;
PAM_USER_UNKNOWN
該用戶不能夠被服務模塊識別;
pam_setcred()函數被用來創建、維持、或刪除一個用戶的證書。Pam_setcred()應該在user已經通過驗證(after pam_authenticate)並且在會話建立之前(before pam_open_ session)被調用。刪除user證書的操作必須在會話被關閉之后執行(after pam_close_ session).user證書應該被應用程序創建,而不是被pam庫或者服務模塊創建。點擊(此處)折疊或打開
- #include <security/pam_appl.h>
- int
- pam_setcred(
- pam_handle_t *pamh,
- int flags);
1.8.1參數講解
參數flags可以被設置為0或者下面的值:1.8.2返回值講解
PAM_ESTABLISH_CRED
初始化用戶證書;
PAM_DELETE_CRED
刪除用戶證書;
PAM_REINITIALIZE_CRED
完全重置用戶證書;
PAM_REFRESH_CRED
延長用戶證書的生命周期;
PAM_BUF_ERR
內存緩沖區錯誤;
PAM_CRED_ERR
設置(創建、維持、重置、回復、刪除等)用戶證書失敗
PAM_CRED_EXPIRED
用戶證書過期;
PAM_CRED_UNAVAIL
回復用戶證書失敗;
PAM_SUCCESS
數據被成功存儲;
PAM_SYSTEM_ERR
系統錯誤,例如無效的指針被傳入,函數正在被其他模塊調用,或者系統錯誤等等;
PAM_USER_UNKNOWN
該用戶不能被夠服務模塊識別;
二、Pam服務模塊開發
2.1認證管理pam_sm_authenticate()2.2賬戶管理pam_sm_acct_mgmt()pam_sm_authenticate()函數是pam_authenticate()函數在服務模塊中的接口,用於執行驗證用戶令牌的任務。下面將對所有pam_sm_xxx()函數統稱為接口函數。點擊(此處)折疊或打開
- #define PAM_SM_AUTH
- #include <security/pam_modules.h>
- PAM_EXTERN int
- pam_sm_authenticate(
- pam_handle_t *pamh,
- int flags,
- int argc,
- const char **argv);
2.1.1參數講解
服務模塊中6個接口函數的參數完全相同,僅在這里做詳細說明;2.1.2返回值講解
我們永遠無法在我們設計的應用程序中直接調用這6個接口函數,也無法在我們自己設計的服務模塊中讓這6個接口函數相互調用,這6接口函數只能作為回調函數以動態鏈接庫的形式存在,並且只能被PAM庫調用。認證請求和認證服務是分離的,應用程序只負責提出認證請求,服務模塊負責認證,兩者靠PAM庫連接起來。
PAM從認證請求函數中獲得pamh參數和flags參數,並准備作為參數傳遞給對應接口函數(分別對應接口函數中pamh和flags)。然后PAM庫從配置文件(配置文件的名字在pam_start()函數中指定)中的arguments項中,獲取將要傳遞給接口函數的第四個參數argv,並計算出參數的個數作為接口函數的第三個參數。
整個參數傳遞的過程大致描述如上。接下來將不對接口函數的參數進行講解,因為接口函數只能被PAM庫調用,傳遞進來的參數的含義在其他部分已做過說明。
接口函數pam_sm_xxx()的返回值與應用程序中對應函數pam_xxx()的返回值基本一致,不做講解,若有疑問,請參考Man手冊。
#define PAM_SM_ACCOUNT2.3會話管理pam_sm_open_session()
#include
PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv);
#define PAM_SM_SESSION2.4會話管理pam_sm_close_session()
#include
PAM_EXTERN int
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv);
#define PAM_SM_SESSION2.5密碼管理pam_sm_chauthtok()
#include
PAM_EXTERN int
pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv);
#define PAM_SM_PASSWORD2.6認證管理pam_sm_setcred()
#include
PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv);
#define PAM_SM_AUTH
#include
PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv);
三、Pam配置文件編輯
使用pam_start()函數指定配置文件的文件名之后,就應該在/etc/pam.d/目錄下創建對應的配置文件,並按照第一部分“Pam的配置文件”中的講解編輯配置文件並保存,即可,不需要重啟什么服務。