PHP/PAM更改用户密码?

问题描述:

是否有任何工作包使用PHP更改linux用户密码?PHP/PAM更改用户密码?

我试过使用PECL:PAM,但当它尝试更改密码时发生错误。

编辑:

PHP代码:

echo pam_chpass($username, $password, $new_pass, &$error) ? 'good' : $error; 

PHP(回波)输出:

Permission denied (in pam_authenticate) 

在/ var /日志/ AUTH(这些是实际从之前,日志没有按“T似乎工作ATM出于某种原因尚未确定):

Jun 11 15:30:20 veda php: pam_unix(php:chauthtok): conversation failed 
Jun 11 15:30:20 veda php: pam_unix(php:chauthtok): password - (old) token not obtained 
Jun 11 15:30:20 veda php: pam_winbind(php:chauthtok): valid_user: wbcGetpwnam gave WBC_ERR_DOMAIN_NOT_FOUND 

其他:

对不起,以前缺乏细节,当我发布这个问题时,我真的很累,但那仍然是一个糟糕的借口。

+0

“那里有一个错误,当它试图更改密码“ - 什么错误?你刚刚去了医生办公室,告诉他“疼,”但不会告诉他在哪里。 – Charles 2010-06-13 20:54:24

afte在线研究小时,我无法找到一个超好的选择,所以我实施了这个黑客攻击。它使用this article来更改使用PHP的密码。

我还使用了PECL:PAM package增添了几分验证。

这页是安全的HTTPS文件夹(通过自动的.htaccess重定向)

<?php 

$messages = array(); 

function change_password ($user, $currpwd, $newpwd) { 

    // Open a handle to expect in write mode 
    $p = popen('/usr/bin/expect','w'); 

    // Log conversation for verification 
    $log = '/tmp/passwd_' . md5($user . time()); 
    $cmd .= "log_file -a \"$log\"; "; 

    // Spawn a shell as $user 
    $cmd .= "spawn /bin/su $user; "; 
    $cmd .= "expect \"Password:\"; "; 
    $cmd .= "send \"$currpwd\\r\"; "; 
    $cmd .= "expect \"[email protected]\"; "; 

    // Change the unix password 
    $cmd .= "send \"/usr/bin/passwd\\r\"; "; 
    $cmd .= "expect \"(current) UNIX password:\"; "; 
    $cmd .= "send \"$currpwd\\r\"; "; 
    $cmd .= "expect \"Enter new UNIX password:\"; "; 
    $cmd .= "send \"$newpwd\\r\"; "; 
    $cmd .= "expect \"Retype new UNIX password:\"; "; 
    $cmd .= "send \"$newpwd\\r\"; "; 
    $cmd .= "expect \"passwd: password updated successfully\"; "; 

    // Commit the command to expect & close 
    fwrite($p, $cmd); pclose ($p); 

    // Read & delete the log 
    $fp = fopen($log,r); 
    $output = fread($fp, 2048); 
    fclose($fp); unlink($log); 
    $output = explode("\n",$output); 

    return (trim($output[count($output)-2]) == 'passwd: password updated successfully') ? true : false; 
} 

