Я не уверен, что это вопрос stackoverflow или serverfault, но вот:
У меня файловый сервер Ubuntu 10.04 (Samba/FTP/HTTP), и я хотел бы иметь возможность дать пользователям возможность изменить свой пароль к серверу через веб-браузер.
Я уже писал подобный скрипт, используя PHP и набор exec, но я считаю, что это небезопасно, потому что его может прослушать кто-то, просматривая список процессов на сервере.
Есть ли какой-нибудь плагин (PHP или Python или другой), который может сделать это легко?
Я предпочитаю не использовать что-то вроде webmin/usermin, так как это слишком сложно для этого.
После часов исследования онлайн, я не смог найти супер хороший вариант, таким образом, я реализован этот взлом. Это использует эту статью для изменения паролей с помощью 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://stackoverflow.com/questions/3032785/php-pam-to-change-user-password/3067974#3067974
При выполнении Samba как PDC, Вы могли бы использовать его, чтобы позволить пользователям изменять свой пароль с помощью ctrl+alt+delete. Я сожалею, если этот anwser не подходит Вам, но я не могу добавить комментарии или так еще...
unix password sync = Yes
passwd program = /usr/bin/php -f /my_folder/my_own_script.php %u
passwd chat = "password:" %n\n "changed"
passwd chat debug = yes
или системная программа:
passwd program = /usr/bin/passwd %u
passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
поиск "Синхронизации Пароля" это к середине документа и объясняет лучше, как это работает: http://www.samba.org/samba/docs/using_samba/ch09.html#samba2-CHP-9-SECT-4.3
Вероятно, лучшее решение состояло бы в том, чтобы использовать некоторый интерфейс LDAP (например, от платформы программирования), или из поля frontend, как Webmin.
I prefer to use 2 separate processes. One process makes a request by dropping a special file into a special folder. Second, a cron job loops through the folder and fulfills the password change requests.
All the calling script needs to do is drop the file into the folder (provided it has permissions to do so.
Please see this link for more details and to get the scripts: http://sylnsr.blogspot.com/2012/09/keep-unix-password-in-sync-with.html