22

I am using the ssh2_connect() method to establish a connection with a remote server. A connection is establishing correctly if I am providing the right hostname and port number. When unable to connect due to wrong credentials, I am trying to call a callback-function but the way I try it isn't calling the callback after connection failure.

This i the code I tried:

$callbacks = array( 
      'ignore' => array($this, 'callbackSshDisconnect'), 
      'debug' => array($this, 'callbackSshDisconnect'), 
      'macerror' => array($this, 'callbackSshDisconnect'), 
      'disconnect' => array($this, 'callbackSshDisconnect'), 
);

ssh2_connect($hostName,$port,array('hostkey', 'ssh-rsa'),$callbacks);

public function callbackSshDisconnect($reason, $message, $language) {
    $this->log('disconnected');
    $this->log($reason);die;
}

What I am doing wrong?

rubo77
  • 19,527
  • 31
  • 134
  • 226
Ganesh Patil
  • 670
  • 1
  • 5
  • 22

4 Answers4

7

When ssh2_connect fails because of wrong host, port, and so on, it doesn't call any callbacks.

What is does, instead, is returning false

PHP documentation says :
Returns a resource on success, or FALSE on error.

$result = ssh2_connect($hostName,$port,array('hostkey' => 'ssh-rsa'),$callbacks);
if ($result === false)
   exit("ssh2_connect failed");

Also, reading the doc, your

array('hostkey', 'ssh-rsa')

should be

array('hostkey' => 'ssh-rsa')
blue112
  • 52,634
  • 3
  • 45
  • 54
5

There's nothing you are doing wrong apart from the typo: array('hostkey', 'ssh-rsa') should be array('hostkey' => 'ssh-rsa'). The function ssh_connect() just returns false for a connection failure; callbacks simply are not initiated yet when the wrong credentials are being used.

There are solutions (e.g. as suggested by rubo77 below) but the one I find will give you most control, and allow you to do what you want (e.g. tracking MAC errors), is to use the phpseclib library (http://phpseclib.sourceforge.net/ssh/intro.html) for ssh connections and control. It gives very fine control of commands, and also includes logging.

It's not the simplest solution, but you can control as finely as if you are at the keyboard/terminal directly.

You have control over timeouts and can use callback on commands. But if you want better control, use read() and write() and you can monitor for disconnects or other issues. Check the documentation on logging with phpseclib: you can either log and parse the log, or call getLastError().

Log files will show 'Connection closed by server' on disconnects for example, but will also tell you if you're using an unsupported authentication mode on login etc.

Or for more, read the code: here, for example, are the disconnect reasons:

    $this->disconnect_reasons = array(
        1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
        2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
        3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
        4 => 'NET_SSH2_DISCONNECT_RESERVED',
        5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
        6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
        7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
        8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
        9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
        10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
        11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
        12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
        13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
        14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
        15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
    );
rubo77
  • 19,527
  • 31
  • 134
  • 226
Robbie
  • 17,605
  • 4
  • 35
  • 72
  • @rubo77: expanded as suggested. Thanks. – Robbie Apr 23 '15 at 02:08
  • no need to hint to other answers, just pretend your answer is the only answer here, feel free to enhance my grammar again – rubo77 Apr 23 '15 at 03:48
  • The aim is to help to OP program the correct solution, not always answer the specific question. So I always credit other answers (if they are correct) when I'm adding to them. However, in this case, I didn't realise you offered the bounty (although have now, thanks). But as you were obviously asking for a better solution than your own, hopefully this will help. As a tip, if you are implementing, check out the instructions for "sudo" (Advanced interactive section) because when you get that to work, you're basically on your way. Otherwise dive in the code; it's easy enough to read. – Robbie Apr 23 '15 at 04:10
  • Thanks @rubo77 I had a misunderstandings about callbacks. I was thinking callbacks will call every time when there is connection problem due to credentials. – Ganesh Patil Apr 27 '15 at 07:28
0

Even if you would use working code, like this:

$callbacks = array(
    'ignore' => 'callback',
    'debug' => 'callback',
    'macerror' => 'callback',
    'disconnect' =>'callback',
);

$session = ssh2_connect($hostName, $port, array('hostkey' => 'ssh-rsa'), $callbacks);
if($session === false) {
    print('Connection failed' . PHP_EOL);
    exit(1);
}

if(!ssh2_auth_pubkey_file(
    $session,
    "user",
    '/home/user/.ssh/id_rsa.pub',
    '/home/user/.ssh/id_rsa'
)) {
    print('Failed to authenticate session' . PHP_EOL);
    exit(2);
}

// Check this great answer:
// http://stackoverflow.com/a/12094837/171318
$stream = ssh2_exec($session, "ls -al");
stream_set_blocking($stream, true);
$stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
echo stream_get_contents($stream);  

function callback($reason, $message, $language) {
    print("callback:" . PHP_EOL);
    print(" " . $message . PHP_EOL);
    print(" " . $reason . PHP_EOL);
}

the callbacks won't get called in a usual application. This is because they were called just under certain circumstances named in the manual page

The disconnect callback for example get's only called if a SSH2_MSG_DISCONNECT packet is received. Such a packet is not received unless the server closes the connection which will usually not happen.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
0

When you are unable to connect due to wrong credentials then you won't get any callbacks anyway, ssh2_connect() just returns false in this case.

If you really want to catch the reason of the failure, you can use output buffer handler to extract the error message (assuming, you have error reporting set on):

set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) {
    list($command,$errormessage)=explode(":",$errstr,2);
    echo "Error ($errno):", $errormessage."<br><br>";
});
$connection = ssh2_connect($hostName,$port);
restore_error_handler();
Robbie
  • 17,605
  • 4
  • 35
  • 72
rubo77
  • 19,527
  • 31
  • 134
  • 226