Merge remote-tracking branch 'upstream/master' into php5-updates

This commit is contained in:
terrafrost 2017-01-17 22:40:24 -06:00
commit a25c841108
6 changed files with 399 additions and 39 deletions

View File

@ -6,17 +6,37 @@ 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](http://phpseclib.bantux.org/code_coverage/master/latest/)
<img src="http://phpseclib.sourceforge.net/pear-icon.png" alt="PEAR Channel" width="16" height="16">
PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm)
* [Code Coverage Report](https://coverage.phpseclib.org/master/latest/)
## Documentation
* [Documentation / Manual](http://phpseclib.sourceforge.net/)
* [API Documentation](http://phpseclib.bantux.org/api/master/) (generated by Sami)
* [API Documentation](https://api.phpseclib.org/master/) (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 require phpseclib/phpseclib ~2.0`
### 1.0
* Long term support (LTS) release
* 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)
* [Download 1.0.5 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.5.zip/download)
## Support
@ -26,40 +46,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
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
```
2. Install Dependencies
``` sh
php composer.phar install
```
## Contributing
1. Fork the Project
2. Install Development Dependencies
2. Ensure you have Composer installed (see [Composer Download Instructions](https://getcomposer.org/download/))
3. Create a Feature Branch
3. Install Development Dependencies
4. (Recommended) Run the Test Suite
``` sh
composer install
```
4. Create a Feature Branch
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

View File

@ -885,6 +885,9 @@ class 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

View File

@ -304,6 +304,9 @@ class SCP
$response = Objects::getFunc($this->ssh, 'get_binary_packet');
switch ($response[SSH1::RESPONSE_TYPE]) {
case NET_SSH1_SMSG_STDOUT_DATA:
if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
return Strings::shift($response[SSH1::RESPONSE_DATA], $length);
case NET_SSH1_SMSG_STDERR_DATA:

View File

@ -376,7 +376,7 @@ class SFTP extends SSH2
);
if (!defined('NET_SFTP_QUEUE_SIZE')) {
define('NET_SFTP_QUEUE_SIZE', 50);
define('NET_SFTP_QUEUE_SIZE', 32);
}
}
@ -392,7 +392,7 @@ class SFTP extends SSH2
public function login($username)
{
$args = func_get_args();
if (!call_user_func_array(array(&$this, 'sublogin'), $args)) {
if (!call_user_func_array([&$this, 'sublogin'], $args)) {
return false;
}
@ -476,11 +476,20 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_VERSION');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nversion', Strings::shift($response, 4)));
$this->version = $version;
while (!empty($response)) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$key = Strings::shift($response, $length);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$value = Strings::shift($response, $length);
$this->extensions[$key] = $value;
@ -591,12 +600,15 @@ class SFTP extends SSH2
private function logError($response, $status = -1)
{
if ($status == -1) {
if (strlen($response) < 4) {
return;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
}
$error = $this->status_codes[$status];
if ($this->version > 2) {
if ($this->version > 2 || strlen($response) < 4) {
extract(unpack('Nlength', Strings::shift($response, 4)));
$this->sftp_errors[] = $error . ': ' . Strings::shift($response, $length);
} else {
@ -631,6 +643,9 @@ class SFTP extends 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.
Strings::shift($response, 4); // skip over the count - it should be 1, anyway
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
return Strings::shift($response, $length);
case NET_SFTP_STATUS:
@ -864,10 +879,19 @@ class SFTP extends SSH2
$response = $this->get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ncount', Strings::shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$shortname = Strings::shift($response, $length);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$longname = Strings::shift($response, $length);
$attributes = $this->parseAttributes($response);
@ -894,6 +918,9 @@ class SFTP extends SSH2
}
break;
case NET_SFTP_STATUS:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_EOF) {
$this->logError($response, $status);
@ -1487,6 +1514,9 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
@ -1599,12 +1629,18 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ncount', Strings::shift($response, 4)));
// the file isn't a symlink
if (!$count) {
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
return Strings::shift($response, $length);
}
@ -1639,7 +1675,11 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
return false;
@ -1702,6 +1742,9 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
@ -1739,6 +1782,9 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
@ -1965,6 +2011,9 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
@ -1996,6 +2045,9 @@ class SFTP extends SSH2
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
@ -2170,6 +2222,15 @@ class SFTP extends SSH2
return false;
}
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;
}
$path = $this->realpath($path);
if ($path === false) {
return false;
@ -2186,6 +2247,9 @@ class SFTP extends 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', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
@ -2611,6 +2675,9 @@ class SFTP extends 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', Strings::shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->logError($response, $status);
@ -2638,6 +2705,10 @@ class SFTP extends SSH2
private function parseAttributes(&$response)
{
$attr = [];
if (strlen($response) < 4) {
//user_error('Malformed file attributes');
return [];
}
extract(unpack('Nflags', Strings::shift($response, 4)));
// SFTPv4+ have a type field (a byte) that follows the above flag field
foreach ($this->attributes as $key => $value) {
@ -2652,9 +2723,17 @@ class SFTP extends SSH2
$attr['size'] = hexdec(Hex::encode(Strings::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', Strings::shift($response, 8));
break;
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
if (strlen($response) < 4) {
//user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Npermissions', Strings::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
@ -2665,13 +2744,29 @@ class SFTP extends SSH2
}
break;
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
if (strlen($response) < 8) {
//user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Natime/Nmtime', Strings::shift($response, 8));
break;
case NET_SFTP_ATTR_EXTENDED: // 0x80000000
if (strlen($response) < 4) {
//user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Ncount', Strings::shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 4) {
//user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$key = Strings::shift($response, $length);
if (strlen($response) < 4) {
//user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$attr[$key] = Strings::shift($response, $length);
}
@ -2825,6 +2920,9 @@ class SFTP extends SSH2
}
$this->packet_buffer.= $temp;
}
if (strlen($this->packet_buffer) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($this->packet_buffer, 4)));
$tempLength = $length;
$tempLength-= strlen($this->packet_buffer);

View File

@ -575,28 +575,46 @@ class SSH1
Strings::shift($response[self::RESPONSE_DATA], 4);
if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', Strings::shift($response[self::RESPONSE_DATA], 2));
$server_key_public_exponent = new BigInteger(Strings::shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_exponent = $server_key_public_exponent;
if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', Strings::shift($response[self::RESPONSE_DATA], 2));
$server_key_public_modulus = new BigInteger(Strings::shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_modulus = $server_key_public_modulus;
Strings::shift($response[self::RESPONSE_DATA], 4);
if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', Strings::shift($response[self::RESPONSE_DATA], 2));
$host_key_public_exponent = new BigInteger(Strings::shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_exponent = $host_key_public_exponent;
if (strlen($response[self::RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', Strings::shift($response[self::RESPONSE_DATA], 2));
$host_key_public_modulus = new BigInteger(Strings::shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_modulus = $host_key_public_modulus;
Strings::shift($response[self::RESPONSE_DATA], 4);
// get a list of the supported ciphers
if (strlen($response[self::RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_ciphers_mask', Strings::shift($response[self::RESPONSE_DATA], 4)));
foreach ($this->supported_ciphers as $mask => $name) {
if (($supported_ciphers_mask & (1 << $mask)) == 0) {
unset($this->supported_ciphers[$mask]);
@ -604,6 +622,9 @@ class SSH1
}
// get a list of the supported authentications
if (strlen($response[self::RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_authentications_mask', Strings::shift($response[self::RESPONSE_DATA], 4)));
foreach ($this->supported_authentications as $mask => $name) {
if (($supported_authentications_mask & (1 << $mask)) == 0) {
@ -1085,7 +1106,11 @@ class 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;
@ -1106,6 +1131,9 @@ class 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) ) {

View File

@ -1021,7 +1021,10 @@ class SSH2
if (!is_resource($this->fsock)) {
$start = microtime(true);
$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;
throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
@ -1119,7 +1122,7 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
}
@ -1318,37 +1321,71 @@ class SSH2
Strings::shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
$server_cookie = Strings::shift($response, 16);
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->kex_algorithms = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->server_host_key_algorithms = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->encryption_algorithms_client_to_server = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->encryption_algorithms_server_to_client = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->mac_algorithms_client_to_server = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->mac_algorithms_server_to_client = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->compression_algorithms_client_to_server = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->compression_algorithms_server_to_client = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->languages_client_to_server = explode(',', Strings::shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->languages_server_to_client = explode(',', Strings::shift($response, $temp['length']));
if (!strlen($response)) {
return false;
}
extract(unpack('Cfirst_kex_packet_follows', Strings::shift($response, 1)));
$first_kex_packet_follows = $first_kex_packet_follows != 0;
// the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
@ -1447,10 +1484,16 @@ class SSH2
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('NprimeLength', Strings::shift($response, 4)));
$primeBytes = Strings::shift($response, $primeLength);
$prime = new BigInteger($primeBytes, -256);
if (strlen($response) < 4) {
return false;
}
extract(unpack('NgLength', Strings::shift($response, 4)));
$gBytes = Strings::shift($response, $gLength);
$g = new BigInteger($gBytes, -256);
@ -1531,24 +1574,42 @@ class SSH2
if ($response === false) {
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
if ($type != $serverKexReplyMessage) {
throw new \UnexpectedValueException('Expected SSH_MSG_KEXDH_REPLY');
}
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->server_public_host_key = $server_public_host_key = Strings::shift($response, $temp['length']);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$public_key_format = Strings::shift($server_public_host_key, $temp['length']);
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$fBytes = Strings::shift($response, $temp['length']);
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($response, 4));
$this->signature = Strings::shift($response, $temp['length']);
if (strlen($this->signature) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($this->signature, 4));
$this->signature_format = Strings::shift($this->signature, $temp['length']);
@ -1618,6 +1679,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
if ($type != NET_SSH2_MSG_NEWKEYS) {
@ -1952,6 +2016,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
@ -1999,6 +2066,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
switch ($type) {
@ -2053,6 +2123,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
switch ($type) {
@ -2060,14 +2133,25 @@ class 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', Strings::shift($response, 4)));
$this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode(Strings::shift($response, $length));
return $this->disconnect_helper(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', Strings::shift($response, 4)));
$auth_methods = explode(',', Strings::shift($response, $length));
if (!strlen($response)) {
return false;
}
extract(unpack('Cpartial_success', Strings::shift($response, 1)));
$partial_success = $partial_success != 0;
@ -2142,16 +2226,31 @@ class SSH2
}
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
Strings::shift($response, $length); // name; may be empty
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
Strings::shift($response, $length); // instruction; may be empty
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
Strings::shift($response, $length); // language tag; may be empty
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nnum_prompts', Strings::shift($response, 4)));
for ($i = 0; $i < count($responses); $i++) {
@ -2166,6 +2265,9 @@ class SSH2
if (isset($this->keyboard_requests_responses)) {
for ($i = 0; $i < $num_prompts; $i++) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
// prompt - ie. "Password: "; must not be empty
$prompt = Strings::shift($response, $length);
@ -2311,12 +2413,19 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_FAILURE:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . Strings::shift($response, $length);
return false;
case NET_SSH2_MSG_USERAUTH_PK_OK:
// we'll just take it on faith that the public key blob and the public key algorithm name are as
@ -2345,6 +2454,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
switch ($type) {
@ -2401,7 +2513,12 @@ class SSH2
$this->is_timeout = false;
$this->stdErrorLog = '';
if (!($this->bitmap & self::MASK_LOGIN)) {
if (!$this->isAuthenticated()) {
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;
}
@ -2463,6 +2580,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
list(, $type) = unpack('C', Strings::shift($response, 1));
switch ($type) {
@ -2600,6 +2720,9 @@ class SSH2
throw new \RuntimeException('Connection closed by server');
}
if (!strlen($response)) {
return false;
}
list(, $type) = unpack('C', Strings::shift($response, 1));
switch ($type) {
@ -2694,7 +2817,7 @@ class SSH2
$this->curTimeout = $this->timeout;
$this->is_timeout = false;
if (!($this->bitmap & self::MASK_LOGIN)) {
if (!$this->isAuthenticated()) {
throw new \RuntimeException('Operation disallowed prior to login()');
}
@ -2735,7 +2858,7 @@ class SSH2
*/
public function write($cmd)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
if (!$this->isAuthenticated()) {
throw new \RuntimeException('Operation disallowed prior to login()');
}
@ -2930,6 +3053,9 @@ class SSH2
$raw = $this->decrypt->decrypt($raw);
}
if (strlen($raw) < 5) {
return false;
}
extract(unpack('Npacket_length/Cpadding_length', Strings::shift($raw, 5)));
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
@ -3001,6 +3127,9 @@ class SSH2
switch (ord($payload[0])) {
case NET_SSH2_MSG_DISCONNECT:
Strings::shift($payload, 1);
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nreason_code/Nlength', Strings::shift($payload, 8)));
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode(Strings::shift($payload, $length));
$this->bitmap = 0;
@ -3010,6 +3139,9 @@ class SSH2
break;
case NET_SSH2_MSG_DEBUG:
Strings::shift($payload, 2);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($payload, 4)));
$this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode(Strings::shift($payload, $length));
$payload = $this->get_binary_packet();
@ -3027,17 +3159,23 @@ class 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 & self::MASK_CONNECTED) && !($this->bitmap & self::MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
Strings::shift($payload, 1);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($payload, 4)));
$this->banner_message = utf8_decode(Strings::shift($payload, $length));
$payload = $this->get_binary_packet();
}
// only called when we've already logged in
if (($this->bitmap & self::MASK_CONNECTED) && ($this->bitmap & self::MASK_LOGIN)) {
if (($this->bitmap & self::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) {
return false;
}
extract(unpack('Nlength', Strings::shift($payload, 4)));
$this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . Strings::shift($payload, $length);
@ -3049,8 +3187,14 @@ class SSH2
break;
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
Strings::shift($payload, 1);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($payload, 4)));
$data = Strings::shift($payload, $length);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nserver_channel', Strings::shift($payload, 4)));
switch ($data) {
case 'auth-agent':
@ -3058,6 +3202,9 @@ class SSH2
if (isset($this->agent)) {
$new_channel = self::CHANNEL_AGENT_FORWARD;
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nremote_window_size', Strings::shift($payload, 4)));
extract(unpack('Nremote_maximum_packet_size', Strings::shift($payload, 4)));
@ -3103,8 +3250,12 @@ class SSH2
break;
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
Strings::shift($payload, 1);
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nchannel', Strings::shift($payload, 4)));
extract(unpack('Nwindow_size', Strings::shift($payload, 4)));
$this->window_size_client_to_server[$channel]+= $window_size;
$payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->get_binary_packet();
@ -3168,6 +3319,10 @@ class SSH2
*/
public function disablePTY()
{
if ($this->in_request_pty_exec) {
$this->_close_channel(self::CHANNEL_EXEC);
$this->in_request_pty_exec = false;
}
$this->request_pty = false;
}
@ -3233,8 +3388,14 @@ class SSH2
return '';
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', Strings::shift($response, 1)));
if (strlen($response) < 4) {
return false;
}
if ($type == NET_SSH2_MSG_CHANNEL_OPEN) {
extract(unpack('Nlength', Strings::shift($response, 4)));
} else {
@ -3258,15 +3419,26 @@ class 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', Strings::shift($response, 4)));
$this->server_channels[$channel] = $server_channel;
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nwindow_size', Strings::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', Strings::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);
$this->on_channel_open();
@ -3305,6 +3477,9 @@ class SSH2
$this->send_channel_packet($channel, chr(0));
}
*/
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$data = Strings::shift($response, $length);
@ -3331,8 +3506,12 @@ class 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', Strings::shift($response, 8)));
$data = Strings::shift($response, $length);
$this->stdErrorLog.= $data;
if ($skip_extended || $this->quiet_mode) {
break;
@ -3346,13 +3525,22 @@ class SSH2
$this->channel_buffers[$channel][] = $data;
break;
case NET_SSH2_MSG_CHANNEL_REQUEST:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$value = Strings::shift($response, $length);
switch ($value) {
case 'exit-signal':
Strings::shift($response, 1);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', Strings::shift($response, 4)));
$this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . Strings::shift($response, $length);
if (strlen($response) < 4) {
return false;
}
Strings::shift($response, 1);
extract(unpack('Nlength', Strings::shift($response, 4)));
if ($length) {
@ -3366,7 +3554,11 @@ class SSH2
break;
case 'exit-status':
if (strlen($response) < 5) {
return false;
}
extract(unpack('Cfalse/Nexit_status', Strings::shift($response, 5)));
$this->exit_status = $exit_status;
// "The client MAY ignore these messages."
@ -3978,6 +4170,9 @@ class 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', Strings::shift($server_public_host_key, 4)));
Strings::shift($server_public_host_key, $length);
@ -3993,15 +4188,27 @@ class SSH2
case 'ssh-dss':
$zero = new BigInteger();
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$p = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$q = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$g = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$y = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
@ -4048,15 +4255,24 @@ class SSH2
break;
case 'ssh-rsa':
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$e = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
$rawN = Strings::shift($server_public_host_key, $temp['length']);
$n = new BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, "\0"));
/*
if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($signature, 4));
$signature = Strings::shift($signature, $temp['length']);
@ -4069,6 +4285,9 @@ class SSH2
}
*/
if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', Strings::shift($signature, 4));
$s = new BigInteger(Strings::shift($signature, $temp['length']), 256);