SSH2: add preliminary support for custom SSH subsystems

This commit is contained in:
terrafrost 2013-10-25 12:35:30 -05:00
parent 15677715e3
commit c6a52cb1b1
2 changed files with 103 additions and 7 deletions

View File

@ -88,7 +88,7 @@ define('NET_SFTP_LOG_REALTIME', 3);
* @see Net_SSH2::_get_channel_packet()
* @access private
*/
define('NET_SFTP_CHANNEL', 2);
define('NET_SFTP_CHANNEL', 0x100);
/**#@+
* @access public

View File

@ -96,8 +96,9 @@ define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000010);
* @see Net_SSH2::_get_channel_packet()
* @access private
*/
define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
define('NET_SSH2_CHANNEL_SHELL',1);
define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
define('NET_SSH2_CHANNEL_SHELL', 1);
define('NET_SSH2_CHANNEL_SUBSYSTEM', 2);
/**#@-*/
/**#@+
@ -696,6 +697,13 @@ class Net_SSH2 {
*/
var $in_request_pty_exec = false;
/**
* Flag set after startSubsystem() is called
*
* @access private
*/
var $in_subsystem;
/**
* Contents of stdError
*
@ -2252,13 +2260,33 @@ class Net_SSH2 {
return true;
}
/**
* Return the channel to be used with read() / write()
*
* @see Net_SSH2::read()
* @see Net_SSH2::write()
* @return Integer
* @access public
*/
function _get_interactive_channel()
{
switch (true) {
case $this->in_subsystem:
return NET_SSH2_CHANNEL_SUBSYSTEM;
case $this->in_request_pty_exec:
return NET_SSH2_CHANNEL_EXEC;
default:
return NET_SSH2_CHANNEL_SHELL;
}
}
/**
* Returns the output of an interactive shell
*
* Returns when there's a match for $expect, which can take the form of a string literal or,
* if $mode == NET_SSH2_READ_REGEX, a regular expression.
*
* @see Net_SSH2::read()
* @see Net_SSH2::write()
* @param String $expect
* @param Integer $mode
* @return String
@ -2279,7 +2307,7 @@ class Net_SSH2 {
return false;
}
$channel = $this->in_request_pty_exec ? NET_SSH2_CHANNEL_EXEC : NET_SSH2_CHANNEL_SHELL;
$channel = $this->_get_interactive_channel();
$match = $expect;
while (true) {
@ -2304,7 +2332,7 @@ class Net_SSH2 {
/**
* Inputs a command into an interactive shell.
*
* @see Net_SSH1::interactiveWrite()
* @see Net_SSH2::read()
* @param String $cmd
* @return Boolean
* @access public
@ -2322,7 +2350,75 @@ class Net_SSH2 {
}
$channel = $this->in_request_pty_exec ? NET_SSH2_CHANNEL_EXEC : NET_SSH2_CHANNEL_SHELL;
return $this->_send_channel_packet($channel, $cmd);
return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
}
/**
* Start a subsystem.
*
* Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept
* a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened.
* To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and
* returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented
* if there's sufficient demand for such a feature.
*
* @see Net_SSH2::stopSubsystem()
* @param String $subsystem
* @return Boolean
* @access public
*/
function startSubsystem($subsystem)
{
$this->window_size_server_to_client[NET_SSH2_CHANNEL_SUBSYSTEM] = $this->window_size;
$packet = pack('CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SUBSYSTEM, $this->window_size, 0x4000);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM);
if ($response === false) {
return false;
}
$packet = pack('CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM], strlen('subsystem'), 'subsystem', 1, strlen($subsystem), $subsystem);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM);
if ($response === false) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA;
$this->bitmap |= NET_SSH2_MASK_SHELL;
$this->in_subsystem = true;
return true;
}
/**
* Stops a subsystem.
*
* @see Net_SSH2::startSubsystem()
* @return Boolean
* @access public
*/
function stopSubsystem()
{
$this->in_subsystem = false;
$this->_close_channel(NET_SSH2_CHANNEL_SUBSYSTEM);
return true;
}
/**