function process_post() { 

    if ((!isset($_SERVER['HTTP_REFERER'])) 
     || (strpos($_SERVER['HTTP_REFERER'], $_SERVER['SCRIPT_NAME']) === FALSE)) { 

     echo "GO AWAY!"; 
     exit(); 
     return FALSE; 

    } 

    global $messages; 

    $username   = trim($_POST['username']); 
    $password_current = trim($_POST['password_current']); 
    $password_new  = trim($_POST['password_new']); 
    $password_confirm = trim($_POST['password_confirm']); 

    // Check for blanks 
    if ($username == '' || $password_current == '' || $password_new == '' || $password_confirm == '') { 
     array_push(&$messages, "ERROR: You cannot leave any field empty."); 
     return FALSE; 
    } 

    // Check username 
    if (!ctype_alnum($username)) { 
     array_push(&$messages, "ERROR: You've entered an invalid username."); 
     return FALSE; 
    } 

    // Check to see if new password is correctly typed 
    if ($password_new != $password_confirm) {  
     array_push(&$messages, "ERROR: New Password and Confirmation do not match."); 
     return FALSE; 
    } 

    // Check if current password is valid (not really neccessary) 
    if (!pam_auth($username, $password_current, &$error, FALSE)) { 
     if (trim($error) == "Permission denied (in pam_authenticate)") 
      array_push(&$messages, "ERROR: You've username/password was not accepted.");  
     else 
      array_push(&$messages, "ERROR: " . $error); 
     return FALSE; 
    } 

    if (change_password ($username, $password_current, $password_new)) 
     array_push(&$messages, "Password Successfully Changed"); 
    else 
     array_push(&$messages, "ERROR: Password change failed."); 

} 

if ($_SERVER['REQUEST_METHOD'] == 'POST') process_post(); 


?><html> 
<head> 


<title>Passwords</title> 

<style type="text/css"> 

body { 
    font-family: Verdana, Arial, sans-serif; 
    font-size: 12px; 
} 

label { 
    width: 150px; 
    display: block; 
    float: left; 
} 

input { 
    float: left; 
} 

br { 
    clear: both; 
} 

.message { 
    font-size: 11px; 
    font-weight: bold; 
} 

.error { 
    color:#C00; 
} 


</style> 

</head> 


<body> 

<h2>Change Passwords</h2> 

<form action="<?= $_SERVER['SCRIPT_NAME'] ?>" method="post"> 

<fieldset> 

<? if (count($messages) != 0) { 

    foreach ($messages as $message) { ?> 

<p class="message<?= ((strpos($message, 'ERROR:') === FALSE) ? '' : ' error') ?>"><?= $message ?></p> 

<? } } ?> 

<label>Username: </label> 
<input type="text" name="username" /><br /> 

<label>Current Password:</label> 
<input type="password" name="password_current" /><br /> 

<label>New Password:</label> 
<input type="password" name="password_new" /><br /> 

<label>Confirm Password:</label> 
<input type="password" name="password_confirm" /><br /> 

<input type="reset" value="Reset" /> <input type="submit" value="Submit" /> 

</fieldset> 


</form> 


</body> 
</html> 

我也有这个问题/答案张贴在https://serverfault.com/questions/150306/how-to-let-users-change-linux-password-from-web-browser/152409#152409

+0

请仔细阅读下面的注释,以便能够正确配置PAM,并处理尝试运行上述代码时可能遇到的所有问题。 – 2011-03-02 07:41:49

+2

这两个版本的脚本都要求要更改密码的用户拥有有效的shell。由于使用'su'脚本不适用于具有禁用shell的用户。 – xebeche 2013-11-20 22:08:27

是否有任何工作包改变了使用PHP的Linux用户的密码?

这是真的,真的很危险。假设你了解风险,那么你会意识到,在应用必须在允许更改密码的权限级别中实现的更改之前,您需要构建一些约束 - 即运行此代码的代码必须是独立的可执行文件无论是setuid executoin还是通过你的php代码通过sudo调用。

当然,没有理由不能用PHP编写独立的代码,除了(至少,最后一次看这个)PHP中的PAM绑定的事实还不成熟,

