7

I'm not sure if this is a stackoverflow question or serverfault but here goes:

I have an Ubuntu 10.04 file server (Samba/FTP/HTTP) and I would like to have the ability to give users the ability to change their password to the server using their web browser.

I've written a similar script before using PHP and a mess of exec but I believe that isn't secure because it can be listened to by someone looking at the list of processes on the server.

Is there some kind of plugin (PHP or Python or other) that can do this easily?

I rather not use something like webmin/usermin as it's overkill for this.

4

5 Answers 5

4

web-chpass can change passwords through PAM.

2
  • This looked very promising, but I don't really know how to use Perl-CGI and it looks a bit dated.
    – wag2639
    Jun 18, 2010 at 7:54
  • @wag2639: I don't think "dated" is a problem; the PAM interface is still the same. Jun 18, 2010 at 11:10
2

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

1

If you are running Samba as a PDC you could use it to allow users to change their password using ctrl+alt+delete. I am sorry if the this anwser does not suit you but i cannot post commets or so yet...

    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

or the system program:

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*

search for "Password Synchronization" it is by the middle of the document and explains better how it works: http://www.samba.org/samba/docs/using_samba/ch09.html#samba2-CHP-9-SECT-4.3

1

Probably the best solution would be to use some kind of LDAP interface (eg. from the programming framework), or out of the box frontend, like Webmin.

1
  • I wanted to use usermin, but it wouldn't work and I don't know how to diagnose. Are there any alternatives?
    – wag2639
    Jun 18, 2010 at 3:23
0

After hours of research online, I wasn't able to find a super good option so I'm implemented this hack. It uses this article for changing passwords using PHP.

I'm also using the PECL:PAM package to add a little verification.

This page is on a secure HTTPS folder (automatic redirect via .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>

I also have this question/answer posted in https://stackoverflow.com/questions/3032785/php-pam-to-change-user-password/3067974#3067974

Not the answer you're looking for? Browse other questions tagged .