diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 92316b35..fbda7b19 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -2744,6 +2744,12 @@ class SSH2 $this->send_binary_packet($packet); + $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; + + if (!$this->get_channel_packet(self::CHANNEL_SHELL)) { + throw new \RuntimeException('Unable to request pty'); + } + $packet = Strings::packSSH2( 'CNsb', NET_SSH2_MSG_CHANNEL_REQUEST, @@ -2753,7 +2759,12 @@ class SSH2 ); $this->send_binary_packet($packet); - $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_IGNORE; + $response = $this->get_channel_packet(self::CHANNEL_SHELL); + if ($response === false) { + throw new \RuntimeException('Unable to request shell'); + } + + $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap |= self::MASK_SHELL; @@ -3187,7 +3198,7 @@ class SSH2 if (!is_resource($this->fsock) || feof($this->fsock)) { $this->bitmap = 0; - throw new ConnectionClosedException('Connection closed prematurely'); + throw new ConnectionClosedException('Connection closed (by server) prematurely'); } $start = microtime(true); @@ -3643,7 +3654,20 @@ class SSH2 protected function get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { - return array_shift($this->channel_buffers[$client_channel]); + switch ($this->channel_status[$client_channel]) { + case NET_SSH2_MSG_CHANNEL_REQUEST: + foreach ($this->channel_buffers[$client_channel] as $i => $packet) { + switch (ord($packet[0])) { + case NET_SSH2_MSG_CHANNEL_SUCCESS: + case NET_SSH2_MSG_CHANNEL_FAILURE: + unset($this->channel_buffers[$client_channel][$i]); + return substr($packet, 1); + } + } + break; + default: + return substr(array_shift($this->channel_buffers[$client_channel]), 1); + } } while (true) { @@ -3698,10 +3722,7 @@ class SSH2 if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) { return $data; } - if (!isset($this->channel_buffers[$channel])) { - $this->channel_buffers[$channel] = []; - } - $this->channel_buffers[$channel][] = $data; + $this->channel_buffers[$channel][] = chr($type) . $data; continue 2; case NET_SSH2_MSG_CHANNEL_REQUEST: @@ -3772,22 +3793,16 @@ class SSH2 return $this->get_channel_packet($client_channel, $skip_extended); } break; - case NET_SSH2_MSG_IGNORE: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_SUCCESS: - //$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_DATA; - continue 3; - case NET_SSH2_MSG_CHANNEL_FAILURE: - $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - throw new \RuntimeException('Error opening channel'); - } - break; case NET_SSH2_MSG_CHANNEL_REQUEST: switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: return true; case NET_SSH2_MSG_CHANNEL_FAILURE: return false; + case NET_SSH2_MSG_CHANNEL_DATA: + list($data) = Strings::unpackSSH2('s', $response); + $this->channel_buffers[$channel][] = chr($type) . $data; + return $this->get_channel_packet($client_channel, $skip_extended); default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); throw new \RuntimeException('Unable to fulfill channel request'); @@ -3801,10 +3816,6 @@ class SSH2 switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: - //if ($this->channel_status[$channel] == NET_SSH2_MSG_IGNORE) { - // $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_DATA; - //} - /* if ($channel == self::CHANNEL_EXEC) { // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server @@ -3827,10 +3838,7 @@ class SSH2 if ($client_channel == $channel) { return $data; } - if (!isset($this->channel_buffers[$channel])) { - $this->channel_buffers[$channel] = []; - } - $this->channel_buffers[$channel][] = $data; + $this->channel_buffers[$channel][] = chr($type) . $data; break; case NET_SSH2_MSG_CHANNEL_CLOSE: $this->curTimeout = 5; @@ -3850,7 +3858,7 @@ class SSH2 break; default: $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION); - throw new \RuntimeException('Error reading channel data'); + throw new \RuntimeException("Error reading channel data ($type)"); } } }