Merge pull request #806 from metaclassing/sshv1-exceptions

Exception support for SSHv1

* metaclassing/sshv1-exceptions:
  I misinterpreted the meaning of === true and messed up quotes on one throw
  Tried to replicate SSHv2 exception support into SSHv1
This commit is contained in:
Andreas Fischer 2015-09-07 00:39:26 +02:00
commit ef3d0a8ed0

View File

@ -537,14 +537,15 @@ class SSH1
* Connect to an SSHv1 server * Connect to an SSHv1 server
* *
* @return bool * @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private * @access private
*/ */
function _connect() function _connect()
{ {
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout); $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) { if (!$this->fsock) {
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr")); throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return false;
} }
$this->server_identification = $init_line = fgets($this->fsock, 255); $this->server_identification = $init_line = fgets($this->fsock, 255);
@ -555,20 +556,17 @@ class SSH1
} }
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) { if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
user_error('Can only connect to SSH servers'); throw new \RuntimeException('Can only connect to SSH servers');
return false;
} }
if ($parts[1][0] != 1) { if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers"); throw new \RuntimeException("Cannot connect to $parts[1] servers");
return false;
} }
fputs($this->fsock, $this->identifier."\r\n"); fputs($this->fsock, $this->identifier."\r\n");
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) { if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
user_error('Expected SSH_SMSG_PUBLIC_KEY'); throw new \UnexpectedValueException('Expected SSH_SMSG_PUBLIC_KEY');
return false;
} }
$anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8); $anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
@ -652,8 +650,7 @@ class SSH1
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0); $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_SESSION_KEY'); throw new \RuntimeException('Error sending SSH_CMSG_SESSION_KEY');
return false;
} }
switch ($cipher) { switch ($cipher) {
@ -682,8 +679,7 @@ class SSH1
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS'); throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
return false;
} }
$this->bitmap = self::MASK_CONNECTED; $this->bitmap = self::MASK_CONNECTED;
@ -697,6 +693,8 @@ class SSH1
* @param string $username * @param string $username
* @param string $password * @param string $password
* @return bool * @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access public * @access public
*/ */
function login($username, $password = '') function login($username, $password = '')
@ -715,8 +713,7 @@ class SSH1
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username); $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_USER'); throw new \RuntimeException('Error sending SSH_CMSG_USER');
return false;
} }
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
@ -728,15 +725,13 @@ class SSH1
$this->bitmap |= self::MASK_LOGIN; $this->bitmap |= self::MASK_LOGIN;
return true; return true;
} elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) { } elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE'); throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
} }
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password); $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_AUTH_PASSWORD'); throw new \RuntimeException('Error sending SSH_CMSG_AUTH_PASSWORD');
return false;
} }
// remove the username and password from the last logged packet // remove the username and password from the last logged packet
@ -756,8 +751,7 @@ class SSH1
} elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) { } elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
return false; return false;
} else { } else {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE'); throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
} }
} }
@ -792,20 +786,19 @@ class SSH1
* @see \phpseclib\Net\SSH1::interactiveWrite() * @see \phpseclib\Net\SSH1::interactiveWrite()
* @param string $cmd * @param string $cmd
* @return mixed * @return mixed
* @throws \RuntimeException on error sending command
* @access public * @access public
*/ */
function exec($cmd, $block = true) function exec($cmd, $block = true)
{ {
if (!($this->bitmap & self::MASK_LOGIN)) { if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()'); throw new \RuntimeException('Operation disallowed prior to login()');
return false;
} }
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd); $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_CMD'); throw new \RuntimeException('Error sending SSH_CMSG_EXEC_CMD');
return false;
} }
if (!$block) { if (!$block) {
@ -841,6 +834,8 @@ class SSH1
* @see \phpseclib\Net\SSH1::interactiveRead() * @see \phpseclib\Net\SSH1::interactiveRead()
* @see \phpseclib\Net\SSH1::interactiveWrite() * @see \phpseclib\Net\SSH1::interactiveWrite()
* @return bool * @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private * @access private
*/ */
function _initShell() function _initShell()
@ -851,8 +846,7 @@ class SSH1
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END); $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_REQUEST_PTY'); throw new \RuntimeException('Error sending SSH_CMSG_REQUEST_PTY');
return false;
} }
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
@ -861,15 +855,13 @@ class SSH1
return false; return false;
} }
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS'); throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
return false;
} }
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL); $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_SHELL'); throw new \RuntimeException('Error sending SSH_CMSG_EXEC_SHELL');
return false;
} }
$this->bitmap |= self::MASK_SHELL; $this->bitmap |= self::MASK_SHELL;
@ -902,18 +894,17 @@ class SSH1
* @param string $expect * @param string $expect
* @param int $mode * @param int $mode
* @return bool * @return bool
* @throws \RuntimeException on connection error
* @access public * @access public
*/ */
function read($expect, $mode = self::READ__SIMPLE) function read($expect, $mode = self::READ__SIMPLE)
{ {
if (!($this->bitmap & self::MASK_LOGIN)) { if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()'); throw new \RuntimeException('Operation disallowed prior to login()');
return false;
} }
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) { if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session'); throw new \RuntimeException('Unable to initiate an interactive shell session');
return false;
} }
$match = $expect; $match = $expect;
@ -941,25 +932,23 @@ class SSH1
* @see \phpseclib\Net\SSH1::interactiveRead() * @see \phpseclib\Net\SSH1::interactiveRead()
* @param string $cmd * @param string $cmd
* @return bool * @return bool
* @throws \RuntimeException on connection error
* @access public * @access public
*/ */
function interactiveWrite($cmd) function interactiveWrite($cmd)
{ {
if (!($this->bitmap & self::MASK_LOGIN)) { if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()'); throw new \RuntimeException('Operation disallowed prior to login()');
return false;
} }
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) { if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session'); throw new \RuntimeException('Unable to initiate an interactive shell session');
return false;
} }
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd); $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_STDIN'); throw new \RuntimeException('Error sending SSH_CMSG_STDIN');
return false;
} }
return true; return true;
@ -976,18 +965,17 @@ class SSH1
* *
* @see \phpseclib\Net\SSH1::interactiveRead() * @see \phpseclib\Net\SSH1::interactiveRead()
* @return string * @return string
* @throws \RuntimeException on connection error
* @access public * @access public
*/ */
function interactiveRead() function interactiveRead()
{ {
if (!($this->bitmap & self::MASK_LOGIN)) { if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()'); throw new \RuntimeException('Operation disallowed prior to login()');
return false;
} }
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) { if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session'); throw new \RuntimeException('Unable to initiate an interactive shell session');
return false;
} }
$read = array($this->fsock); $read = array($this->fsock);