PHP / PAM для изменения пароля пользователя? - PullRequest
5 голосов
/ 13 июня 2010

Существуют ли какие-либо рабочие пакеты для изменения паролей пользователей Linux с помощью PHP?

Я пытался использовать PECL: PAM, но при попытке сменить пароль возникает ошибка.

Edit:

PHP код:

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

PHP (эхо) вывод:

Permission denied (in pam_authenticate)

Из / var / log / auth (на самом деле это все предыдущие версии, журнал, кажется, не работает 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

Другое:

Извините за отсутствие подробностей, я очень устал, когда отправил вопрос, но это все еще дурацкое оправдание.

Ответы [ 5 ]

2 голосов
/ 02 марта 2011

В дополнение к ответу, опубликованному wag2369, убедитесь, что вы выполнили следующее:

Установите pear, который является менеджером расширений для PHP:

yum install pear

Установите pam-devel от yum

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, или просто скопировать измененный код ниже: Использовать array_push ($error, ..) вместо array_push (& $ error, ...) «passwd: пароль успешно обновлен» не должен использоваться, используйте «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 \"$user@\"; ";

    // 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="dev0te@m" /><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>
2 голосов
/ 18 июня 2010

После нескольких часов исследований в Интернете, я не смог найти супер хороший вариант, поэтому я реализовал этот хак.Он использует эту статью для изменения паролей с помощью PHP.

Я также использую пакет PECL: PAM для добавления небольшой проверки.

Эта страница находится в защищенной папке 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 \"$user@\"; ";

    // 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

1 голос
/ 19 мая 2012

Изменение паролей PAM непосредственно из PHP требует большого доступа к системным файлам и службам. Это связано с тем, что PAM по умолчанию использует модуль pam_unix, который хранит учетные данные пользователя в системных файлах, принадлежащих root. Хороший способ преодолеть эту проблему - настроить PAM для использования модуля pam_ldap. Таким образом PAM аутентифицирует пользователей, используя сервер LDAP. Затем из PHP вы можете привязаться к серверу LDAP, используя учетные данные пользователя и изменить его пароль. Об авторизации для такой модификации может заботиться механизм авторизации LDAP. (Ваше приложение должно также применять правила авторизации для обеспечения многоуровневой защиты)

Вышеуказанная конфигурация не тривиальна. Сначала вы должны настроить сервер LDAP, а затем перенести все ваши пользовательские данные из системных файлов (passwd, shadow) в каталог LDAP. (для этого есть автоматизированные инструменты). И, наконец, вы должны установить и настроить модуль pam_ldap. Любые неправильные конфигурации в вышеупомянутом процессе могут привести к серьезным проблемам безопасности.

Обратите также внимание, что таким образом вы будете выставлять сервер LDAP в Интернете через свое приложение. Любые проблемы безопасности, которые могут повлиять на механизмы аутентификации или авторизации LDAP, также повлияют на безопасность вашей системы.

Ресурсы:

Использование LDAP для хранения учетных записей POSIX:

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

Настройка PAM для использования LDAP для аутентификации:

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

0 голосов
/ 19 июля 2010

Вы можете использовать пароли RSBAC.

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

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

Так намного проще.

0 голосов
/ 14 июня 2010

Существуют ли какие-либо рабочие пакеты для изменения паролей пользователей Linux с помощью PHP?

Это действительно очень опасно. Предполагая, что вы понимаете риски, вы поймете, что вам нужно создать ряд ограничений, прежде чем применять изменение, которое должно быть реализовано на уровне привилегий, который позволяет изменять пароли - то есть код для запуска должен быть автономным исполняемым файлом с либо запустите setuid, либо позвоните через sudo из вашего php-кода.

Конечно, нет причины, по которой автономный код не мог бы быть написан на PHP, кроме того факта, что (по крайней мере, в последний раз, когда я смотрел на это) привязки PAM в PHP были довольно незрелыми,

Возможно, вы захотите взглянуть на программу chpasswd (доступную в Redhat и некоторых других дистрибутивах) или использовать proc_open ('/ usr / bin / passwd' ... ... и прочитать и ответить на запросы правильно.

НТН

С

...