SFTP: reopen channel on channel closure

This commit is contained in:
terrafrost 2021-05-09 01:07:09 -05:00
parent bd0e217793
commit 05828a8759
2 changed files with 85 additions and 107 deletions

View File

@ -284,6 +284,16 @@ class SFTP extends SSH2
*/ */
private $preserveTime = false; private $preserveTime = false;
/**
* Was the last packet due to the channels being closed or not?
*
* @see self::get()
* @see self::get_sftp_packet()
* @var bool
* @access private
*/
private $channel_close = false;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -442,6 +452,18 @@ class SFTP extends SSH2
return false; return false;
} }
return $this->init_sftp_connection();
}
/**
* (Re)initializes the SFTP channel
*
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access private
*/
private function init_sftp_connection()
{
$this->window_size_server_to_client[self::CHANNEL] = $this->window_size; $this->window_size_server_to_client[self::CHANNEL] = $this->window_size;
$packet = Strings::packSSH2( $packet = Strings::packSSH2(
@ -457,10 +479,7 @@ class SFTP extends SSH2
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN; $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->get_channel_packet(self::CHANNEL, true); $this->get_channel_packet(self::CHANNEL, true);
if ($response === false) {
return false;
}
$packet = Strings::packSSH2( $packet = Strings::packSSH2(
'CNsbs', 'CNsbs',
@ -501,10 +520,7 @@ class SFTP extends SSH2
} }
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA; $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
$this->send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3");
if (!$this->send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
if ($this->packet_type != NET_SFTP_VERSION) { if ($this->packet_type != NET_SFTP_VERSION) {
@ -577,7 +593,7 @@ class SFTP extends SSH2
* *
* @access public * @access public
*/ */
function disableStatCache() public function disableStatCache()
{ {
$this->use_stat_cache = false; $this->use_stat_cache = false;
} }
@ -679,9 +695,7 @@ class SFTP extends SSH2
if ($this->pwd === false) { if ($this->pwd === false) {
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
if (!$this->send_sftp_packet(NET_SFTP_REALPATH, Strings::packSSH2('s', $path))) { $this->send_sftp_packet(NET_SFTP_REALPATH, Strings::packSSH2('s', $path));
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -758,9 +772,7 @@ class SFTP extends SSH2
// the file's uid / gid match the currently logged in user's uid / gid but how there's no easy // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
// way to get those with SFTP // way to get those with SFTP
if (!$this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir))) { $this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir));
return false;
}
// see \phpseclib3\Net\SFTP::nlist() for a more thorough explanation of the following // see \phpseclib3\Net\SFTP::nlist() for a more thorough explanation of the following
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
@ -899,9 +911,7 @@ class SFTP extends SSH2
} }
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
if (!$this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir))) { $this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir));
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -927,9 +937,7 @@ class SFTP extends SSH2
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
// why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
// SSH_MSG_CHANNEL_DATA messages is not known to me. // SSH_MSG_CHANNEL_DATA messages is not known to me.
if (!$this->send_sftp_packet(NET_SFTP_READDIR, Strings::packSSH2('s', $handle))) { $this->send_sftp_packet(NET_SFTP_READDIR, Strings::packSSH2('s', $handle));
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -1319,9 +1327,7 @@ class SFTP extends SSH2
{ {
// SFTPv4+ adds an additional 32-bit integer field - flags - to the following: // SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
$packet = Strings::packSSH2('s', $filename); $packet = Strings::packSSH2('s', $filename);
if (!$this->send_sftp_packet($type, $packet)) { $this->send_sftp_packet($type, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -1384,9 +1390,7 @@ class SFTP extends SSH2
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL; $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime); $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
$packet = Strings::packSSH2('sN', $filename, $flags) . $attr; $packet = Strings::packSSH2('sN', $filename, $flags) . $attr;
if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { $this->send_sftp_packet(NET_SFTP_OPEN, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -1475,9 +1479,7 @@ class SFTP extends SSH2
// tell us if the file actually exists. // tell us if the file actually exists.
// incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following: // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
$packet = pack('Na*', strlen($filename), $filename); $packet = pack('Na*', strlen($filename), $filename);
if (!$this->send_sftp_packet(NET_SFTP_STAT, $packet)) { $this->send_sftp_packet(NET_SFTP_STAT, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -1525,9 +1527,7 @@ class SFTP extends SSH2
// SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
// SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT. // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
if (!$this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $filename) . $attr)) { $this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $filename) . $attr);
return false;
}
/* /*
"Because some systems must use separate system calls to set various attributes, it is possible that a failure "Because some systems must use separate system calls to set various attributes, it is possible that a failure
@ -1592,9 +1592,7 @@ class SFTP extends SSH2
return false; return false;
} }
} else { } else {
if (!$this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $temp) . $attr)) { $this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $temp) . $attr);
return false;
}
$i++; $i++;
@ -1607,9 +1605,7 @@ class SFTP extends SSH2
} }
} }
if (!$this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $path) . $attr)) { $this->send_sftp_packet(NET_SFTP_SETSTAT, Strings::packSSH2('s', $path) . $attr);
return false;
}
$i++; $i++;
@ -1639,9 +1635,7 @@ class SFTP extends SSH2
$link = $this->realpath($link); $link = $this->realpath($link);
if (!$this->send_sftp_packet(NET_SFTP_READLINK, Strings::packSSH2('s', $link))) { $this->send_sftp_packet(NET_SFTP_READLINK, Strings::packSSH2('s', $link));
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -1687,9 +1681,7 @@ class SFTP extends SSH2
$link = $this->realpath($link); $link = $this->realpath($link);
$packet = Strings::packSSH2('ss', $target, $link); $packet = Strings::packSSH2('ss', $target, $link);
if (!$this->send_sftp_packet(NET_SFTP_SYMLINK, $packet)) { $this->send_sftp_packet(NET_SFTP_SYMLINK, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) { if ($this->packet_type != NET_SFTP_STATUS) {
@ -1751,9 +1743,7 @@ class SFTP extends SSH2
private function mkdir_helper($dir, $mode) private function mkdir_helper($dir, $mode)
{ {
// send SSH_FXP_MKDIR without any attributes (that's what the \0\0\0\0 is doing) // send SSH_FXP_MKDIR without any attributes (that's what the \0\0\0\0 is doing)
if (!$this->send_sftp_packet(NET_SFTP_MKDIR, Strings::packSSH2('s', $dir) . "\0\0\0\0")) { $this->send_sftp_packet(NET_SFTP_MKDIR, Strings::packSSH2('s', $dir) . "\0\0\0\0");
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) { if ($this->packet_type != NET_SFTP_STATUS) {
@ -1793,9 +1783,7 @@ class SFTP extends SSH2
return false; return false;
} }
if (!$this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $dir))) { $this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $dir));
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) { if ($this->packet_type != NET_SFTP_STATUS) {
@ -1898,9 +1886,7 @@ class SFTP extends SSH2
$this->remove_from_stat_cache($remote_file); $this->remove_from_stat_cache($remote_file);
$packet = Strings::packSSH2('sNN', $remote_file, $flags, 0); $packet = Strings::packSSH2('sNN', $remote_file, $flags, 0);
if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { $this->send_sftp_packet(NET_SFTP_OPEN, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -1982,11 +1968,13 @@ class SFTP extends SSH2
$subtemp = $offset + $sent; $subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->send_sftp_packet(NET_SFTP_WRITE, $packet, $j)) { try {
$this->send_sftp_packet(NET_SFTP_WRITE, $packet, $j);
} catch (\Exception $e) {
if ($mode & self::SOURCE_LOCAL_FILE) { if ($mode & self::SOURCE_LOCAL_FILE) {
fclose($fp); fclose($fp);
} }
return false; throw $e;
} }
$sent+= strlen($temp); $sent+= strlen($temp);
if (is_callable($progressCallback)) { if (is_callable($progressCallback)) {
@ -2066,9 +2054,7 @@ class SFTP extends SSH2
*/ */
private function close_handle($handle) private function close_handle($handle)
{ {
if (!$this->send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { $this->send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle));
return false;
}
// "The client MUST release all resources associated with the handle regardless of the status." // "The client MUST release all resources associated with the handle regardless of the status."
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
@ -2117,9 +2103,7 @@ class SFTP extends SSH2
} }
$packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0); $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { $this->send_sftp_packet(NET_SFTP_OPEN, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -2163,11 +2147,13 @@ class SFTP extends SSH2
$packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet; $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
$packet = Strings::packSSH2('sN3', $handle, $tempoffset / 4294967296, $tempoffset, $packet_size); $packet = Strings::packSSH2('sN3', $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
if (!$this->send_sftp_packet(NET_SFTP_READ, $packet, $i)) { try {
$this->send_sftp_packet(NET_SFTP_READ, $packet, $i);
} catch (\Exception $e) {
if ($fclose_check) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
return false; throw $e;
} }
$packet = null; $packet = null;
$read+= $packet_size; $read+= $packet_size;
@ -2216,8 +2202,12 @@ class SFTP extends SSH2
if ($fclose_check) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
throw new \UnexpectedValueException('Expected NET_SFTP_DATA or NET_SFTP_STATUS. ' if ($this->channel_close) {
. 'Got packet type: ' . $this->packet_type); $this->init_sftp_connection();
} else {
throw new \UnexpectedValueException('Expected NET_SFTP_DATA or NET_SFTP_STATUS. '
. 'Got packet type: ' . $this->packet_type);
}
} }
$response = null; $response = null;
} }
@ -2282,9 +2272,7 @@ class SFTP extends SSH2
} }
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
if (!$this->send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) { $this->send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path));
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) { if ($this->packet_type != NET_SFTP_STATUS) {
@ -2347,9 +2335,7 @@ class SFTP extends SSH2
return false; return false;
} }
} else { } else {
if (!$this->send_sftp_packet(NET_SFTP_REMOVE, Strings::packSSH2('s', $temp))) { $this->send_sftp_packet(NET_SFTP_REMOVE, Strings::packSSH2('s', $temp));
return false;
}
$this->remove_from_stat_cache($temp); $this->remove_from_stat_cache($temp);
$i++; $i++;
@ -2363,9 +2349,7 @@ class SFTP extends SSH2
} }
} }
if (!$this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $path))) { $this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $path));
return false;
}
$this->remove_from_stat_cache($path); $this->remove_from_stat_cache($path);
$i++; $i++;
@ -2461,9 +2445,7 @@ class SFTP extends SSH2
public function is_readable($path) public function is_readable($path)
{ {
$packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_READ, 0); $packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_READ, 0);
if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { $this->send_sftp_packet(NET_SFTP_OPEN, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -2487,9 +2469,7 @@ class SFTP extends SSH2
public function is_writable($path) public function is_writable($path)
{ {
$packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_WRITE, 0); $packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_WRITE, 0);
if (!$this->send_sftp_packet(NET_SFTP_OPEN, $packet)) { $this->send_sftp_packet(NET_SFTP_OPEN, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
switch ($this->packet_type) { switch ($this->packet_type) {
@ -2706,9 +2686,7 @@ class SFTP extends SSH2
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
$packet = Strings::packSSH2('ss', $oldname, $newname); $packet = Strings::packSSH2('ss', $oldname, $newname);
if (!$this->send_sftp_packet(NET_SFTP_RENAME, $packet)) { $this->send_sftp_packet(NET_SFTP_RENAME, $packet);
return false;
}
$response = $this->get_sftp_packet(); $response = $this->get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) { if ($this->packet_type != NET_SFTP_STATUS) {
@ -2942,6 +2920,8 @@ class SFTP extends SSH2
*/ */
private function get_sftp_packet($request_id = null) private function get_sftp_packet($request_id = null)
{ {
$this->channel_close = false;
if (isset($request_id) && isset($this->requestBuffer[$request_id])) { if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
$this->packet_type = $this->requestBuffer[$request_id]['packet_type']; $this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
$temp = $this->requestBuffer[$request_id]['packet']; $temp = $this->requestBuffer[$request_id]['packet'];
@ -2966,7 +2946,7 @@ class SFTP extends SSH2
$this->packet_buffer.= $temp; $this->packet_buffer.= $temp;
} }
if (strlen($this->packet_buffer) < 4) { if (strlen($this->packet_buffer) < 4) {
return false; throw new \RuntimeException('Packet is too small');
} }
extract(unpack('Nlength', Strings::shift($this->packet_buffer, 4))); extract(unpack('Nlength', Strings::shift($this->packet_buffer, 4)));
/** @var integer $length */ /** @var integer $length */

View File

@ -2657,10 +2657,7 @@ class SSH2
$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->get_channel_packet(self::CHANNEL_EXEC); $this->get_channel_packet(self::CHANNEL_EXEC);
if ($response === false) {
return false;
}
if ($this->request_pty === true) { if ($this->request_pty === true) {
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
@ -2719,8 +2716,7 @@ class SSH2
$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->get_channel_packet(self::CHANNEL_EXEC); if (!$this->get_channel_packet(self::CHANNEL_EXEC)) {
if ($response === false) {
return false; return false;
} }
@ -2783,10 +2779,7 @@ class SSH2
$this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->get_channel_packet(self::CHANNEL_SHELL); $this->get_channel_packet(self::CHANNEL_SHELL);
if ($response === false) {
return false;
}
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = Strings::packSSH2( $packet = Strings::packSSH2(
@ -2884,8 +2877,7 @@ class SSH2
$this->send_binary_packet($packet); $this->send_binary_packet($packet);
$response = $this->get_channel_packet($request_channel); if (!$this->get_channel_packet($request_channel)) {
if ($response === false) {
return false; return false;
} }
@ -2937,9 +2929,9 @@ class SSH2
return Strings::shift($this->interactiveBuffer, $pos + strlen($match)); return Strings::shift($this->interactiveBuffer, $pos + strlen($match));
} }
$response = $this->get_channel_packet($channel); $response = $this->get_channel_packet($channel);
if (is_bool($response)) { if ($response === true) {
$this->in_request_pty_exec = false; $this->in_request_pty_exec = false;
return $response ? Strings::shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false; return Strings::shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
} }
$this->interactiveBuffer.= $response; $this->interactiveBuffer.= $response;
@ -2999,10 +2991,7 @@ class SSH2
$this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN; $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->get_channel_packet(self::CHANNEL_SUBSYSTEM); $this->get_channel_packet(self::CHANNEL_SUBSYSTEM);
if ($response === false) {
return false;
}
$packet = Strings::packSSH2( $packet = Strings::packSSH2(
'CNsCs', 'CNsCs',
@ -3016,8 +3005,7 @@ class SSH2
$this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST; $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->get_channel_packet(self::CHANNEL_SUBSYSTEM); if (!$this->get_channel_packet(self::CHANNEL_SUBSYSTEM)) {
if ($response === false) {
return false; return false;
} }
@ -3335,7 +3323,8 @@ class SSH2
} }
if (strlen($raw) < 5) { if (strlen($raw) < 5) {
return false; $this->bitmap = 0;
throw new \RuntimeException('Plaintext is too short');
} }
extract(unpack('Npacket_length/Cpadding_length', Strings::shift($raw, 5))); extract(unpack('Npacket_length/Cpadding_length', Strings::shift($raw, 5)));
/** /**
@ -3686,7 +3675,16 @@ class SSH2
/** /**
* Gets channel data * Gets channel data
* *
* Returns the data as a string if it's available and false if not. * Returns the data as a string. bool(true) is returned if:
*
* - the server closes the channel
* - if the connection times out
* - if the channel status is CHANNEL_OPEN and the response was CHANNEL_OPEN_CONFIRMATION
* - if the channel status is CHANNEL_REQUEST and the response was CHANNEL_SUCCESS
*
* bool(false) is returned if:
*
* - if the channel status is CHANNEL_REQUEST and the response was CHANNEL_FAILURE
* *
* @param int $client_channel * @param int $client_channel
* @param bool $skip_extended * @param bool $skip_extended