From 99a21278564d7a842e4029732847869fe2b5c68a Mon Sep 17 00:00:00 2001 From: terrafrost Date: Thu, 17 Nov 2016 20:54:38 -0600 Subject: [PATCH 01/18] Hash: fix E_NOTICE with PHP4-style constructor --- phpseclib/Crypt/Hash.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpseclib/Crypt/Hash.php b/phpseclib/Crypt/Hash.php index ca421ace..faa17c57 100644 --- a/phpseclib/Crypt/Hash.php +++ b/phpseclib/Crypt/Hash.php @@ -178,7 +178,7 @@ class Crypt_Hash */ function Crypt_Hash($hash = 'sha1') { - $this->__construct($mode); + $this->__construct($hash); } /** From 8b4208ee60407efe3d13753eb92d0a41dda613d5 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Fri, 18 Nov 2016 20:37:08 -0600 Subject: [PATCH 02/18] SFTP: logging didn't work correctly in 2.0 branch --- phpseclib/Net/SFTP.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 053ad3b7..15aabc6d 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -2792,13 +2792,13 @@ class SFTP extends SSH2 if (defined('NET_SFTP_LOGGING')) { $packet_type = '-> ' . $this->packet_types[$type] . ' (' . round($stop - $start, 4) . 's)'; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) { + if (NET_SFTP_LOGGING == self::LOG_REALTIME) { echo "
\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n
\r\n"; flush(); ob_flush(); } else { $this->packet_type_log[] = $packet_type; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) { + if (NET_SFTP_LOGGING == self::LOG_COMPLEX) { $this->packet_log[] = $data; } } @@ -2868,13 +2868,13 @@ class SFTP extends SSH2 if (defined('NET_SFTP_LOGGING')) { $packet_type = '<- ' . $this->packet_types[$this->packet_type] . ' (' . round($stop - $start, 4) . 's)'; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) { + if (NET_SFTP_LOGGING == self::LOG_REALTIME) { echo "
\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n
\r\n"; flush(); ob_flush(); } else { $this->packet_type_log[] = $packet_type; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) { + if (NET_SFTP_LOGGING == self::LOG_COMPLEX) { $this->packet_log[] = $packet; } } @@ -2898,10 +2898,10 @@ class SFTP extends SSH2 } switch (NET_SFTP_LOGGING) { - case NET_SFTP_LOG_COMPLEX: + case self::LOG_COMPLEX: return $this->_format_log($this->packet_log, $this->packet_type_log); break; - //case NET_SFTP_LOG_SIMPLE: + //case self::LOG_SIMPLE: default: return $this->packet_type_log; } @@ -2956,4 +2956,4 @@ class SFTP extends SSH2 $this->pwd = false; parent::_disconnect($reason); } -} +} \ No newline at end of file From 51bafdebe2529b09710451b8dda5dab78d6b5f11 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Fri, 18 Nov 2016 20:48:01 -0600 Subject: [PATCH 03/18] SFTP: CS adjustment --- phpseclib/Net/SFTP.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 15aabc6d..affabedc 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -2956,4 +2956,4 @@ class SFTP extends SSH2 $this->pwd = false; parent::_disconnect($reason); } -} \ No newline at end of file +} From b70cb8764179060dff71969b1a41f7df76f0b3b6 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 19 Nov 2016 20:39:05 -0600 Subject: [PATCH 04/18] SFTP: don't delete directory if $path is empty --- phpseclib/Net/SFTP.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index a279bdfb..d5404994 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -2237,6 +2237,10 @@ class Net_SFTP extends Net_SSH2 return false; } + if (empty($path)) { + return false; + } + $path = $this->_realpath($path); if ($path === false) { return false; From 48cf16599b4bda669ec3d69f16ffd2c3e4c52c3c Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 22 Oct 2016 22:13:17 -0500 Subject: [PATCH 05/18] suppress unpack() PHP warnings --- phpseclib/Net/SCP.php | 3 + phpseclib/Net/SFTP.php | 90 +++++++++++++++++- phpseclib/Net/SSH1.php | 27 +++++- phpseclib/Net/SSH2.php | 203 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 320 insertions(+), 3 deletions(-) diff --git a/phpseclib/Net/SCP.php b/phpseclib/Net/SCP.php index 83ae5cc8..354acea1 100644 --- a/phpseclib/Net/SCP.php +++ b/phpseclib/Net/SCP.php @@ -335,6 +335,9 @@ class Net_SCP $response = $this->ssh->_get_binary_packet(); switch ($response[NET_SSH1_RESPONSE_TYPE]) { case NET_SSH1_SMSG_STDOUT_DATA: + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) { + return false; + } extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA])); return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length); case NET_SSH1_SMSG_STDERR_DATA: diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index a279bdfb..776247bb 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -527,11 +527,20 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nversion', $this->_string_shift($response, 4))); $this->version = $version; while (!empty($response)) { + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $key = $this->_string_shift($response, $length); + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $value = $this->_string_shift($response, $length); $this->extensions[$key] = $value; @@ -642,12 +651,15 @@ class Net_SFTP extends Net_SSH2 function _logError($response, $status = -1) { if ($status == -1) { + if (strlen($response) < 4) { + return; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); } $error = $this->status_codes[$status]; - if ($this->version > 2) { + if ($this->version > 2 || strlen($response) < 4) { extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length); } else { @@ -696,6 +708,9 @@ class Net_SFTP extends Net_SSH2 // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks // at is the first part and that part is defined the same in SFTP versions 3 through 6. $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); return $this->_string_shift($response, $length); case NET_SFTP_STATUS: @@ -930,10 +945,19 @@ class Net_SFTP extends Net_SSH2 $response = $this->_get_sftp_packet(); switch ($this->packet_type) { case NET_SFTP_NAME: + if (strlen($response) < 4) { + return false; + } extract(unpack('Ncount', $this->_string_shift($response, 4))); for ($i = 0; $i < $count; $i++) { + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $shortname = $this->_string_shift($response, $length); + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $longname = $this->_string_shift($response, $length); $attributes = $this->_parseAttributes($response); @@ -960,6 +984,9 @@ class Net_SFTP extends Net_SSH2 } break; case NET_SFTP_STATUS: + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_EOF) { $this->_logError($response, $status); @@ -1554,6 +1581,9 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -1666,12 +1696,18 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Ncount', $this->_string_shift($response, 4))); // the file isn't a symlink if (!$count) { return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); return $this->_string_shift($response, $length); } @@ -1706,6 +1742,9 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -1769,6 +1808,9 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -1806,6 +1848,9 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED? @@ -2033,6 +2078,9 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -2064,6 +2112,9 @@ class Net_SFTP extends Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -2254,6 +2305,9 @@ class Net_SFTP extends Net_SSH2 } // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -2679,6 +2733,9 @@ class Net_SFTP extends Net_SSH2 } // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED + if (strlen($response) < 4) { + return false; + } extract(unpack('Nstatus', $this->_string_shift($response, 4))); if ($status != NET_SFTP_STATUS_OK) { $this->_logError($response, $status); @@ -2706,6 +2763,10 @@ class Net_SFTP extends Net_SSH2 function _parseAttributes(&$response) { $attr = array(); + if (strlen($response) < 4) { + user_error('Malformed file attributes'); + return array(); + } extract(unpack('Nflags', $this->_string_shift($response, 4))); // SFTPv4+ have a type field (a byte) that follows the above flag field foreach ($this->attributes as $key => $value) { @@ -2720,9 +2781,17 @@ class Net_SFTP extends Net_SSH2 $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8))); break; case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) + if (strlen($response) < 8) { + user_error('Malformed file attributes'); + return $attr; + } $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); break; case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004 + if (strlen($response) < 4) { + user_error('Malformed file attributes'); + return $attr; + } $attr+= unpack('Npermissions', $this->_string_shift($response, 4)); // mode == permissions; permissions was the original array key and is retained for bc purposes. // mode was added because that's the more industry standard terminology @@ -2733,13 +2802,29 @@ class Net_SFTP extends Net_SSH2 } break; case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008 + if (strlen($response) < 8) { + user_error('Malformed file attributes'); + return $attr; + } $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8)); break; case NET_SFTP_ATTR_EXTENDED: // 0x80000000 + if (strlen($response) < 4) { + user_error('Malformed file attributes'); + return $attr; + } extract(unpack('Ncount', $this->_string_shift($response, 4))); for ($i = 0; $i < $count; $i++) { + if (strlen($response) < 4) { + user_error('Malformed file attributes'); + return $attr; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $key = $this->_string_shift($response, $length); + if (strlen($response) < 4) { + user_error('Malformed file attributes'); + return $attr; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $attr[$key] = $this->_string_shift($response, $length); } @@ -2893,6 +2978,9 @@ class Net_SFTP extends Net_SSH2 } $this->packet_buffer.= $temp; } + if (strlen($this->packet_buffer) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4))); $tempLength = $length; $tempLength-= strlen($this->packet_buffer); diff --git a/phpseclib/Net/SSH1.php b/phpseclib/Net/SSH1.php index fb23daa6..55473d08 100644 --- a/phpseclib/Net/SSH1.php +++ b/phpseclib/Net/SSH1.php @@ -614,20 +614,32 @@ class Net_SSH1 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) { + return false; + } $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->server_key_public_exponent = $server_key_public_exponent; + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) { + return false; + } $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->server_key_public_modulus = $server_key_public_modulus; $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) { + return false; + } $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->host_key_public_exponent = $host_key_public_exponent; + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) { + return false; + } $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->host_key_public_modulus = $host_key_public_modulus; @@ -635,6 +647,9 @@ class Net_SSH1 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); // get a list of the supported ciphers + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) { + return false; + } extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); foreach ($this->supported_ciphers as $mask => $name) { if (($supported_ciphers_mask & (1 << $mask)) == 0) { @@ -643,6 +658,9 @@ class Net_SSH1 } // get a list of the supported authentications + if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) { + return false; + } extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); foreach ($this->supported_authentications as $mask => $name) { if (($supported_authentications_mask & (1 << $mask)) == 0) { @@ -1139,7 +1157,11 @@ class Net_SSH1 } $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $temp = unpack('Nlength', fread($this->fsock, 4)); + $data = fread($this->fsock, 4); + if (strlen($data) < 4) { + return false; + } + $temp = unpack('Nlength', $data); $padding_length = 8 - ($temp['length'] & 7); $length = $temp['length'] + $padding_length; @@ -1160,6 +1182,9 @@ class Net_SSH1 $type = $raw[$padding_length]; $data = substr($raw, $padding_length + 1, -4); + if (strlen($raw) < 4) { + return false; + } $temp = unpack('Ncrc', substr($raw, -4)); //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) { diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 8281e73a..14bcf9a5 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -1124,7 +1124,7 @@ class Net_SSH2 return false; } - if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { + if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) { user_error('Expected SSH_MSG_KEXINIT'); return false; } @@ -1313,36 +1313,69 @@ class Net_SSH2 $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT) $server_cookie = $this->_string_shift($response, 16); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); + if (!strlen($response)) { + return false; + } extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1))); $first_kex_packet_follows = $first_kex_packet_follows != 0; @@ -1426,16 +1459,25 @@ class Net_SSH2 user_error('Connection closed by server'); return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) { user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP'); return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('NprimeLength', $this->_string_shift($response, 4))); $primeBytes = $this->_string_shift($response, $primeLength); $prime = new Math_BigInteger($primeBytes, -256); + if (strlen($response) < 4) { + return false; + } extract(unpack('NgLength', $this->_string_shift($response, 4))); $gBytes = $this->_string_shift($response, $gLength); $g = new Math_BigInteger($gBytes, -256); @@ -1518,6 +1560,9 @@ class Net_SSH2 user_error('Connection closed by server'); return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != $serverKexReplyMessage) { @@ -1525,19 +1570,34 @@ class Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']); + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $fBytes = $this->_string_shift($response, $temp['length']); $f = new Math_BigInteger($fBytes, -256); + if (strlen($response) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->signature = $this->_string_shift($response, $temp['length']); + if (strlen($this->signature) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); $this->signature_format = $this->_string_shift($this->signature, $temp['length']); @@ -1598,6 +1658,9 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_NEWKEYS) { @@ -2030,6 +2093,9 @@ class Net_SSH2 return false; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { @@ -2083,6 +2149,9 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { @@ -2138,6 +2207,9 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { @@ -2145,14 +2217,23 @@ class Net_SSH2 if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; } + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_FAILURE: // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees // multi-factor authentication + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $auth_methods = explode(',', $this->_string_shift($response, $length)); + if (!strlen($response)) { + return false; + } extract(unpack('Cpartial_success', $this->_string_shift($response, 1))); $partial_success = $partial_success != 0; @@ -2227,16 +2308,31 @@ class Net_SSH2 } } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); // name; may be empty + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); // instruction; may be empty + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); // language tag; may be empty + if (strlen($response) < 4) { + return false; + } extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); for ($i = 0; $i < count($responses); $i++) { @@ -2251,6 +2347,9 @@ class Net_SSH2 if (isset($this->keyboard_requests_responses)) { for ($i = 0; $i < $num_prompts; $i++) { + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); // prompt - ie. "Password: "; must not be empty $prompt = $this->_string_shift($response, $length); @@ -2396,10 +2495,16 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); return false; @@ -2431,6 +2536,9 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { @@ -2549,6 +2657,9 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } list(, $type) = unpack('C', $this->_string_shift($response, 1)); switch ($type) { @@ -2686,6 +2797,9 @@ class Net_SSH2 return false; } + if (!strlen($response)) { + return false; + } list(, $type) = unpack('C', $this->_string_shift($response, 1)); switch ($type) { @@ -3021,6 +3135,9 @@ class Net_SSH2 return false; } + if (strlen($raw) < 5) { + return false; + } extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5))); $remaining_length = $packet_length + 4 - $this->decrypt_block_size; @@ -3096,6 +3213,9 @@ class Net_SSH2 switch (ord($payload[0])) { case NET_SSH2_MSG_DISCONNECT: $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" . utf8_decode($this->_string_shift($payload, $length)); $this->bitmap = 0; @@ -3105,6 +3225,9 @@ class Net_SSH2 break; case NET_SSH2_MSG_DEBUG: $this->_string_shift($payload, 2); + if (strlen($payload) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); @@ -3124,6 +3247,9 @@ class Net_SSH2 // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); + if (strlen($payload) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->banner_message = utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); @@ -3133,6 +3259,9 @@ class Net_SSH2 if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 + if (strlen($payload) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length); @@ -3144,8 +3273,14 @@ class Net_SSH2 break; case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 $this->_string_shift($payload, 1); + if (strlen($payload) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($payload, 4))); $data = $this->_string_shift($payload, $length); + if (strlen($payload) < 4) { + return false; + } extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); switch ($data) { case 'auth-agent': @@ -3153,6 +3288,9 @@ class Net_SSH2 if (isset($this->agent)) { $new_channel = NET_SSH2_CHANNEL_AGENT_FORWARD; + if (strlen($payload) < 8) { + return false; + } extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4))); extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4))); @@ -3198,6 +3336,9 @@ class Net_SSH2 break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: $this->_string_shift($payload, 1); + if (strlen($payload) < 8) { + return false; + } extract(unpack('Nchannel', $this->_string_shift($payload, 4))); extract(unpack('Nwindow_size', $this->_string_shift($payload, 4))); $this->window_size_client_to_server[$channel]+= $window_size; @@ -3330,8 +3471,14 @@ class Net_SSH2 return ''; } + if (!strlen($response)) { + return false; + } extract(unpack('Ctype', $this->_string_shift($response, 1))); + if (strlen($response) < 4) { + return false; + } if ($type == NET_SSH2_MSG_CHANNEL_OPEN) { extract(unpack('Nlength', $this->_string_shift($response, 4))); } else { @@ -3355,14 +3502,23 @@ class Net_SSH2 case NET_SSH2_MSG_CHANNEL_OPEN: switch ($type) { case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: + if (strlen($response) < 4) { + return false; + } extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); $this->server_channels[$channel] = $server_channel; + if (strlen($response) < 4) { + return false; + } extract(unpack('Nwindow_size', $this->_string_shift($response, 4))); if ($window_size < 0) { $window_size&= 0x7FFFFFFF; $window_size+= 0x80000000; } $this->window_size_client_to_server[$channel] = $window_size; + if (strlen($response) < 4) { + return false; + } $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']; $result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended); @@ -3402,6 +3558,9 @@ class Net_SSH2 $this->_send_channel_packet($channel, chr(0)); } */ + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $data = $this->_string_shift($response, $length); @@ -3428,6 +3587,9 @@ class Net_SSH2 } */ // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR + if (strlen($response) < 8) { + return false; + } extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); $this->stdErrorLog.= $data; @@ -3443,14 +3605,23 @@ class Net_SSH2 $this->channel_buffers[$channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_REQUEST: + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $value = $this->_string_shift($response, $length); switch ($value) { case 'exit-signal': $this->_string_shift($response, 1); + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length); $this->_string_shift($response, 1); + if (strlen($response) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($response, 4))); if ($length) { $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length); @@ -3463,6 +3634,9 @@ class Net_SSH2 break; case 'exit-status': + if (strlen($response) < 5) { + return false; + } extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5))); $this->exit_status = $exit_status; @@ -4091,6 +4265,9 @@ class Net_SSH2 $signature = $this->signature; $server_public_host_key = $this->server_public_host_key; + if (strlen($server_public_host_key) < 4) { + return false; + } extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); $this->_string_shift($server_public_host_key, $length); @@ -4106,15 +4283,27 @@ class Net_SSH2 case 'ssh-dss': $zero = new Math_BigInteger(); + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); @@ -4161,15 +4350,24 @@ class Net_SSH2 break; case 'ssh-rsa': + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); + if (strlen($server_public_host_key) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $rawN = $this->_string_shift($server_public_host_key, $temp['length']); $n = new Math_BigInteger($rawN, -256); $nLength = strlen(ltrim($rawN, "\0")); /* + if (strlen($signature) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($signature, 4)); $signature = $this->_string_shift($signature, $temp['length']); @@ -4186,6 +4384,9 @@ class Net_SSH2 } */ + if (strlen($signature) < 4) { + return false; + } $temp = unpack('Nlength', $this->_string_shift($signature, 4)); $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256); From 7cb66ea56efd02bcf82c5933c84071a37121dcd5 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sun, 20 Nov 2016 11:08:53 -0600 Subject: [PATCH 06/18] SSH2: don't use timeout value of 0 for fsockopen --- phpseclib/Net/SSH2.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 12741c73..712656bd 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -1040,7 +1040,10 @@ class Net_SSH2 if (!is_resource($this->fsock)) { $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout); + // with stream_select a timeout of 0 means that no timeout takes place; + // with fsockopen a timeout of 0 means that you instantly timeout + // to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0 + $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout); if (!$this->fsock) { $host = $this->host . ':' . $this->port; user_error(rtrim("Cannot connect to $host. Error $errno. $errstr")); From a2d9622bf9644f85644546bb75504a2992756bb6 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sun, 20 Nov 2016 18:03:01 -0600 Subject: [PATCH 07/18] SFTP: update directory deletion check (#1059) --- phpseclib/Net/SFTP.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index d5404994..43ad4f54 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -2237,7 +2237,12 @@ class Net_SFTP extends Net_SSH2 return false; } - if (empty($path)) { + if (is_object($path)) { + // It's an object. Cast it as string before we check anything else. + $path = (string) $path; + } + + if (!is_string($path) || $path == '') { return false; } From 6fb34887c5bf06f5757f35d341bd0e79f5a017d7 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sun, 20 Nov 2016 18:13:01 -0600 Subject: [PATCH 08/18] SFTP: change queue size to 32 (max packet size is 32kb so 32*32=1M) --- phpseclib/Net/SFTP.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 43ad4f54..a3fc89f5 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -413,7 +413,7 @@ class Net_SFTP extends Net_SSH2 ); if (!defined('NET_SFTP_QUEUE_SIZE')) { - define('NET_SFTP_QUEUE_SIZE', 50); + define('NET_SFTP_QUEUE_SIZE', 32); } } From b26f14e5feab0f7181f44a7a94772a7b80bc8e0f Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 17 Dec 2016 16:09:48 -0600 Subject: [PATCH 09/18] SSH2: make it so disabling PTY closes exec() channel if it's open --- phpseclib/Net/SSH2.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 8bf9a805..68de7fbc 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -2601,6 +2601,11 @@ class Net_SSH2 return false; } + if ($this->in_request_pty_exec) { + user_error('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.'); + return false; + } + // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but, // honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway. @@ -3408,6 +3413,10 @@ class Net_SSH2 */ function disablePTY() { + if ($this->in_request_pty_exec) { + $this->_close_channel(NET_SSH2_CHANNEL_EXEC); + $this->in_request_pty_exec = false; + } $this->request_pty = false; } From d80794b1d9d152b8840ab425ccfe8ccea9b6418e Mon Sep 17 00:00:00 2001 From: vladimirghetau Date: Fri, 16 Dec 2016 16:27:56 +0000 Subject: [PATCH 10/18] exec authentication, code reuse --- phpseclib/Net/SSH2.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 8bf9a805..87206dfb 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -2597,7 +2597,7 @@ class Net_SSH2 $this->is_timeout = false; $this->stdErrorLog = ''; - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + if (!$this->isAuthenticated()) { return false; } @@ -2896,7 +2896,7 @@ class Net_SSH2 $this->curTimeout = $this->timeout; $this->is_timeout = false; - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + if (!$this->isAuthenticated()) { user_error('Operation disallowed prior to login()'); return false; } @@ -2938,7 +2938,7 @@ class Net_SSH2 */ function write($cmd) { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + if (!$this->isAuthenticated()) { user_error('Operation disallowed prior to login()'); return false; } @@ -3248,7 +3248,7 @@ class Net_SSH2 } // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in - if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { + if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); if (strlen($payload) < 4) { return false; @@ -3259,7 +3259,7 @@ class Net_SSH2 } // only called when we've already logged in - if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { + if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && $this->isAuthenticated()) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 if (strlen($payload) < 4) { From da6e5211df61196a370d943b0f44f4d1fda488ef Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 17 Dec 2016 17:41:56 -0600 Subject: [PATCH 11/18] X509: ignore certificate transparency extension --- phpseclib/File/X509.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpseclib/File/X509.php b/phpseclib/File/X509.php index 040551f0..932262a0 100644 --- a/phpseclib/File/X509.php +++ b/phpseclib/File/X509.php @@ -1939,6 +1939,9 @@ class File_X509 // "SET Secure Electronic Transaction Specification" // http://www.maithean.com/docs/set_bk3.pdf case '2.23.42.7.0': // id-set-hashedRootKey + // "Certificate Transparency" + // https://tools.ietf.org/html/rfc6962 + case '1.3.6.1.4.1.11129.2.4.2': return true; // CSR attributes From 3cebd4ec5918927563dad08621a9cc942e891910 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 18 Dec 2016 10:32:35 +0100 Subject: [PATCH 12/18] README: Update Coverage and API URLs. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 75089a01..64dcc711 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 * [Download (1.0.5)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.5.zip/download) * [Browse Git](https://github.com/phpseclib/phpseclib) -* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/1.0/latest/) +* [Code Coverage Report](https://coverage.phpseclib.org/1.0/latest/) PEAR Channel PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm) @@ -16,7 +16,7 @@ PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear. ## Documentation * [Documentation / Manual](http://phpseclib.sourceforge.net/) -* [API Documentation](http://phpseclib.bantux.org/api/1.0/) (generated by Sami) +* [API Documentation](https://api.phpseclib.org/1.0/) (generated by Sami) ## Support From d0d26cd29fb1e769a2af1bad6107d99bdff8bcb8 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 18 Dec 2016 10:38:28 +0100 Subject: [PATCH 13/18] README: Remove pipe into php. --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 64dcc711..b265fd35 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,12 @@ Need Support? Dependencies are managed via Composer. -1. Download the [`composer.phar`](https://getcomposer.org/composer.phar) executable as per the - [Composer Download Instructions](https://getcomposer.org/download/), e.g. by running - - ``` sh - curl -sS https://getcomposer.org/installer | php - ``` +1. Install Composer (see [Composer Download Instructions](https://getcomposer.org/download/)) 2. Install Dependencies ``` sh - php composer.phar install + composer install ``` ## Contributing From bd5b8809e8b270c8f8f76780dcf885c7578e32ce Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 18 Dec 2016 10:40:24 +0100 Subject: [PATCH 14/18] README: Merge 'Installing Development Dependencies' into 'Contributing'. --- README.md | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b265fd35..e510e437 100644 --- a/README.md +++ b/README.md @@ -26,35 +26,29 @@ Need Support? * [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new) * [Browse the Support Forum](http://www.frostjedi.com/phpbb/viewforum.php?f=46) (no longer in use) -## Installing Development Dependencies +## Contributing -Dependencies are managed via Composer. +1. Fork the Project -1. Install Composer (see [Composer Download Instructions](https://getcomposer.org/download/)) +2. Ensure you have Composer installed (see [Composer Download Instructions](https://getcomposer.org/download/)) -2. Install Dependencies +3. Install Development Dependencies ``` sh composer install ``` -## Contributing +4. Create a Feature Branch -1. Fork the Project - -2. Install Development Dependencies - -3. Create a Feature Branch - -4. (Recommended) Run the Test Suite +5. (Recommended) Run the Test Suite ``` sh vendor/bin/phpunit ``` -5. (Recommended) Check whether your code conforms to our Coding Standards by running +6. (Recommended) Check whether your code conforms to our Coding Standards by running ``` sh vendor/bin/phing -f build/build.xml sniff ``` -6. Send us a Pull Request +7. Send us a Pull Request From 804cade3c08f3bd0ce8e03fa427fb560c04c4239 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 18 Dec 2016 11:02:41 +0100 Subject: [PATCH 15/18] README: Add branches section. --- README.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e510e437..dfaa909d 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,38 @@ MIT-licensed pure-PHP implementations of an arbitrary-precision integer arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael, AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 -* [Download (1.0.5)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.5.zip/download) * [Browse Git](https://github.com/phpseclib/phpseclib) * [Code Coverage Report](https://coverage.phpseclib.org/1.0/latest/) -PEAR Channel -PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm) - ## Documentation * [Documentation / Manual](http://phpseclib.sourceforge.net/) * [API Documentation](https://api.phpseclib.org/1.0/) (generated by Sami) +## Branches + +### master + +* Development Branch +* Unstable API +* Do not use in production + +### 2.0 + +* Modernized version of 1.0 +* Minimum PHP version: 5.3.3 +* PSR-4 autoloading with namespace rooted at `\phpseclib` +* Install via Composer: `composer requite phpseclib/phpseclib ~2.0` + +### 1.0 + +* Long term support (LTS) release +* PHP4 compatible +* Composer compatible (PSR-0 autoloading) +* Install via Composer: `composer require phpseclib/phpseclib ~1.0` +* PEAR Channel PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm) +* [Download 1.0.5 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.5.zip/download) + ## Support Need Support? From c7390e26f509d0659f555ccad3909bd808342992 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 18 Dec 2016 11:08:04 +0100 Subject: [PATCH 16/18] README: Reword 1.0 PEAR installation instructions. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dfaa909d..bf35a206 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 * Long term support (LTS) release * PHP4 compatible * Composer compatible (PSR-0 autoloading) -* Install via Composer: `composer require phpseclib/phpseclib ~1.0` -* PEAR Channel PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm) +* Install using Composer: `composer require phpseclib/phpseclib ~1.0` +' Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm) * [Download 1.0.5 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.5.zip/download) ## Support From 95335f95608a152c1490e3c3e3086eaa86eb93e5 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 24 Dec 2016 21:20:13 -0600 Subject: [PATCH 17/18] SSH2: update PTY changes for 2.0 branch --- phpseclib/Net/SSH2.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index ed506c29..b6aed420 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -3312,7 +3312,7 @@ class SSH2 function disablePTY() { if ($this->in_request_pty_exec) { - $this->_close_channel(NET_SSH2_CHANNEL_EXEC); + $this->_close_channel(self::CHANNEL_EXEC); $this->in_request_pty_exec = false; } $this->request_pty = false; From a0e6bd87f237ef2d5f7e9c8af73ec88d8c6b044e Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 25 Dec 2016 16:09:17 +0100 Subject: [PATCH 18/18] README: Fix typos. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bf35a206..305c1c3e 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 * Modernized version of 1.0 * Minimum PHP version: 5.3.3 * PSR-4 autoloading with namespace rooted at `\phpseclib` -* Install via Composer: `composer requite phpseclib/phpseclib ~2.0` +* Install via Composer: `composer require phpseclib/phpseclib ~2.0` ### 1.0 @@ -35,7 +35,7 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 * PHP4 compatible * Composer compatible (PSR-0 autoloading) * Install using Composer: `composer require phpseclib/phpseclib ~1.0` -' Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm) +* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm) * [Download 1.0.5 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.5.zip/download) ## Support