use authentication files

This commit is contained in:
Robin Appelman 2014-07-21 20:26:24 +02:00
commit d18b9db9c0
3 changed files with 28 additions and 21 deletions

View file

@ -22,19 +22,21 @@ class RawConnection {
*/
private $process;
public function __construct($command, $env = array()) {
$descriptorSpec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array('file', '/dev/null', 'w')
0 => array('pipe', 'r'), // child reads from stdin
1 => array('pipe', 'w'), // child writes to stdout
2 => array('pipe', 'w'), // child writes to stderr
3 => array('pipe', 'r'), // child reads from fd#3
4 => array('pipe', 'r'), // child reads from fd#4
5 => array('pipe', 'w') // child writes to fd#5
);
setlocale(LC_ALL, Server::LOCALE);
$env = array_merge($env, array(
'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!!
'LC_ALL' => Server::LOCALE
));
$this->process = proc_open($command, $descriptorSpec, $this->pipes, null, $env);
$this->process = proc_open($command, $descriptorSpec, $this->pipes, '/', $env);
if (!$this->isValid()) {
throw new ConnectionError();
}
@ -94,6 +96,19 @@ class RawConnection {
return $this->pipes[0];
}
public function writeAuthentication($user, $password) {
$auth = ($password === false)
? "username=$user"
: "username=$user\npassword=$password";
if (fwrite($this->pipes[3], $auth) === false) {
fclose($this->pipes[3]);
return false;
}
fclose($this->pipes[3]);
return true;
}
public function __destruct() {
proc_terminate($this->process);
proc_close($this->process);

View file

@ -81,19 +81,14 @@ class Server {
* @throws \Icewind\SMB\InvalidHostException
*/
public function listShares() {
$user = escapeshellarg($this->getUser());
$command = self::CLIENT . ' -U ' . $user . ' ' . '-gL ' . escapeshellarg($this->getHost());
$command = Server::CLIENT . ' --authentication-file=/proc/self/fd/3' .
' -gL ' . escapeshellarg($this->getHost());
$connection = new RawConnection($command);
$connection->write($this->getPassword() . PHP_EOL);
$connection->writeAuthentication($this->getUser(), $this->getPassword());
$output = $connection->readAll();
$line = $output[0];
// disregard password prompt
if (substr($line, 0, 6) == 'Enter ' and count($output) > 1) {
$line = $output[1];
}
$line = rtrim($line, ')');
if (substr($line, -23) === ErrorCodes::LogonFailure) {
throw new AuthenticationException();

View file

@ -40,11 +40,10 @@ class Share implements IShare {
if ($this->connection and $this->connection->isValid()) {
return;
}
$command = Server::CLIENT . ' -U ' . escapeshellarg($this->server->getUser()) .
$command = Server::CLIENT . ' --authentication-file=/proc/self/fd/3' .
' //' . $this->server->getHost() . '/' . $this->name;
$this->connection = new Connection($command);
$this->connection->write($this->server->getPassword());
$this->connection->readLine(); // discard password prompt
$this->connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
if (!$this->connection->isValid()) {
throw new ConnectionError();
}
@ -212,13 +211,11 @@ class Share implements IShare {
public function read($source) {
$source = $this->escapePath($source);
// since we do binary transfer over STDOUT we create a new connection
$command = Server::CLIENT . ' -U ' . escapeshellarg($this->server->getUser()) .
$command = Server::CLIENT . ' --authentication-file=/proc/self/fd/3' .
' //' . $this->server->getHost() . '/' . $this->name
. ' -c \'get ' . $source . ' -\'';
// because we're piping the files content over STOUT using the password prompt is no option here
$connection = new Connection($command, array(
'PASSWD' => $this->server->getPassword()
));
$connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
$fh = $connection->getOutputStream();
//save the connection as context of the stream to prevent it going out of scope and cleaning up the resource
stream_context_set_option($fh, 'file', 'connection', $connection);