使用者資料庫會將登入名稱與數值使用者 ID 映射至帳戶記錄。/etc/passwd 是常見表示法,但應用程式不得假設檔案是權威來源。glibc 透過 Name Service Switch(NSS)解析 passwd 資料庫,而 /etc/nsswitch.conf 中的 passwd: 項目可以查詢本機檔案、systemd、LDAP、NIS 或其他已安裝提供者。
PAM 不會執行這些查詢。PAM 處理驗證與帳戶管理原則,而 NSS 回答身分資料庫查詢。
帳戶記錄 #
<pwd.h> 定義公開記錄:
struct passwd {
char *pw_name; /* login name */
char *pw_passwd; /* password field, commonly "x" */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* primary group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* login shell */
};在一般 Linux 安裝中,歷史上的密碼欄位不再公開可重複使用的密碼雜湊。雜湊會保存在受另外保護的 shadow 資料庫中;公開的 passwd 記錄通常包含 x 或其他標記。
查詢使用者 #
兩個函數會執行索引查詢:
#include <pwd.h>
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);getpwnam() 依登入名稱搜尋,而 getpwuid() 依數值 UID 搜尋。成功時兩者都會回傳指向函式庫管理儲存空間的指標。後續的密碼資料庫呼叫可能覆寫該儲存空間,應用程式不得釋放它。NULL 可能代表「找不到」或錯誤,因此在呼叫前將 errno 設為零,並在需要區分時於呼叫後檢查它。
NSS 定義查詢語意。請求可能造成本機檔案存取、IPC 或網路流量,而 NSS 原則可以在每個提供者結果後停止或繼續。因此,直接剖析 /etc/passwd 不等同於呼叫這些介面。
使用可重入介面 #
多執行緒程式碼應使用 getpwnam_r() 與 getpwuid_r(),因為它們會將字串放入呼叫者提供的儲存空間:
struct passwd pwd;
struct passwd *result;
char *buf = malloc(buflen);
int error = getpwnam_r("build", &pwd, buf, buflen, &result);
if (error != 0) {
/* error is an error number; ERANGE means the buffer was too small */
} else if (result == NULL) {
/* no matching account */
} else {
printf("%s has UID %ju\n", pwd.pw_name, (uintmax_t)pwd.pw_uid);
}查詢完成時函數回傳零,包括找不到的情況。成功時 *result 指向所提供的 struct passwd,沒有相符記錄時則為 NULL。正的錯誤號碼會直接回報失敗,而不是透過回傳值 -1。若字元緩衝區無法容納所有被參照的字串,函數會回傳 ERANGE;請增加緩衝區後重試。sysconf() 的 _SC_GETPW_R_SIZE_MAX 是初始大小提示;回傳 -1 時,它不是保證的上限。
pwd 內的回傳指標都指向 buf 內部,因此使用記錄期間兩個物件都必須保持存活。可重入性保護函式庫儲存空間;它不會使 NSS 提供者的外部資料庫不可變,也不會使一連串獨立查詢具備原子性。
列舉資料庫 #
串流風格 API 會按照已設定提供者公開的順序造訪帳戶記錄:
setpwent();
struct passwd *entry;
while ((entry = getpwent()) != NULL)
printf("%s\n", entry->pw_name);
endpwent();setpwent()會倒回列舉位置,並可能開啟提供者資源。getpwent()使用共用的內部儲存空間回傳下一個項目。endpwent()關閉列舉資源。
這些函數維護程序全域的列舉狀態,多個執行緒並行使用時並不安全。getpwent_r() 提供由呼叫者擁有的記錄與字串緩衝區,但列舉仍具有共用串流狀態;glibc 將 setpwent()、getpwent_r() 與 endpwent() 分類為:另一個執行緒操作該狀態時不安全。若其他執行緒可能同時列舉,請將完整列舉序列化。
對由網路支援的目錄而言,列舉也可能不完整或成本高昂。應用程式需要單一身分時,請使用索引查詢,不要將完整掃描視為穩定快照。
評論
在 GitHub 上閱讀或評論(發表評論需要登入)