diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 87ae1764..59a2630e 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -2830,6 +2830,7 @@ class Net_SSH2 } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; + if (!$this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC)) { user_error('Unable to request pseudo-terminal'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); @@ -2956,6 +2957,13 @@ class Net_SSH2 return false; } + $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; + + if (!$this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL)) { + user_error('Unable to request pseudo-terminal'); + return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); + } + $packet = pack( 'CNNa*C', NET_SSH2_MSG_CHANNEL_REQUEST, @@ -2968,7 +2976,12 @@ class Net_SSH2 return false; } - $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_IGNORE; + $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); + if ($response === false) { + return false; + } + + $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap |= NET_SSH2_MASK_SHELL; @@ -3386,7 +3399,7 @@ class Net_SSH2 if (!is_resource($this->fsock) || feof($this->fsock)) { $this->bitmap = 0; - user_error('Connection closed prematurely'); + user_error('Connection closed (by server) prematurely'); return false; } @@ -3741,7 +3754,20 @@ class Net_SSH2 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) { @@ -3818,7 +3844,7 @@ class Net_SSH2 if (!isset($this->channel_buffers[$channel])) { $this->channel_buffers[$channel] = array(); } - $this->channel_buffers[$channel][] = $data; + $this->channel_buffers[$channel][] = chr($type) . $data; continue 2; case NET_SSH2_MSG_CHANNEL_REQUEST: @@ -3908,22 +3934,23 @@ class Net_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: - user_error('Error opening channel'); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - 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: + if (strlen($response) < 4) { + return false; + } + extract(unpack('Nlength', $this->_string_shift($response, 4))); + $data = $this->_string_shift($response, $length); + if (!isset($this->channel_buffers[$channel])) { + $this->channel_buffers[$channel] = array(); + } + $this->channel_buffers[$channel][] = chr($type) . $data; + return $this->_get_channel_packet($client_channel, $skip_extended); default: user_error('Unable to fulfill channel request'); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); @@ -3937,10 +3964,6 @@ class Net_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 == NET_SSH2_CHANNEL_EXEC) { // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server @@ -3970,7 +3993,7 @@ class Net_SSH2 if (!isset($this->channel_buffers[$channel])) { $this->channel_buffers[$channel] = array(); } - $this->channel_buffers[$channel][] = $data; + $this->channel_buffers[$channel][] = chr($type) . $data; break; case NET_SSH2_MSG_CHANNEL_CLOSE: $this->curTimeout = 5; @@ -3989,7 +4012,7 @@ class Net_SSH2 case NET_SSH2_MSG_CHANNEL_EOF: break; default: - user_error('Error reading channel data'); + user_error("Error reading channel data ($type)"); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } }