SSH2: implement a different fix for #1613

This commit is contained in:
terrafrost 2021-10-11 08:47:51 -05:00
parent 1fab947f01
commit 0fe328936c

View File

@ -2830,6 +2830,7 @@ class Net_SSH2
} }
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC)) { if (!$this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC)) {
user_error('Unable to request pseudo-terminal'); user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
@ -2956,6 +2957,13 @@ class Net_SSH2
return false; 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( $packet = pack(
'CNNa*C', 'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST, NET_SSH2_MSG_CHANNEL_REQUEST,
@ -2968,7 +2976,12 @@ class Net_SSH2
return false; 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; $this->bitmap |= NET_SSH2_MASK_SHELL;
@ -3386,7 +3399,7 @@ class Net_SSH2
if (!is_resource($this->fsock) || feof($this->fsock)) { if (!is_resource($this->fsock) || feof($this->fsock)) {
$this->bitmap = 0; $this->bitmap = 0;
user_error('Connection closed prematurely'); user_error('Connection closed (by server) prematurely');
return false; return false;
} }
@ -3741,7 +3754,20 @@ class Net_SSH2
function _get_channel_packet($client_channel, $skip_extended = false) function _get_channel_packet($client_channel, $skip_extended = false)
{ {
if (!empty($this->channel_buffers[$client_channel])) { 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) { while (true) {
@ -3818,7 +3844,7 @@ class Net_SSH2
if (!isset($this->channel_buffers[$channel])) { if (!isset($this->channel_buffers[$channel])) {
$this->channel_buffers[$channel] = array(); $this->channel_buffers[$channel] = array();
} }
$this->channel_buffers[$channel][] = $data; $this->channel_buffers[$channel][] = chr($type) . $data;
continue 2; continue 2;
case NET_SSH2_MSG_CHANNEL_REQUEST: case NET_SSH2_MSG_CHANNEL_REQUEST:
@ -3908,22 +3934,23 @@ class Net_SSH2
return $this->_get_channel_packet($client_channel, $skip_extended); return $this->_get_channel_packet($client_channel, $skip_extended);
} }
break; 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: case NET_SSH2_MSG_CHANNEL_REQUEST:
switch ($type) { switch ($type) {
case NET_SSH2_MSG_CHANNEL_SUCCESS: case NET_SSH2_MSG_CHANNEL_SUCCESS:
return true; return true;
case NET_SSH2_MSG_CHANNEL_FAILURE: case NET_SSH2_MSG_CHANNEL_FAILURE:
return false; 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: default:
user_error('Unable to fulfill channel request'); user_error('Unable to fulfill channel request');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
@ -3937,10 +3964,6 @@ class Net_SSH2
switch ($type) { switch ($type) {
case NET_SSH2_MSG_CHANNEL_DATA: 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) { 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 // 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])) { if (!isset($this->channel_buffers[$channel])) {
$this->channel_buffers[$channel] = array(); $this->channel_buffers[$channel] = array();
} }
$this->channel_buffers[$channel][] = $data; $this->channel_buffers[$channel][] = chr($type) . $data;
break; break;
case NET_SSH2_MSG_CHANNEL_CLOSE: case NET_SSH2_MSG_CHANNEL_CLOSE:
$this->curTimeout = 5; $this->curTimeout = 5;
@ -3989,7 +4012,7 @@ class Net_SSH2
case NET_SSH2_MSG_CHANNEL_EOF: case NET_SSH2_MSG_CHANNEL_EOF:
break; break;
default: default:
user_error('Error reading channel data'); user_error("Error reading channel data ($type)");
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
} }
} }