Change Linux or UNIX system password using PHP script

If you just wanted to change your own password or other user passwords use passwd command.

Advertisement

I was asked to setup a PHP based interface to change the password. Since my knowledge of php is limited. Here is what I did:

Warning: This is an outdated and insecure information. Please see the official php.net document for more information. You have been warned to ignore this post.

Required tools/setup:

You must have following tools/software installed

=> Shell script to change password

=> Sudo access

=> Apache or Lighttpd web server

=> PHP server side

Step # 1: Setup a shell script to change password

This shell script use expect tool to change the password (see more about expect tool here).

Sample shell script code

#!/bin/sh
# \
exec expect -f "$0" ${1+"$@"}
set password [lindex $argv 1]
spawn passwd [lindex $argv 0]
sleep 1
expect "assword:"
send "$password\r"
expect "assword:"
send "$password\r"
expect eof

You can execute this script as follows (dowload link):
$ chpasswd username password

Download script and copy to your webroot or location where webserver can read this script file:
$ cp chpasswd /var/www/

ALTERNATIVELY, if you are using Ligtttpd web server:
$ cp chpasswd /home/lighttpd

Step # 2: Setup sudo to execute a command as root user

Apache or Lighttpd web server drops root privileges as soon as they go into background. This makes changing password scenario difficult as passwd command needs root privileges to change other user account password.

Typically, Apache 2 use www-data user and Lighttpd use lighttppd username to drop privileges. Login as root user and type the following command:
# visudo

Now allow your web server to execute a script (chpasswd) w/o password. If you are using Apache web server, type the following command:
www-data ALL=NOPASSWD: /var/www/chpasswd

ALTERNATIVELY, if you are using Ligtttpd web server, type the following command:
lighttpd ALL=NOPASSWD: /home/lighttpd/chpasswd

Save and close the file.

Step # 3: Create a PHP based interface

Now you need to write a php script. Here is sample php script. This is a demo script. You should modify it according to your requirement or setup. At minimum, you need to setup correct shell script location so that it will work for you out of box. Open php script and locate line:
$shellscript = "sudo /home/lighttpd/chpasswd";

Change it to point to correct location. PHP Source code:

<?php
// change .. me! - shell script name
$shellscript = "sudo /home/lighttpd/chpasswd";
 
// Make sure form is submitted by user
if(!(isset($_POST['pwdchange']))) {
 // if not display them form
 writeHead("Change password");
 writeForm();
 writeFoot();
}
else {
 // try to change the password
 $callshell=true;
 // get username and password
 $_POST['username'] = stripslashes(trim($_POST['username']));
 $_POST['passwd'] = stripslashes(trim($_POST['passwd']));
 
// if user skip our javascript ...
// make sure we can only change password if we have both username and password
 if(empty($_POST['username'])) {
   $callshell=false;
 }
 if(empty($_POST['passwd'])) {
   $callshell=false;
 }
 if ( $callshell == true ) {
  // command to change password
  $cmd="$shellscript " . $_POST['username'] . " " . $_POST['passwd'];
  // call command
  // $cmd - command, $output - output of $cmd, $status - useful to find if command failed or not
   exec($cmd,$output,$status);
   if ( $status == 0 ) { // Success - password changed
   writeHead("Password changed");
   echo '<h3>Password changed</h3>Setup a new password';
   writeFoot();
   }
   else { // Password failed
      writeHead("Password change failed");
      echo '<h3>Password change failed</h3>';
      echo '<p>System returned following information:</p>';
      print_r($output);
      echo '<p><em>Please contact tech-support for more info! Or try <a href='.$_SERVER['PHP_SELF'].'again</a></em></p>';
      writeFoot();
   }
 }
 else {
   writeHead("Something was wrong -- Please try again");
   echo 'Error - Please enter username and password';
   writeForm();
   writeFoot();
 }
}
 
