mirror of
https://github.com/phpseclib/phpseclib.git
synced 2025-02-05 05:18:28 +00:00
Merge branch '1.0' into 2.0
This commit is contained in:
commit
0b9fd56b6f
@ -146,6 +146,10 @@ class SSH2
|
|||||||
* Dumps the content real-time to a file
|
* Dumps the content real-time to a file
|
||||||
*/
|
*/
|
||||||
const LOG_REALTIME_FILE = 4;
|
const LOG_REALTIME_FILE = 4;
|
||||||
|
/**
|
||||||
|
* Dumps the message numbers real-time
|
||||||
|
*/
|
||||||
|
const LOG_REALTIME_SIMPLE = 5;
|
||||||
/**
|
/**
|
||||||
* Make sure that the log never gets larger than this
|
* Make sure that the log never gets larger than this
|
||||||
*/
|
*/
|
||||||
@ -1104,6 +1108,46 @@ class SSH2
|
|||||||
*/
|
*/
|
||||||
var $extra_packets;
|
var $extra_packets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytes Transferred Since Last Key Exchange
|
||||||
|
*
|
||||||
|
* Includes outbound and inbound totals
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $bytesTransferredSinceLastKEX = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After how many transferred byte should phpseclib initiate a key re-exchange?
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $doKeyReexchangeAfterXBytes = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has a key re-exchange been initialized?
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $keyExchangeInProgress = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEX Buffer
|
||||||
|
*
|
||||||
|
* If we're in the middle of a key exchange we want to buffer any additional packets we get until
|
||||||
|
* the key exchange is over
|
||||||
|
*
|
||||||
|
* @see self::_get_binary_packet()
|
||||||
|
* @see self::_key_exchange()
|
||||||
|
* @see self::exec()
|
||||||
|
* @var array
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $kex_buffer = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Constructor.
|
* Default Constructor.
|
||||||
*
|
*
|
||||||
@ -1478,8 +1522,13 @@ class SSH2
|
|||||||
*/
|
*/
|
||||||
function _key_exchange($kexinit_payload_server = false)
|
function _key_exchange($kexinit_payload_server = false)
|
||||||
{
|
{
|
||||||
|
$this->bytesTransferredSinceLastKEX = 0;
|
||||||
|
|
||||||
$preferred = $this->preferred;
|
$preferred = $this->preferred;
|
||||||
$send_kex = true;
|
// for the initial key exchange $send_kex is true (no key re-exchange has been started)
|
||||||
|
// for phpseclib initiated key exchanges $send_kex is false
|
||||||
|
$send_kex = !$this->keyExchangeInProgress;
|
||||||
|
$this->keyExchangeInProgress = true;
|
||||||
|
|
||||||
$kex_algorithms = isset($preferred['kex']) ?
|
$kex_algorithms = isset($preferred['kex']) ?
|
||||||
$preferred['kex'] :
|
$preferred['kex'] :
|
||||||
@ -1565,22 +1614,29 @@ class SSH2
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($kexinit_payload_server === false) {
|
if ($kexinit_payload_server === false && $send_kex) {
|
||||||
if (!$this->_send_binary_packet($kexinit_payload_client)) {
|
if (!$this->_send_binary_packet($kexinit_payload_client)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->extra_packets = 0;
|
while (true) {
|
||||||
$kexinit_payload_server = $this->_get_binary_packet();
|
$kexinit_payload_server = $this->_get_binary_packet();
|
||||||
if ($kexinit_payload_server === false) {
|
if ($kexinit_payload_server === false) {
|
||||||
$this->bitmap = 0;
|
$this->bitmap = 0;
|
||||||
user_error('Connection closed by server');
|
user_error('Connection closed by server');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strlen($kexinit_payload_server)) {
|
||||||
|
switch (ord($kexinit_payload_server[0])) {
|
||||||
|
case NET_SSH2_MSG_KEXINIT:
|
||||||
|
break 2;
|
||||||
|
case NET_SSH2_MSG_DISCONNECT:
|
||||||
|
return $this->_handleDisconnect($kexinit_payload_server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
|
$this->kex_buffer[] = $kexinit_payload_server;
|
||||||
user_error('Expected SSH_MSG_KEXINIT');
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$send_kex = false;
|
$send_kex = false;
|
||||||
@ -1596,7 +1652,7 @@ class SSH2
|
|||||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||||
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
||||||
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
|
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
|
||||||
if ($this->session_id === false && $this->extra_packets) {
|
if ($this->session_id === false && count($this->kex_buffer)) {
|
||||||
user_error('Possible Terrapin Attack detected');
|
user_error('Possible Terrapin Attack detected');
|
||||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||||
}
|
}
|
||||||
@ -2007,6 +2063,8 @@ class SSH2
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->keyExchangeInProgress = false;
|
||||||
|
|
||||||
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
|
if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
|
||||||
$this->get_seq_no = $this->send_seq_no = 0;
|
$this->get_seq_no = $this->send_seq_no = 0;
|
||||||
}
|
}
|
||||||
@ -3588,6 +3646,10 @@ class SSH2
|
|||||||
*/
|
*/
|
||||||
function _get_binary_packet($skip_channel_filter = false)
|
function _get_binary_packet($skip_channel_filter = false)
|
||||||
{
|
{
|
||||||
|
if (!$this->keyExchangeInProgress && count($this->kex_buffer)) {
|
||||||
|
return $this->_filter(array_shift($this->kex_buffer), $skip_channel_filter);
|
||||||
|
}
|
||||||
|
|
||||||
if ($skip_channel_filter) {
|
if ($skip_channel_filter) {
|
||||||
$read = array($this->fsock);
|
$read = array($this->fsock);
|
||||||
$write = $except = null;
|
$write = $except = null;
|
||||||
@ -3672,9 +3734,11 @@ class SSH2
|
|||||||
|
|
||||||
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
|
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
|
||||||
|
|
||||||
|
$this->bytesTransferredSinceLastKEX+= $packet_length + $padding_length + 5;
|
||||||
|
|
||||||
// quoting <http://tools.ietf.org/html/rfc4253#section-6.1>,
|
// quoting <http://tools.ietf.org/html/rfc4253#section-6.1>,
|
||||||
// "implementations SHOULD check that the packet length is reasonable"
|
// "implementations SHOULD check that the packet length is reasonable"
|
||||||
// PuTTY uses 0x9000 as the actual max packet size and so to shall we
|
// PuTTY uses 0x9000 as the actual max packet size and so, too, shall we
|
||||||
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
|
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
|
||||||
if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decryptName) && !($this->bitmap & SSH2::MASK_LOGIN)) {
|
if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decryptName) && !($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||||
$this->bad_key_size_fix = true;
|
$this->bad_key_size_fix = true;
|
||||||
@ -3764,7 +3828,34 @@ class SSH2
|
|||||||
$this->last_packet = $current;
|
$this->last_packet = $current;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_filter($payload, $skip_channel_filter);
|
if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) {
|
||||||
|
$this->_key_exchange();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't filter if we're in the middle of a key exchange (since _filter might send out packets)
|
||||||
|
return $this->keyExchangeInProgress ? $payload : $this->_filter($payload, $skip_channel_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Disconnect
|
||||||
|
*
|
||||||
|
* Because some binary packets need to be ignored...
|
||||||
|
*
|
||||||
|
* @see self::_filter()
|
||||||
|
* @see self::_key_exchange
|
||||||
|
* @return boolean
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _handleDisconnect($payload)
|
||||||
|
{
|
||||||
|
$this->_string_shift($payload, 1);
|
||||||
|
if (strlen($payload) < 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
|
||||||
|
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
|
||||||
|
$this->bitmap = 0;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3780,20 +3871,11 @@ class SSH2
|
|||||||
{
|
{
|
||||||
switch (ord($payload[0])) {
|
switch (ord($payload[0])) {
|
||||||
case NET_SSH2_MSG_DISCONNECT:
|
case NET_SSH2_MSG_DISCONNECT:
|
||||||
$this->_string_shift($payload, 1);
|
return $this->_handleDisconnect($payload);
|
||||||
if (strlen($payload) < 8) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
|
|
||||||
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
|
|
||||||
$this->bitmap = 0;
|
|
||||||
return false;
|
|
||||||
case NET_SSH2_MSG_IGNORE:
|
case NET_SSH2_MSG_IGNORE:
|
||||||
$this->extra_packets++;
|
|
||||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||||
break;
|
break;
|
||||||
case NET_SSH2_MSG_DEBUG:
|
case NET_SSH2_MSG_DEBUG:
|
||||||
$this->extra_packets++;
|
|
||||||
$this->_string_shift($payload, 2);
|
$this->_string_shift($payload, 2);
|
||||||
if (strlen($payload) < 4) {
|
if (strlen($payload) < 4) {
|
||||||
return false;
|
return false;
|
||||||
@ -3805,7 +3887,7 @@ class SSH2
|
|||||||
case NET_SSH2_MSG_UNIMPLEMENTED:
|
case NET_SSH2_MSG_UNIMPLEMENTED:
|
||||||
return false;
|
return false;
|
||||||
case NET_SSH2_MSG_KEXINIT:
|
case NET_SSH2_MSG_KEXINIT:
|
||||||
// this is here for key re-exchanges after the initial key exchange
|
// this is here for server initiated key re-exchanges after the initial key exchange
|
||||||
if ($this->session_id !== false) {
|
if ($this->session_id !== false) {
|
||||||
$this->send_kex_first = false;
|
$this->send_kex_first = false;
|
||||||
if (!$this->_key_exchange($payload)) {
|
if (!$this->_key_exchange($payload)) {
|
||||||
@ -4369,6 +4451,8 @@ class SSH2
|
|||||||
|
|
||||||
$packet.= $hmac;
|
$packet.= $hmac;
|
||||||
|
|
||||||
|
$this->bytesTransferredSinceLastKEX+= strlen($packet);
|
||||||
|
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$result = strlen($packet) == @fputs($this->fsock, $packet);
|
$result = strlen($packet) == @fputs($this->fsock, $packet);
|
||||||
$stop = microtime(true);
|
$stop = microtime(true);
|
||||||
@ -4382,6 +4466,10 @@ class SSH2
|
|||||||
$this->last_packet = $current;
|
$this->last_packet = $current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) {
|
||||||
|
$this->_key_exchange();
|
||||||
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4459,6 +4547,10 @@ class SSH2
|
|||||||
$this->realtime_log_wrap = true;
|
$this->realtime_log_wrap = true;
|
||||||
}
|
}
|
||||||
fputs($this->realtime_log_file, $entry);
|
fputs($this->realtime_log_file, $entry);
|
||||||
|
break;
|
||||||
|
case NET_SSH2_LOG_REALTIME_SIMPLE:
|
||||||
|
echo $message_number;
|
||||||
|
echo PHP_SAPI == 'cli' ? "\r\n" : '<br>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user