你可能想看看chpasswd的程序(可在红帽和其他一些发行版),或使用proc_open(“的/ usr/bin中/ passwd文件” ......和阅读并提示正确响应。

HTH

C.

+0

我在找东西,以便用户可以更改自己的密码。它不会使用自己的用户权限来尝试登录和密码更改吗? – wag2639 2010-06-14 03:26:12

+0

Erk!如果你不明白为什么这不起作用,那么你可能不应该搞砸它,除非你已经阅读了更多关于认证和许可如何在posix系统上工作的内容。而且您不得允许基于Web的表单更改密码所需的权限。编写webmin的人是有能力的程序员 - 他们错误地多次错了。只有root可以改变他人的密码。要更改自己的密码,它仍然需要以root身份启动,然后seteuid()。 – symcbean 2010-06-14 10:33:23

+0

然后我想我会用proc_open去。我只是减少了一个更好的检查。 – wag2639 2010-06-15 02:43:50

你可以使用RSBAC密码。

$ret = system("echo \"newpass newpass\" | rsbac_password -n"); 

if ($ret) 
    echo "fail."; 
else 
    echo "done!"; 

这么容易多了。

除了张贴wag2369答案,一定要执行以下操作:

安装梨是PHP的扩展管理器:

yum install pear 

从百胜

安装PAM-devel的
yum install pam-devel 

安装PHP扩展PAM

pecl install --alldeps PAM 

--alldeps:指自动安装所有的依赖

修改文件/etc/php.ini并输入以下内容:

extension=pam.so 
pam.servicename="php" 

执行以下操作以允许PAM PHP服务:

cd /etc/pam.d 
ln -s login /etc/pam.d/php 

重新启动Apache :

/etc/init.d/httpd restart 

/etc/shadow文件应该是可读的(这是一个安全漏洞,反思请)

chmod g+r,o+r /etc/shadow 

安装预计如果尚未安装

yum install expect 

修复发表wag2369或只是在代码中的bug复制下面的修改后的代码: '不应使用'passwd:password updated successfully',使用 'passwd:更新所有认证令牌成功“。而不是检查。

<?php 
$messages = array(); 

function change_password ($user, $currpwd, $newpwd) { 

    // Open a handle to expect in write mode 
    $p = popen('/usr/bin/expect','w'); 

    // Log conversation for verification 
    $log = '/tmp/passwd_' . md5($user . time()); 
    $cmd = ""; 
    $cmd .= "log_file -a \"$log\"; "; 

    // Spawn a shell as $user 
    $cmd .= "spawn /bin/su $user; "; 
    $cmd .= "expect \"Password:\"; "; 
    $cmd .= "send \"$currpwd\\r\"; "; 
    $cmd .= "expect \"[email protected]\"; "; 

    // Change the unix password 
    $cmd .= "send \"/usr/bin/passwd\\r\"; "; 
    $cmd .= "expect \"(current) UNIX password:\"; "; 
    $cmd .= "send \"$currpwd\\r\"; "; 
    $cmd .= "expect \"Enter new UNIX password:\"; "; 
    $cmd .= "send \"$newpwd\\r\"; "; 
    $cmd .= "expect \"Retype new UNIX password:\"; "; 
    $cmd .= "send \"$newpwd\\r\"; "; 
    $cmd .= "expect \"passwd: all authentication tokens updated successfully.\"; "; 

    // Commit the command to expect & close 
    fwrite($p, $cmd); pclose ($p); 

    // Read & delete the log 
    $fp = fopen($log,'r'); 
    $output = fread($fp, 2048); 
    fclose($fp); unlink($log); 
    $output = explode("\n",$output); 

    return (trim($output[count($output)-2]) == 'passwd: all authentication tokens updated successfully.') ? true : false; 
} 

function process_post() { 

    if ((!isset($_SERVER['HTTP_REFERER'])) 
     || (strpos($_SERVER['HTTP_REFERER'], $_SERVER['SCRIPT_NAME']) === FALSE)) { 

     echo "GO AWAY!"; 
     exit(); 
     return FALSE; 

    } 

    global $messages; 

    $username   = trim($_POST['username']); 
    $password_current = trim($_POST['password_current']); 
    $password_new  = trim($_POST['password_new']); 
    $password_confirm = trim($_POST['password_confirm']); 

    // Check for blanks 
    if ($username == '' || $password_current == '' || $password_new == '' || $password_confirm == '') { 
     array_push($messages, "ERROR: You cannot leave any field empty."); 
     return FALSE; 
    } 

    // Check username 
    if (!ctype_alnum($username)) { 
     array_push($messages, "ERROR: You've entered an invalid username."); 
     return FALSE; 
    } 

    // Check to see if new password is correctly typed 
    if ($password_new != $password_confirm) {  
     array_push($messages, "ERROR: New Password and Confirmation do not match."); 
     return FALSE; 
    } 

    // Check if current password is valid (not really neccessary) 
    $error = ''; 
    if (!pam_auth($username, $password_current, $error, FALSE)) { 
     if (trim($error) == "Permission denied (in pam_authenticate)") 
      array_push($messages, "ERROR: Your username/password was not accepted.");  
     else 
      array_push($messages, "ERROR: " . $error); 
     return FALSE; 
    } 

    if (change_password ($username, $password_current, $password_new)) 
     array_push($messages, "Password Successfully Changed"); 
    else 
     array_push($messages, "ERROR: Password change failed."); 

} 

if ($_SERVER['REQUEST_METHOD'] == 'POST') process_post(); 


?><html> 
<head> 


<title>Passwords</title> 

<style type="text/css"> 

body { 
    font-family: Verdana, Arial, sans-serif; 
    font-size: 12px; 
} 

label { 
    width: 150px; 
    display: block; 
    float: left; 
} 

input { 
    float: left; 
} 

br { 
    clear: both; 
} 

.message { 
    font-size: 11px; 
    font-weight: bold; 
} 

.error { 
    color:#C00; 
} 


</style> 

</head> 


<body> 

<h2>Change Passwords</h2> 

<form action="<?= $_SERVER['SCRIPT_NAME'] ?>" method="post"> 

<fieldset> 

<? if (count($messages) != 0) { 

    foreach ($messages as $message) { ?> 

<p class="message<?= ((strpos($message, 'ERROR:') === FALSE) ? '' : ' error') ?>"><?= $message ?></p> 

<? } } ?> 

<label>Username: </label> 
<input type="text" name="username" value="halaluya" /><br /> 

<label>Current Password:</label> 
<input type="password" name="password_current" value="[email protected]" /><br /> 

<label>New Password:</label> 
<input type="password" name="password_new" value="123" /><br /> 

<label>Confirm Password:</label> 
<input type="password" name="password_confirm" value="123" /><br /> 

<input type="reset" value="Reset" /> <input type="submit" value="Submit" /> 

</fieldset> 


</form> 


</body> 
</html> 
+0

对于php.ini设置和chmod,这篇文章是我在互联网上搜索过的最详细的文章。 – 2017-05-11 10:13:18

直接从PHP更改PAM密码需要多次访问您的系统文件和服务。这是因为PAM默认使用pam_unix模块,该模块将用户凭证存储在由root拥有的系统文件中。解决此问题的一个好方法是设置PAM以使用pam_ldap模块。这种PAM方式使用LDAP服务器对用户进行身份验证。然后从PHP中,您可以使用用户凭据绑定到LDAP服务器并更改密码。授权这种修改将由LDAP授权机制来处理。 (您的应用程序还应该执行授权规则,以提供分层的安全性)

上述配置不是微不足道的。您必须先设置LDAP服务器,然后将所有用户数据从系统文件(passwd,shadow)迁移到LDAP目录。 (有自动化工具)。最后,您必须安装并设置pam_ldap模块。上述过程中的任何错误配置都可能导致严重的安全问题。

请注意,通过这种方式,您将通过您的应用程序将LDAP服务器公开到Web上。任何可能影响LDAP认证或授权机制的安全问题也会影响您的系统安全。

资源:

使用LDAP存储POSIX帐户:

http://www.ibm.com/developerworks/linux/library/l-openldap/

设置PAM使用LDAP进行身份验证:

http://wiki.debian.org/LDAP/PAM

+0

您提到有自动工具转移到LDAP。你有链接到那些? – Azmisov 2014-08-08 20:17:38