// display html head
function writeHead($title) {
echo '
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> ' .$title. '</title>
<style type="text/css" media="screen">
.passwdform {
	position: static;
	overflow: hidden;
}
 
.passwdleft {
	width: 25%;
	text-align: right;
	clear: both;
	float: left;
	display: inline;
	padding: 4px;
	margin: 5px 0;
}
 
.passwdright {
	width: 70%;
	text-align: left;
	float: right;
	display: inline;
	padding: 4px;
	margin: 5px 0;
}
 
.passwderror {
	border: 1px solid #ff0000;
}
 
.passwdsubmit {
}
</style>
 
</head>
 
<body>';
 
}
// display html form
function writeForm() {
echo '
<h3>Use following form to change password:</h3>
 
<script>
function checkForm() {
if (document.forms.changepassword.elements[\'username\'].value.length == 0) {
    alert(\'Please enter a value for the "User name" field\');
    return false;
}
if (document.forms.changepassword.elements[\'passwd\'].value.length == 0) {
    alert(\'Please enter a value for the "Password" field\');
    return false;
}
  return true;
}
</script>
 
<div class="contactform">
<form action="' . $_SERVER[PHP_SELF]. '" method="post" onSubmit="return checkForm()" name="changepassword">
<div class="passwdleft"><label for="lblusername">User Name: </label></div>
<div class="passwdright"><input type="text" name="username" id="lblusername" size="30" maxlength="50" value="" /> (required)</div>
<div class="passwdleft"><label for="lblpasswd">Password: </label></div>
<div class="passwdright"><input type="password" name="passwd" id="lblpasswd" size="30" maxlength="50" value="" /> (required)</div>
<div class="passwdright"><input type="submit" name="Submit" value="Change password" id="passwdsubmit" />
<input type="hidden" name="pwdchange" value="process" /></div>
</form>
</div>
';
 
}
// display footer
function writeFoot(){
echo '</body>
</html>
';
}
?>

Step # 4: Run the script

Point a web browser to your server url – https://mydomain.com/changepassword.php. You should see a username and password form as follows:

changepassword php script output # 1

If a password is changed successfully, you should get confirmation as follows:

changepassword php script output # 2

For some reason if a password failed to change, you should get detailed error message as follows:

changepassword php script output # 3

Step # 5: Security

Note this is an example and not final solution as it is little insecure.

  • Never ever run this script over http session. Always run over https session.
  • Put script in a password protected directory (see how to setup Apache or Lighttpd web server password protected directory).
  • Never ever, trust user input. Above php script is just a sample, for real life production you should consider more powerful user input validation. Discussion regarding PHP programming security is beyond the scope of this article. You can consult a good PHP book or search a web using your favorite search engine 🙂

🥺 Was this helpful? Please add a comment to show your appreciation or feedback.

nixCrat Tux Pixel Penguin
Hi! 🤠
I'm Vivek Gite, and I write about Linux, macOS, Unix, IT, programming, infosec, and open source. Subscribe to my RSS feed or email newsletter for updates.

74 comments… add one
  • tom Jan 13, 2010 @ 11:52

    Apache error_log says password

    any help ?

  • Aurangzeb Feb 2, 2010 @ 9:51

    A unix sofrware is copied and installed on another hard drive but during booting it is protected, how to unprotect?

  • an0nym0us Apr 26, 2010 @ 20:48

    Thank you.

    One note for CentOS/RHEL users is that ‘requiretty’ is enabled by default in the sudoers file. To get around this add:

    Defaults:www-data !requiretty

    before the “www-data ALL=NOPASSWD: /var/www/chpasswd” line. Obviously you’ll need substitute the name of the user that the webserver runs under if it isn’t www-data (in CentOS it seems to be ‘apache’ by default).

    Thanks again!

  • an0nym0us Apr 26, 2010 @ 21:31

    @Terry

    That’s a nice little function but it looks like it only works for users who have shell access. For instance, it looks like it won’t work for users with /sbin/nologin as a shell, such as is typical for FTP users.

  • Ashish May 27, 2010 @ 13:23

    Hi;

    Thanks for this script. It worked for me on Solaris 10.

    regards;
    Ashish

  • Akash Jul 11, 2010 @ 15:36

    Hi; i m having problem with my php installation in linux on my pc. Whenever i try to start the service of php, it throws an error “service failed”. but it installs without any error if I connect my hard disk to someone else’s computer. can anyone has solution for this problem?????

  • Chris Jul 27, 2010 @ 12:33

    The file in /tmp will contain the password briefly, allowing an attack vector. How about an interactive ssh shell through php?

    [code]

    Password Update Utility

    Username

    Current Password

    New Password

    Confirm New Password

    <?php

    if ($_POST['submitChangePassword'])
    {
    $error = "0";
    # Die on root user
    if ($_POST['username'] == 'root')
    {
    echo ('Authentication Failed');
    }
    else
    {
    # Connect and reset password
    $connection = ssh2_connect($targetHost, $targetPort);

    if (!ssh2_auth_password($connection, $_POST['username'], $_POST['OldPassword']))
    {
    echo ('Authentication Failed');
    }
    else
    {
    $out = '';
    $last_line = '';
    $cmds[0] = "passwd";
    $cmds[1] = $_POST['OldPassword'];
    $cmds[2] = $_POST['NewPassword'];
    $cmds[3] = $_POST['NewPassword2'];
    $shell = ssh2_shell($connection);

    for($i=0; $i

    [/code]

  • Rick Nov 13, 2010 @ 2:46

    Or you could just do the hash right in PHP using crypt, and then change the password in one command using perl:
    usermod -p `perl -e ‘print crypt(“password”, “user”)’` user

    Here’s an example of a PHP script to do it. This is part of a CGI I wrote. This is NOT how the actual CGI works. I stripped out the GET and PUT methods for clarity’s sake. Also, the real CGI doesn’t have root access. Instead, it communicates with another process that does. That combined with the fact that this script validates the current user and password makes it more secure.

    Please do not grant CGI access to a script based on this example and place it on a Web site.

     "peter", "old" => "oldpassword", "new" => "newpassword");
    
        // Get the old password and new password
        $user = $data["user"];
        $old = $data["old"];
        $new = $data["new"];
    	// Get the current password hash to compare
    	// Read the file and return the data
    	$old_hash = @file_get_contents($pw_path);
    	if (!$old_hash)	// Couldn't access the file
        {
            printf("Cannot read password file: ".$pw_path."n");
            return;
        }
        // Parse out the hash
        $old_hash = strstr($old_hash, $user);
    	if (!$old_hash) // The user doesn't exist
        {
            printf("No user named ".$user." in ".$pw_path."n");
            return;
    	}
        // Get everything in front of the next ccarriage return
        $old_hash2 = strstr($old_hash, "n", TRUE);
        // If it's the last line, that's ok too
        if (!$old_hash2)
            $old_hash2 = $old_hash;
        $old_hash = trim($old_hash2);
        // Could use explode, but this is just as easy
        $old_hash = strstr($old_hash, ":");
        $old_hash = substr($old_hash, 1);
        // PHP's crypt guesses the encryption alogrithm based on the "salt"
        // Linux passwords typically use MD5, so we'll just use the old hash.
        // Apache's htpasswd, for example, typically uses DES, so we would use
        // just the first to characters; $salt = substr($old_hash, 0, 2);
        $salt = $old_hash;
        // Now get a hash to match the existing password
        $new_hash = crypt($old, $salt);
        if ($new_hash != $old_hash)
        {
            printf("The entered password doesn't match the current passwordn");
            return;
        }
        // Now change new passwords
    	$command = sprintf($change_script, $new, $new, $new);
        $output = ExecuteCommand($command);
    
    	// Now send the result
        printf($output."n");
    
    ?>
  • Rick Nov 13, 2010 @ 2:47

    Sorry, that previous code listing was a bad cut and paste:

     "peter", "old" => "oldpassword", "new" => "newpassword");
    
        // Get the old password and new password
        $user = $data["user"];
        $old = $data["old"];
        $new = $data["new"];
    	// Get the current password hash to compare
    	// Read the file and return the data
    	$old_hash = @file_get_contents($pw_path);
    	if (!$old_hash)	// Couldn't access the file
        {
            printf("Cannot read password file: ".$pw_path."n");
            return;
        }
        // Parse out the hash
        $old_hash = strstr($old_hash, $user);
    	if (!$old_hash) // The user doesn't exist
        {
            printf("No user named ".$user." in ".$pw_path."n");
            return;
    	}
        // Get everything in front of the next ccarriage return
        $old_hash2 = strstr($old_hash, "n", TRUE);
        // If it's the last line, that's ok too
        if (!$old_hash2)
            $old_hash2 = $old_hash;
        $old_hash = trim($old_hash2);
        // Could use explode, but this is just as easy
        $old_hash = strstr($old_hash, ":");
        $old_hash = substr($old_hash, 1);
        // PHP's crypt guesses the encryption alogrithm based on the "salt"
        // Linux passwords typically use MD5, so we'll just use the old hash.
        // Apache's htpasswd, for example, typically uses DES, so we would use
        // just the first to characters; $salt = substr($old_hash, 0, 2);
        $salt = $old_hash;
        // Now get a hash to match the existing password
        $new_hash = crypt($old, $salt);
        if ($new_hash != $old_hash)
        {
            printf("The entered password doesn't match the current passwordn");
            return;
        }
        // Now change new passwords
    	$command = sprintf($change_script, $new, $new, $new);
        $output = ExecuteCommand($command);
    
    	// Now send the result
        printf($output."n");
    
    ?>
  • Killzone 3 Feb 27, 2011 @ 8:37

    Hi I try run PHP login to my shell script and show results on wep page is work but my server must install PHP my admin

  • karthik Jun 6, 2011 @ 12:13

    Hi
    i am getting the below error when i tested the script in command line.
    i have chmod 755 chpasswd.sh
    error message …..
    exec: 3: expect: not found
    Kindly advice

Leave a Reply

Your email address will not be published. Required fields are marked *

Use HTML <pre>...</pre> for code samples. Your comment will appear only after approval by the site admin.