PDA

View Full Version : proc_open() & passwd binary


Foxxie
01-04-03, 07:19 PM
Hello developers,
I'm currently working on making a php script that interacts with the passwd binary to change user passwords rather then going in and manually editing the /etc/group, /etc/passwd, and /etc/shadow files with php. For some reason the script isn't working correctly and the error output I get is the following:

New password:
New password:
New password:
passwd: Conversation error

Here is the code:

#!/usr/bin/php -f
<?php

$structure = array
(
"0" => array("pipe", "r"),
"1" => array("pipe", "w"),
"2" => array("file", "/tmp/error-output.txt", "a")
);

$proc = proc_open("passwd $argv[1]", $structure, $pipes);
if(is_resource($proc))
{
$r = fread($pipes[0], 1024);

if(strstr($r, "New password:"))
{
fwrite($pipes[1], $argv[2]);
}
$r = fread($pipes[0], 1024);

if(strstr($r, "Retype new password:"))
{
fwrite($pipes[1], $argv[2]);
}
$r = fread($pipes[0], 1024);

if(strstr($r, "passwd: all authentication tokens updated successfully."))
{
print "The user $argv[1]'s password has sucessfully been changed.\n";
}
else
{
print "The user $argv[1]'s password change has failed.\n";
}

fclose($pipes[0]);
fclose($pipes[1]);
proc_close($proc);
}
?>

Does anyone have any idea why it's not working correctly? If so thanks, and your help is greatly appreciated :).

iseletsk
05-14-03, 01:25 PM
You will not be able to do it this way. passwd program picks up tty, instead of getting input from stdin. This was done specifically, so it would be "hard" to implement scripts using this command (as much as I remember thats the only reason - but maybe it also protects from stealing your input).

The only way to deal with it is through expect command or Expect module in perl.

You can also alternatively try to find pam module for perl, and do it through it.

nekton
07-22-03, 12:34 AM
i had the same problem. i'm still on changing code but my console version works very well. i'll list some important point of what's to be done and what to take care of:

- the input has to send thrue stdin without \n or \r (just fwrite($pipe, "newpass") f.e.)

- take a rest and insert some sleeps between the fwrites. i dunno how long the delay should be but i've tested with 2 sec each sleep and it works. yes it's quite slow but i'm in to find a better solution.

if anybody has aditional facts please let me know :)
here's some "quick 'n' dirty" code of my trials. the loop is not tested yet (i used to run the "new pass" sequence manualy in the tested code) but i should also work fine.


#! /usr/local/bin/php -q
<?

$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "error-output.txt", "a") // stderr is a file to write to
);

$process = proc_open("passwd $user", $descriptorspec, $pipes);

if (is_resource($process)) {
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /tmp/error-output.txt

sleep(2);
fwrite($pipes[0], "oldpass");

for($i=0;$i<=1;$i++)
{
sleep(2) ;
fwrite($pipes[0], "newpass");
}

fclose($pipes[0]);

while(!feof($pipes[1])) {
echo fgets($pipes[1], 1024);
}

fclose($pipes[1]);
}

?>




/*edit*/

i've also found a possible solution with "passwd --stdin" on google. Course this doesn't fit to my system (gentoo linux) i don't have more infos about. i just wanted post for people wich can use ;)