moved agent forwarding channel handling to filter method and reusing existing open channels to request forwarding

This commit is contained in:
montdidier 2015-02-06 11:28:23 +08:00
parent 25b328c440
commit 1803bcac0b
2 changed files with 111 additions and 73 deletions

View File

@ -99,8 +99,7 @@ define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020);
define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
define('NET_SSH2_CHANNEL_SHELL', 1);
define('NET_SSH2_CHANNEL_SUBSYSTEM', 2);
define('NET_SSH2_CHANNEL_AGENT_REQUEST', 3);
define('NET_SSH2_CHANNEL_AGENT_FORWARD', 4);
define('NET_SSH2_CHANNEL_AGENT_FORWARD', 3);
/**#@-*/
/**#@+
@ -2146,7 +2145,6 @@ class Net_SSH2
$keys = $agent->requestIdentities();
foreach ($keys as $key) {
if ($this->_privatekey_login($username, $key)) {
$this->agent->_on_login_success($this);
return true;
}
}
@ -2491,6 +2489,24 @@ class Net_SSH2
}
}
/**
* Return an available open channel
*
* @return Integer
* @access public
*/
function _get_open_channel()
{
$channel = NET_SSH2_CHANNEL_EXEC;
do {
if (array_key_exists($channel, $this->channel_status) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
return $channel;
}
} while ($channel++ < NET_SSH2_CHANNEL_SUBSYSTEM);
user_error("Unable to find an open channel");
}
/**
* Returns the output of an interactive shell
*
@ -2844,6 +2860,45 @@ class Net_SSH2
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
$payload = $this->_get_binary_packet();
break;
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
$this->_string_shift($payload, 1);
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$data = $this->_string_shift($payload, $length);
extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
switch($data) {
case 'auth-agent':
case 'auth-agent@openssh.com':
if (isset($this->agent)) {
$new_channel = NET_SSH2_CHANNEL_AGENT_FORWARD;
extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4)));
extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4)));
$this->packet_size_client_to_server[$new_channel] = $remote_window_size;
$this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
$this->window_size_client_to_server[$new_channel] = $this->window_size;
$packet_size = 0x4000;
$packet = pack('CN4',
NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, $server_channel, $new_channel, $packet_size, $packet_size);
$this->server_channels[$new_channel] = $server_channel;
$this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
if (!$this->_send_binary_packet($packet)) {
return false;
}
}
default:
$packet = pack('CN3a*Na*',
NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, '');
if (!$this->_send_binary_packet($packet)) {
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
$payload = $this->_get_binary_packet();
break;
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
@ -3011,7 +3066,9 @@ class Net_SSH2
$this->window_size_client_to_server[$channel] = $window_size;
$temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
$this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server'];
return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
$result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
$this->_on_channel_open();
return $result;
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
default:
user_error('Unable to open channel');
@ -3036,41 +3093,6 @@ class Net_SSH2
// ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA
switch ($type) {
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
$data = $this->_string_shift($response, $length);
switch($data) {
case 'auth-agent':
case 'auth-agent@openssh.com':
if (!isset($this->agent)) {
break 2;
}
break;
default:
break 2;
}
$new_channel = NET_SSH2_CHANNEL_AGENT_FORWARD;
extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
extract(unpack('Nremote_window_size', $this->_string_shift($response, 4)));
extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($response, 4)));
$this->packet_size_client_to_server[$new_channel] = $remote_window_size;
$this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
$this->window_size_client_to_server[$new_channel] = $this->window_size;
$packet_size = 0x4000;
$packet = pack('CN4',
NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, $server_channel, $new_channel, $packet_size, $packet_size);
$this->server_channels[$new_channel] = $server_channel;
$this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
if (!$this->_send_binary_packet($packet)) {
return false;
}
break;
case NET_SSH2_MSG_CHANNEL_DATA:
/*
if ($channel == NET_SSH2_CHANNEL_EXEC) {
@ -3528,6 +3550,22 @@ class Net_SSH2
return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
}
/**
* Helper function for agent->_on_channel_open()
*
* Used when channels are created to inform agent
* of said channel opening. Must be called after
* channel open confirmation received
*
* @access private
*/
function _on_channel_open()
{
if (isset($this->agent)) {
$this->agent->_on_channel_open($this);
}
}
/**
* Returns all errors
*

View File

@ -64,6 +64,20 @@ define('SYSTEM_SSH_AGENT_FAILURE', 5);
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
/**@+
* Agent forwarding status
*
* @access private
*/
// no forwarding requested and not active
define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
// request agent forwarding when opportune
define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
// forwarding has been request and is active
define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
/**#@-*/
/**
@ -227,11 +241,11 @@ class System_SSH_Agent
var $fsock;
/**
* Did we request agent forwarding
* Agent forwarding status
*
* @access private
*/
var $request_forwarding;
var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
/**
* Buffer for accumulating forwarded authentication
@ -336,7 +350,8 @@ class System_SSH_Agent
}
/**
* Request the remote server to forward authentication requests to the local SSH agent
* Signal that agent forwarding should
* be requested when a channel is opened
*
* @param Net_SSH2 $ssh
* @return Boolean
@ -344,16 +359,13 @@ class System_SSH_Agent
*/
function startSSHForwarding($ssh)
{
if (!$this->request_forwarding) {
$this->request_forwarding = true;
$this->_request_forwarding($ssh);
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
}
}
/**
* The worker function to make a request to a remote server
* asking it to forward authentication requests to the local SSH
* agent
* Request agent forwarding of remote server
*
* @param Net_SSH2 $ssh
* @return Boolean
@ -361,53 +373,41 @@ class System_SSH_Agent
*/
function _request_forwarding($ssh)
{
$ssh->window_size_server_to_client[NET_SSH2_CHANNEL_AGENT_REQUEST] = $ssh->window_size;
$packet_size = 0x4000;
$packet = pack('CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_AGENT_REQUEST, $ssh->window_size_server_to_client[NET_SSH2_CHANNEL_AGENT_REQUEST], $packet_size);
$ssh->channel_status[NET_SSH2_CHANNEL_AGENT_REQUEST] = NET_SSH2_MSG_CHANNEL_OPEN;
if (!$ssh->_send_binary_packet($packet)) {
return false;
}
$response = $ssh->_get_channel_packet(NET_SSH2_CHANNEL_AGENT_REQUEST);
if ($response === false) {
return false;
}
$request_channel = $ssh->_get_open_channel();
$packet = pack('CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST, $ssh->server_channels[NET_SSH2_CHANNEL_AGENT_REQUEST], strlen('auth-agent-req@openssh.com'), 'auth-agent-req@openssh.com', 1);
NET_SSH2_MSG_CHANNEL_REQUEST, $ssh->server_channels[$request_channel], strlen('auth-agent-req@openssh.com'), 'auth-agent-req@openssh.com', 1);
$ssh->channel_status[NET_SSH2_CHANNEL_AGENT_REQUEST] = NET_SSH2_MSG_CHANNEL_REQUEST;
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$ssh->_send_binary_packet($packet)) {
return false;
}
$response = $ssh->_get_channel_packet(NET_SSH2_CHANNEL_AGENT_REQUEST);
$response = $ssh->_get_channel_packet($request_channel);
if ($response === false) {
return false;
}
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
return true;
}
/**
* On Successful Login
* On successful channel open
*
* This method should be called upon successful SSH login if you
* wish to give the SSH Agent an opportunity to take further
* action. i.e. request agent forwarding
* This method is called upon successful channel
* open to give the SSH Agent an opportunity
* to take further action. i.e. request agent forwarding
*
* @param Net_SSH2 $ssh
* @access private
*/
function _on_login_success($ssh)
function _on_channel_open($ssh)
{
if ($this->request_forwarding) {
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
$this->_request_forwarding($ssh);
}
}