6

I have a "simple" question: How can I securely change a user's password from within a PHP script, without granting Apache root privileges or introducing other crazy security holes?

Background: CentOS 6, Apache 2.2.13, PHP 5.3.3

I am aware of the pam_chpasswd() command, which is part of the PECL PAM library. However, this function fails unless the host process (httpd) has read access to the /etc/shadow file. (BAD IDEA! Not sure how this library helps if it requires such high privileges...)

The ideal situation, as far as I can see, is to have PHP call a shell script with 'sudo -u[username of user changing his password]' This would run the script "AS" the user, so he should have permission to change his own password. And sudo would require that the user send along his existing password in order to be authenticated, thus preventing one user from changing another user's password.

But this doesn't work for some reason... when opening the process with popen, the process never executes. I have the shell script set up to dump some text into a publicly writable file in /tmp. But it never gets to that point.

$cmd = "/usr/bin/sudo -S -u$username /file_to_execute.sh";
$handle = popen ($cmd, "w");   // Open the process for writing
fwrite ($handle, "$current_password\n");  // Send the user's current password to sudo (-S option)
fwrite  .... (write the username, current password, and new password, so the script can change it)
$result = pclose($handle);

If I access this php script (http://server/script.php), the function immediately fails, and $result = 1

If I modify the sudoers file (visudo) and add a line:
$Defaults:apache !requiretty

The script freezes for about 10 seconds, then fails ($result = 1)

Any suggestions for doing this are greatly appreciated!

Ryan Griggs
  • 2,457
  • 2
  • 35
  • 58
  • Any of these work? http://stackoverflow.com/questions/127459/using-shell-execpasswd-to-change-a-users-password?rq=1 – aknosis Jul 24 '12 at 16:34

2 Answers2

2

To achieve the above with security in mind, I would suggest either the use of expect or adding the Apche user to a group who has write access to said file and only said file.

With expect, you will need to include your sudo password, as it will listen for the response from the OS of Password:, and when seen, it automatically replies with the sudo password. This would allow you to team up shell_exec() and family with expect to achieve your results.

I would go the second route for security, which would use a group permission to write to the file for a group which only has write access to that file.

Example:

groupadd secure_apache
usermod -G secure_apache apache_user
chown owner:secure_apache /tmp/file_to_change
chmod 740 /tmp/file_to_change
Mike Mackintosh
  • 13,917
  • 6
  • 60
  • 87
  • Will #2 work in a multi-user environment? i.e. several users try to change their passwords simultaneously? I assume each password-change request would have to create a randomly-named file to prevent users stepping on each other during the process...? – Ryan Griggs Jul 24 '12 at 17:59
  • 1
    If you go with the second option, you can implement a `flock()` to lock the file when the first user tries. WHen they are completed, remove the `flock()` and the other users can go. Atleast the other users will get an error saying unable at this time. – Mike Mackintosh Jul 24 '12 at 18:02
  • I have never had luck with `popen` accessing the `STDIN` from sudo. Take a look at this though.. http://stackoverflow.com/questions/127459/using-shell-execpasswd-to-change-a-users-password – Mike Mackintosh Jul 24 '12 at 18:19
0

A more secure way to do this is to store username and password in a file in a special directory and let cron do the job (once per minute)

Ron
  • 1,336
  • 12
  • 20
  • Thanks for your answer. However, this introduces 2 problems: 1) The user can't get immediate feedback on whether his password was changed. 2) The user's existing password is not verified. Seems like this may not be too secure. I want the user to be required to give his existing password in order to change the password. This prevents any type of hijacking by one user to change another user's password. – Ryan Griggs Jul 24 '12 at 16:33