2

Here's what I'm trying to achieve: open a shell (korn or bash, doesn't matter), from that shell, I want to open a ssh connection (ssh user@host). At some point it is likely to happen I will be prompted for either a password or I might be asked whether or not I'm sure I want to connect (offending keys).

Before anyone asks: yes, I am aware there is a plugin for ssh2 exec calls, but the servers I'm working on don't support it, and are unlikely to do so.

Here's what I've tried so far:

$desc = array(array('pipe','r'),array('pipe','w'));//used in all example code
$p = proc_open('ssh user@host',$desc,$pipes);
if(!is_resource($p)){ die('@!#$%');}//will omit this line from now on
sleep(1);//omitting this,too but it's there every time I need it

Then I tried to read console output (stream_get_contents($pipes[1])) to see what I have to pass next (either password, yes or return 'connection failed: '.stream_get_contents($pipes[1]) and proc_close $p.

This gave me the following error:

Pseudo-terminal will not be allocated because stdin is not a terminal.

So, I though ssh was called in the php:// io-stream context, seems a plausible explanation of the above error.

Next: I though about my first SO question and decided it might be a good idea to open a bash/ksh shell first:

$p = proc_open('bash',$desc,$pipes);

And take it from there, but I got the exact same error message, only this time, the script stopped running but ssh did run. So I got hopeful, then felt stupid and, eventually, desperate:

$p=proc_open('bash && ssh user@host',$desc,$pipes);

After a few seconds wait, I got the following error:

PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 133693440 bytes)

The Call Stack keeps bringing up the stream_get_contents line, even in my last desperate attempt:

#!/path/to/bin/php -n
<?php
    $p = proc_open('bash && ssh user@host',array(array('pipe','r'),array('pipe','w')),$ps);
    if (!is_resource($p))
    {
        die('FFS');
    }
    usleep(10);
    fwrite($ps[0],'yes'."\n");
    fflush($ps[0]);
    usleep(20);
    fwrite($ps[0],'password'."\n");
    fflush($ps[0]);
    usleep(20);
    fwrite($ps[0],'whoami'."\n");
    fflush($ps[0]);
    usleep(2);
    $msg = stream_get_contents($ps[1]);
    fwrite($ps[0],'exit'."\n");
    fclose($ps[0]);
    fclose($ps[1]);
    proc_close($p);
?>

I know, its a mess, a lot of fflush and redundancy, but the point is: I know this connection will first prompt me for offending keys, and then ask a password. My guess is the stream in $pipes[1] holds the ssh connection, hence it's content is huge. what I need then, is a pipe inside a pipe... is this even possible? I must be missing something, what good is a pipe if this isn't possible... My guess is the proc_open command is wrong to begin with, (error: Broken pipe). But I really can't see any other way around the first error... any thoughts? Or follow up questions if the above rant isn't at all clear (which it probably isn't).

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149

1 Answers1

1

Before anyone asks: yes, I am aware there is a plugin for ssh2 exec calls, but the servers I'm working on don't support it, and are unlikely to do so.

There are actually two. The PECL module, which is a PITA that most servers don't have installed anyway and phpseclib, a pure PHP SSH2 implementation. An example of its use:

<?php
include('Net/SSH2.php');

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
    exit('Login Failed');
}

echo $ssh->exec('pwd');
echo $ssh->exec('ls -la');
?>
neubert
  • 15,947
  • 24
  • 120
  • 212
  • Thanks, interesting lib, though I wonder: is it still supported? judging by the code, I'd say it's written with PHP4 in mind, and the first bunch of hits on google are all over a year old... I'll give it a try, nonetheless. If it works, it works, and I'll let you know – Elias Van Ootegem Apr 11 '12 at 17:41
  • 1
    There was a commit made three days ago to its SVN repo and the author made a post yesterday helping someone. I think the goal of the library is to be both PHP4 and PHP5 compatible. Using private / public instead of var makes the code PHP5 only but doesn't really add a lot otherwise imho. – neubert Apr 11 '12 at 20:02
  • Sorry, nice though this lib is, interacting with the processes on the remote host is still a bit of a no-no, isn't it? `$ssh->exec('su');` for example, will hang, because I can't seem to find a way to pass the password. – Elias Van Ootegem Apr 12 '12 at 10:28
  • Try $ssh->read() and $ssh->write(). Here's an example of how to do it with sudo: http://phpseclib.sourceforge.net/documentation/net.html#net_ssh_sudo – neubert Apr 12 '12 at 21:39
  • Thanks... stupid of me not to spend 5 minutes more checking sourceforge. I'm still a bit worried about the successive calls, though... but hey, I'll get there. Thanks again – Elias Van Ootegem Apr 12 '12 at 21:54
  • I've installed the pecl module phpseclib and it's shown on the phpinfo(), but i cant run that code. I've tried modifying some things, but still cannot run it. – m3nda Jun 21 '15 at 14:51