在某些系統集成場景下 (如 Web 管理面板、單點登錄代理),需要驗證 Linux 系統賬號密碼。verifypasswd() 函數通過讀取 /etc/passwd (或 /etc/shadow) 中的加密哈希,使用相同鹽值加密用戶輸入密碼進行比對。
<?php
function verifypasswd($USERNAME, $PASSWORD) {
$fd = fopen("/etc/passwd", "r");
$contents = fread($fd, filesize("/etc/passwd"));
fclose($fd);
if (!$contents) return -2; // 文件讀取錯誤
$lines = explode("\n", $contents); // 修正:原代碼 split("n") 有誤
$passwd = array();
foreach ($lines as $line) {
list($user, $pass) = explode(":", $line, 2); // 僅分割第一個冒號
if ($user == $USERNAME) {
break;
}
}
if (!$user) return 0; // 用戶不存在
// 經典 DES crypt 格式:前2字符為鹽值
$cryptedpass = $pass;
$salt = substr($cryptedpass, 0, 2);
$Pass = crypt($PASSWORD, $salt);
return ($Pass == $cryptedpass) ? 1 : -1; // 1: 正確, -1: 錯誤
}
?>
/etc/passwd (世界可讀) 或 /etc/shadow (僅 root 可讀) 權限。Web 服務器通常以 www-data/apache 運行,**無法直接讀取 shadow 文件**。$5$/$6$ 開頭)、yescrypt 等,crypt() 支持這些格式,但鹽值提取邏輯需相應調整 (非固定 2 字符)。pam_auth 模塊或 PHP pam 擴展,通過系統 PAM 堆疊驗證,無需讀取密碼文件。password_hash() (bcrypt/argon2) 存儲,與系統賬號解耦。代碼修正提示:原代碼 split("n") 應為 explode("\n") 或 preg_split("/\r?\n/");split(":", ...) 應限制分割次數防止字段值含冒號報錯。