$Attributes = array(
@@ -1232,6 +1252,14 @@ class X509
)
);
+ $this->PostalAddress = array(
+ 'type' => ASN1::TYPE_SEQUENCE,
+ 'optional' => true,
+ 'min' => 1,
+ 'max' => -1,
+ 'children' => $this->DirectoryString
+ );
+
// OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
$this->oids = array(
'1.3.6.1.5.5.7' => 'id-pkix',
@@ -1266,6 +1294,7 @@ class X509
'2.5.4.9' => 'id-at-streetAddress',
'2.5.4.45' => 'id-at-uniqueIdentifier',
'2.5.4.72' => 'id-at-role',
+ '2.5.4.16' => 'id-at-postalAddress',
'0.9.2342.19200300.100.1.25' => 'id-domainComponent',
'1.2.840.113549.1.9' => 'pkcs-9',
@@ -1404,10 +1433,11 @@ class X509
* Returns an associative array describing the X.509 cert or a false if the cert failed to load
*
* @param string $cert
+ * @param int $mode
* @access public
* @return mixed
*/
- function loadX509($cert)
+ function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT)
{
if (is_array($cert) && isset($cert['tbsCertificate'])) {
unset($this->currentCert);
@@ -1428,7 +1458,13 @@ class X509
$asn1 = new ASN1();
- $cert = $this->_extractBER($cert);
+ if ($mode != self::FORMAT_DER) {
+ $newcert = $this->_extractBER($cert);
+ if ($mode == self::FORMAT_PEM && $cert == $newcert) {
+ return false;
+ }
+ $cert = $newcert;
+ }
if ($cert === false) {
$this->currentCert = false;
@@ -1448,7 +1484,11 @@ class X509
$this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
- $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
+ if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
+ $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
+ }
+ $this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
+ $this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);
$key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
$key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
@@ -1525,6 +1565,8 @@ class X509
$asn1->loadFilters($filters);
$this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
+ $this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
+ $this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);
$cert = $asn1->encodeDER($cert, $this->Certificate);
@@ -1548,9 +1590,9 @@ class X509
*/
function _mapInExtensions(&$root, $path, $asn1)
{
- $extensions = &$this->_subArray($root, $path);
+ $extensions = &$this->_subArrayUnchecked($root, $path);
- if (is_array($extensions)) {
+ if ($extensions) {
for ($i = 0; $i < count($extensions); $i++) {
$id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue'];
@@ -1642,7 +1684,7 @@ class X509
$map = $this->_getMapping($id);
if (is_bool($map)) {
if (!$map) {
- //user_error($id . ' is not a currently supported extension');
+ user_error($id . ' is not a currently supported extension');
unset($extensions[$i]);
}
} else {
@@ -1682,7 +1724,7 @@ class X509
if ($mapped !== false) {
$values[$j] = $mapped;
}
- if ($id == 'pkcs-9-at-extensionRequest') {
+ if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
$this->_mapInExtensions($values, $j, $asn1);
}
} elseif ($map) {
@@ -1715,7 +1757,7 @@ class X509
$id = $attributes[$i]['type'];
$map = $this->_getMapping($id);
if ($map === false) {
- //user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
+ user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
unset($attributes[$i]);
} elseif (is_array($attributes[$i]['value'])) {
$values = &$attributes[$i]['value'];
@@ -1737,6 +1779,68 @@ class X509
}
}
+ /**
+ * Map DN values from ANY type to DN-specific internal
+ * format.
+ *
+ * @param array ref $root
+ * @param string $path
+ * @param object $asn1
+ * @access private
+ */
+ function _mapInDNs(&$root, $path, $asn1)
+ {
+ $dns = &$this->_subArray($root, $path);
+
+ if (is_array($dns)) {
+ for ($i = 0; $i < count($dns); $i++) {
+ for ($j = 0; $j < count($dns[$i]); $j++) {
+ $type = $dns[$i][$j]['type'];
+ $value = &$dns[$i][$j]['value'];
+ if (is_object($value) && $value instanceof Element) {
+ $map = $this->_getMapping($type);
+ if (!is_bool($map)) {
+ $decoded = $asn1->decodeBER($value);
+ $value = $asn1->asn1map($decoded[0], $map);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Map DN values from DN-specific internal format to
+ * ANY type.
+ *
+ * @param array ref $root
+ * @param string $path
+ * @param object $asn1
+ * @access private
+ */
+ function _mapOutDNs(&$root, $path, $asn1)
+ {
+ $dns = &$this->_subArray($root, $path);
+
+ if (is_array($dns)) {
+ $size = count($dns);
+ for ($i = 0; $i < $size; $i++) {
+ for ($j = 0; $j < count($dns[$i]); $j++) {
+ $type = $dns[$i][$j]['type'];
+ $value = &$dns[$i][$j]['value'];
+ if (is_object($value) && $value instanceof Element) {
+ continue;
+ }
+
+ $map = $this->_getMapping($type);
+ if (!is_bool($map)) {
+ $value = new Element($asn1->encodeDER($value, $map));
+ }
+ }
+ }
+ }
+ }
+
/**
* Associate an extension ID to an extension mapping
*
@@ -1769,6 +1873,8 @@ class X509
return $this->AuthorityInfoAccessSyntax;
case 'id-ce-subjectAltName':
return $this->SubjectAltName;
+ case 'id-ce-subjectDirectoryAttributes':
+ return $this->SubjectDirectoryAttributes;
case 'id-ce-privateKeyUsagePeriod':
return $this->PrivateKeyUsagePeriod;
case 'id-ce-issuerAltName':
@@ -1801,6 +1907,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
@@ -1828,6 +1937,8 @@ class X509
return $this->CertificateIssuer;
case 'id-ce-holdInstructionCode':
return $this->HoldInstructionCode;
+ case 'id-at-postalAddress':
+ return $this->PostalAddress;
}
return false;
@@ -2019,14 +2130,16 @@ class X509
switch (true) {
case isset($this->currentCert['tbsCertificate']):
// self-signed cert
- if ($this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']) {
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
- switch (true) {
- case !is_array($authorityKey):
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
- $signingCert = $this->currentCert; // working cert
- }
+ switch (true) {
+ case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
+ case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(self::DN_STRING) === $this->getDN(self::DN_STRING):
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
+ switch (true) {
+ case !is_array($authorityKey):
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ $signingCert = $this->currentCert; // working cert
+ }
}
if (!empty($this->CAs)) {
@@ -2034,15 +2147,17 @@ class X509
// even if the cert is a self-signed one we still want to see if it's a CA;
// if not, we'll conditionally return an error
$ca = $this->CAs[$i];
- if ($this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
- switch (true) {
- case !is_array($authorityKey):
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
- $signingCert = $ca; // working cert
- break 2;
- }
+ switch (true) {
+ case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
+ case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
+ switch (true) {
+ case !is_array($authorityKey):
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ $signingCert = $ca; // working cert
+ break 3;
+ }
}
}
if (count($this->CAs) == $i && $caonly) {
@@ -2078,15 +2193,17 @@ class X509
if (!empty($this->CAs)) {
for ($i = 0; $i < count($this->CAs); $i++) {
$ca = $this->CAs[$i];
- if ($this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']) {
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
- switch (true) {
- case !is_array($authorityKey):
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
- $signingCert = $ca; // working cert
- break 2;
- }
+ switch (true) {
+ case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
+ case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
+ switch (true) {
+ case !is_array($authorityKey):
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
+ $signingCert = $ca; // working cert
+ break 3;
+ }
}
}
}
@@ -2108,8 +2225,7 @@ class X509
/**
* Validates a signature
*
- * Returns true if the signature is verified and false if it is not correct.
- * If the algorithms are unsupposed an exception is thrown.
+ * Returns true if the signature is verified, false if it is not correct or null on error
*
* @param string $publicKeyAlgorithm
* @param string $publicKey
@@ -2117,8 +2233,7 @@ class X509
* @param string $signature
* @param string $signatureSubject
* @access private
- * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
- * @return bool
+ * @return int
*/
function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
{
@@ -2142,11 +2257,11 @@ class X509
}
break;
default:
- throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
+ return null;
}
break;
default:
- throw new UnsupportedAlgorithmException('Public key algorithm unsupported');
+ return null;
}
return true;
@@ -2189,9 +2304,7 @@ class X509
*/
function _decodeIP($ip)
{
- $ip = base64_decode($ip);
- list(, $ip) = unpack('N', $ip);
- return long2ip($ip);
+ return inet_ntop(base64_decode($ip));
}
/**
@@ -2205,7 +2318,7 @@ class X509
*/
function _encodeIP($ip)
{
- return base64_encode(pack('N', ip2long($ip)));
+ return base64_encode(inet_pton($ip));
}
/**
@@ -2292,6 +2405,9 @@ class X509
case 'uniqueidentifier':
case 'x500uniqueidentifier':
return 'id-at-uniqueIdentifier';
+ case 'postaladdress':
+ case 'id-at-postaladdress':
+ return 'id-at-postalAddress';
default:
return false;
}
@@ -2381,25 +2497,38 @@ class X509
return false;
}
+ $asn1 = new ASN1();
+ $asn1->loadOIDs($this->oids);
+ $filters = array();
+ $filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
+ $asn1->loadFilters($filters);
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
$dn = $dn['rdnSequence'];
$result = array();
- $asn1 = new ASN1();
for ($i = 0; $i < count($dn); $i++) {
if ($dn[$i][0]['type'] == $propName) {
$v = $dn[$i][0]['value'];
- if (!$withType && is_array($v)) {
- foreach ($v as $type => $s) {
- $type = array_search($type, $asn1->ANYmap, true);
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
- $s = $asn1->convert($s, $type);
- if ($s !== false) {
- $v = $s;
- break;
+ if (!$withType) {
+ if (is_array($v)) {
+ foreach ($v as $type => $s) {
+ $type = array_search($type, $asn1->ANYmap, true);
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
+ $s = $asn1->convert($s, $type);
+ if ($s !== false) {
+ $v = $s;
+ break;
+ }
}
}
- }
- if (is_array($v)) {
- $v = array_pop($v); // Always strip data type.
+ if (is_array($v)) {
+ $v = array_pop($v); // Always strip data type.
+ }
+ } elseif (is_object($v) && $v instanceof Element) {
+ $map = $this->_getMapping($propName);
+ if (!is_bool($map)) {
+ $decoded = $asn1->decodeBER($v);
+ $v = $asn1->asn1map($decoded[0], $map);
+ }
}
}
$result[] = $v;
@@ -2440,7 +2569,7 @@ class X509
}
// handles everything else
- $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 1; $i < count($results); $i+=2) {
$prop = trim($results[$i], ', =/');
$value = $results[$i + 1];
@@ -2475,33 +2604,19 @@ class X509
$filters = array();
$filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
return $asn1->encodeDER($dn, $this->Name);
- case self::DN_OPENSSL:
- $dn = $this->getDN(self::DN_STRING, $dn);
- if ($dn === false) {
- return false;
- }
- $attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
- $dn = array();
- for ($i = 1; $i < count($attrs); $i += 2) {
- $prop = trim($attrs[$i], ', =/');
- $value = $attrs[$i + 1];
- if (!isset($dn[$prop])) {
- $dn[$prop] = $value;
- } else {
- $dn[$prop] = array_merge((array) $dn[$prop], array($value));
- }
- }
- return $dn;
case self::DN_CANON:
// No SEQUENCE around RDNs and all string values normalized as
- // trimmed lowercase UTF-8 with all spacing as one blank.
+ // trimmed lowercase UTF-8 with all spacing as one blank.
+ // constructed RDNs will not be canonicalized
$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$result = '';
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
foreach ($dn['rdnSequence'] as $rdn) {
foreach ($rdn as $i => $attr) {
$attr = &$rdn[$i];
@@ -2533,7 +2648,15 @@ class X509
// Default is to return a string.
$start = true;
$output = '';
+
+ $result = array();
$asn1 = new ASN1();
+ $asn1->loadOIDs($this->oids);
+ $filters = array();
+ $filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
+ $asn1->loadFilters($filters);
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
+
foreach ($dn['rdnSequence'] as $field) {
$prop = $field[0]['type'];
$value = $field[0]['value'];
@@ -2541,33 +2664,37 @@ class X509
$delim = ', ';
switch ($prop) {
case 'id-at-countryName':
- $desc = 'C=';
+ $desc = 'C';
break;
case 'id-at-stateOrProvinceName':
- $desc = 'ST=';
+ $desc = 'ST';
break;
case 'id-at-organizationName':
- $desc = 'O=';
+ $desc = 'O';
break;
case 'id-at-organizationalUnitName':
- $desc = 'OU=';
+ $desc = 'OU';
break;
case 'id-at-commonName':
- $desc = 'CN=';
+ $desc = 'CN';
break;
case 'id-at-localityName':
- $desc = 'L=';
+ $desc = 'L';
break;
case 'id-at-surname':
- $desc = 'SN=';
+ $desc = 'SN';
break;
case 'id-at-uniqueIdentifier':
$delim = '/';
- $desc = 'x500UniqueIdentifier=';
+ $desc = 'x500UniqueIdentifier';
+ break;
+ case 'id-at-postalAddress':
+ $delim = '/';
+ $desc = 'postalAddress';
break;
default:
$delim = '/';
- $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '=';
+ $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
}
if (!$start) {
@@ -2587,12 +2714,18 @@ class X509
if (is_array($value)) {
$value = array_pop($value); // Always strip data type.
}
+ } elseif (is_object($value) && $value instanceof Element) {
+ $callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
+ $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
}
- $output.= $desc . $value;
+ $output.= $desc . '=' . $value;
+ $result[$desc] = isset($result[$desc]) ?
+ array_merge((array) $dn[$prop], array($value)) :
+ $value;
$start = false;
}
- return $output;
+ return $format == self::DN_OPENSSL ? $result : $output;
}
/**
@@ -2820,7 +2953,7 @@ class X509
* @access public
* @return mixed
*/
- function loadCSR($csr)
+ function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT)
{
if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
unset($this->currentCert);
@@ -2839,7 +2972,13 @@ class X509
$asn1 = new ASN1();
- $csr = $this->_extractBER($csr);
+ if ($mode != self::FORMAT_DER) {
+ $newcsr = $this->_extractBER($csr);
+ if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
+ return false;
+ }
+ $csr = $newcsr;
+ }
$orig = $csr;
if ($csr === false) {
@@ -2861,8 +3000,10 @@ class X509
return false;
}
- $this->dn = $csr['certificationRequestInfo']['subject'];
$this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
+ $this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
+
+ $this->dn = $csr['certificationRequestInfo']['subject'];
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
@@ -2909,6 +3050,9 @@ class X509
case 'rsaEncryption':
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
+ $csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
+ $csr['signatureAlgorithm']['parameters'] = null;
+ $csr['certificationRequestInfo']['signature']['parameters'] = null;
}
}
@@ -2922,6 +3066,7 @@ class X509
$asn1->loadFilters($filters);
+ $this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
$this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$csr = $asn1->encodeDER($csr, $this->CertificationRequest);
@@ -2959,7 +3104,7 @@ class X509
$asn1 = new ASN1();
- // OpenSSL produces SPKAC's that are preceeded by the string SPKAC=
+ // OpenSSL produces SPKAC's that are preceded by the string SPKAC=
$temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) {
@@ -3046,7 +3191,7 @@ class X509
return $spkac;
// case self::FORMAT_PEM:
default:
- // OpenSSL's implementation of SPKAC requires the SPKAC be preceeded by SPKAC= and since there are pretty much
+ // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much
// no other SPKAC decoders phpseclib will use that same format
return 'SPKAC=' . base64_encode($spkac);
}
@@ -3059,7 +3204,7 @@ class X509
* @access public
* @return mixed
*/
- function loadCRL($crl)
+ function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT)
{
if (is_array($crl) && isset($crl['tbsCertList'])) {
$this->currentCert = $crl;
@@ -3069,7 +3214,13 @@ class X509
$asn1 = new ASN1();
- $crl = $this->_extractBER($crl);
+ if ($mode != self::FORMAT_DER) {
+ $newcrl = $this->_extractBER($crl);
+ if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
+ return false;
+ }
+ $crl = $newcrl;
+ }
$orig = $crl;
if ($crl === false) {
@@ -3093,11 +3244,19 @@ class X509
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
- $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
- $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
- if (is_array($rclist)) {
- foreach ($rclist as $i => $extension) {
- $this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1);
+ $this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
+ if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
+ $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
+ }
+ if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
+ $rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
+ if ($rclist_ref) {
+ $rclist = $crl['tbsCertList']['revokedCertificates'];
+ foreach ($rclist as $i => $extension) {
+ if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
+ $this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
+ }
+ }
}
}
@@ -3145,6 +3304,7 @@ class X509
$asn1->loadFilters($filters);
+ $this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
$this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
$rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
if (is_array($rclist)) {
@@ -3306,8 +3466,8 @@ class X509
$altName = array();
- if (isset($subject->domains) && count($subject->domains) > 1) {
- $altName = array_map(array('X509', '_dnsName'), $subject->domains);
+ if (isset($subject->domains) && count($subject->domains)) {
+ $altName = array_map(array('\phpseclib\File\X509', '_dnsName'), $subject->domains);
}
if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
@@ -3631,7 +3791,6 @@ class X509
* @param \phpseclib\File\X509 $subject
* @param string $signatureAlgorithm
* @access public
- * @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
* @return mixed
*/
function _sign($key, $signatureAlgorithm)
@@ -3650,12 +3809,10 @@ class X509
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
return $this->currentCert;
- default:
- throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
}
}
- throw new UnsupportedAlgorithmException('Unsupported public key algorithm');
+ return false;
}
/**
@@ -3716,6 +3873,74 @@ class X509
$this->caFlag = true;
}
+ /**
+ * Check for validity of subarray
+ *
+ * This is intended for use in conjunction with _subArrayUnchecked(),
+ * implementing the checks included in _subArray() but without copying
+ * a potentially large array by passing its reference by-value to is_array().
+ *
+ * @param array $root
+ * @param string $path
+ * @return boolean
+ * @access private
+ */
+ function _isSubArrayValid($root, $path)
+ {
+ if (!is_array($root)) {
+ return false;
+ }
+
+ foreach (explode('/', $path) as $i) {
+ if (!is_array($root)) {
+ return false;
+ }
+
+ if (!isset($root[$i])) {
+ return true;
+ }
+
+ $root = $root[$i];
+ }
+
+ return true;
+ }
+
+ /**
+ * Get a reference to a subarray
+ *
+ * This variant of _subArray() does no is_array() checking,
+ * so $root should be checked with _isSubArrayValid() first.
+ *
+ * This is here for performance reasons:
+ * Passing a reference (i.e. $root) by-value (i.e. to is_array())
+ * creates a copy. If $root is an especially large array, this is expensive.
+ *
+ * @param array $root
+ * @param string $path absolute path with / as component separator
+ * @param bool $create optional
+ * @access private
+ * @return array|false
+ */
+ function &_subArrayUnchecked(&$root, $path, $create = false)
+ {
+ $false = false;
+
+ foreach (explode('/', $path) as $i) {
+ if (!isset($root[$i])) {
+ if (!$create) {
+ return $false;
+ }
+
+ $root[$i] = array();
+ }
+
+ $root = &$root[$i];
+ }
+
+ return $root;
+ }
+
/**
* Get a reference to a subarray
*
@@ -4560,7 +4785,7 @@ class X509
* subject=/O=organization/OU=org unit/CN=common name
* issuer=/O=organization/CN=common name
*/
- $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1);
+ $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
// remove new lines
diff --git a/inc/Exts/phpseclib/Math/BigInteger.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
similarity index 98%
rename from inc/Exts/phpseclib/Math/BigInteger.php
rename to vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
index b8fbad2b..4b13d7c6 100644
--- a/inc/Exts/phpseclib/Math/BigInteger.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
@@ -199,17 +199,10 @@ class BigInteger
*/
var $is_negative = false;
- /**
- * Random number generator function
- *
- * @access private
- */
- var $generator = 'mt_rand';
-
/**
* Precision
*
- * @see setPrecision()
+ * @see self::setPrecision()
* @access private
*/
var $precision = -1;
@@ -217,7 +210,7 @@ class BigInteger
/**
* Precision Bitmask
*
- * @see setPrecision()
+ * @see self::setPrecision()
* @access private
*/
var $bitmask = false;
@@ -229,8 +222,8 @@ class BigInteger
* a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
* however, $this->hex is only calculated when $this->__sleep() is called.
*
- * @see __sleep()
- * @see __wakeup()
+ * @see self::__sleep()
+ * @see self::__wakeup()
* @var string
* @access private
*/
@@ -299,6 +292,7 @@ class BigInteger
case !isset($versions['Header']):
case !isset($versions['Library']):
case $versions['Header'] == $versions['Library']:
+ case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
break;
default:
@@ -729,7 +723,7 @@ class BigInteger
* {@link http://php.net/language.oop5.basic#51624}
*
* @access public
- * @see __clone()
+ * @see self::__clone()
* @return \phpseclib\Math\BigInteger
*/
function copy()
@@ -737,7 +731,6 @@ class BigInteger
$temp = new static();
$temp->value = $this->value;
$temp->is_negative = $this->is_negative;
- $temp->generator = $this->generator;
$temp->precision = $this->precision;
$temp->bitmask = $this->bitmask;
return $temp;
@@ -766,7 +759,7 @@ class BigInteger
* PHP5, call BigInteger::copy(), instead.
*
* @access public
- * @see copy()
+ * @see self::copy()
* @return \phpseclib\Math\BigInteger
*/
function __clone()
@@ -779,16 +772,13 @@ class BigInteger
*
* Will be called, automatically, when serialize() is called on a BigInteger object.
*
- * @see __wakeup()
+ * @see self::__wakeup()
* @access public
*/
function __sleep()
{
$this->hex = $this->toHex(true);
$vars = array('hex');
- if ($this->generator != 'mt_rand') {
- $vars[] = 'generator';
- }
if ($this->precision > 0) {
$vars[] = 'precision';
}
@@ -800,7 +790,7 @@ class BigInteger
*
* Will be called, automatically, when unserialize() is called on a BigInteger object.
*
- * @see __sleep()
+ * @see self::__sleep()
* @access public
*/
function __wakeup()
@@ -814,6 +804,39 @@ class BigInteger
}
}
+ /**
+ * __debugInfo() magic method
+ *
+ * Will be called, automatically, when print_r() or var_dump() are called
+ *
+ * @access public
+ */
+ function __debugInfo()
+ {
+ $opts = array();
+ switch (MATH_BIGINTEGER_MODE) {
+ case self::MODE_GMP:
+ $engine = 'gmp';
+ break;
+ case self::MODE_BCMATH:
+ $engine = 'bcmath';
+ break;
+ case self::MODE_INTERNAL:
+ $engine = 'internal';
+ $opts[] = PHP_INT_SIZE == 8 ? '64-bit' : '32-bit';
+ }
+ if (MATH_BIGINTEGER_MODE != self::MODE_GMP && defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
+ $opts[] = 'OpenSSL';
+ }
+ if (!empty($opts)) {
+ $engine.= ' (' . implode($opts, ', ') . ')';
+ }
+ return array(
+ 'value' => '0x' . $this->toHex(true),
+ 'engine' => $engine
+ );
+ }
+
/**
* Adds two BigIntegers.
*
@@ -1802,7 +1825,7 @@ class BigInteger
// calculate the appropriate window size.
// $window_size == 3 if $window_ranges is between 25 and 81, for example.
- for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i) {
+ for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
}
$n_value = $n->value;
@@ -1856,7 +1879,7 @@ class BigInteger
*
* For most $modes this will return the remainder.
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
@@ -1893,7 +1916,7 @@ class BigInteger
/**
* Modular reduction preperation
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
@@ -1911,7 +1934,7 @@ class BigInteger
/**
* Modular multiply
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $y
@@ -1931,7 +1954,7 @@ class BigInteger
/**
* Modular square
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
@@ -1952,7 +1975,7 @@ class BigInteger
* Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
* we'll just use this function as a wrapper for doing that.
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param \phpseclib\Math\BigInteger
* @return \phpseclib\Math\BigInteger
@@ -1982,7 +2005,7 @@ class BigInteger
* (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
* comments for details.
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param array $n
* @param array $m
@@ -2079,7 +2102,7 @@ class BigInteger
* For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this
* is that this function does not fold the denominator into a smaller form.
*
- * @see _slidingWindow()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
@@ -2150,7 +2173,7 @@ class BigInteger
*
* If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
*
- * @see _regularBarrett()
+ * @see self::_regularBarrett()
* @param array $x_value
* @param bool $x_negative
* @param array $y_value
@@ -2231,8 +2254,8 @@ class BigInteger
* improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
* to work correctly.
*
- * @see _prepMontgomery()
- * @see _slidingWindow()
+ * @see self::_prepMontgomery()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
@@ -2278,8 +2301,8 @@ class BigInteger
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
*
- * @see _prepMontgomery()
- * @see _montgomery()
+ * @see self::_prepMontgomery()
+ * @see self::_montgomery()
* @access private
* @param array $x
* @param array $y
@@ -2330,8 +2353,8 @@ class BigInteger
/**
* Prepare a number for use in Montgomery Modular Reductions
*
- * @see _montgomery()
- * @see _slidingWindow()
+ * @see self::_montgomery()
+ * @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
@@ -2369,7 +2392,7 @@ class BigInteger
*
* Thanks to Pedro Gimeno Fortea for input!
*
- * @see _montgomery()
+ * @see self::_montgomery()
* @access private
* @param array $x
* @return int
@@ -2453,7 +2476,7 @@ class BigInteger
*
* Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that
* 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
- * combination is returned is dependant upon which mode is in use. See
+ * combination is returned is dependent upon which mode is in use. See
* {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
*
* Here's an example:
@@ -2650,7 +2673,7 @@ class BigInteger
* @param \phpseclib\Math\BigInteger $y
* @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
* @access public
- * @see equals()
+ * @see self::equals()
* @internal Could return $this->subtract($x), but that's not as fast as what we do do.
*/
function compare($y)
@@ -2673,7 +2696,7 @@ class BigInteger
* @param array $y_value
* @param bool $y_negative
* @return int
- * @see compare()
+ * @see self::compare()
* @access private
*/
function _compare($x_value, $x_negative, $y_value, $y_negative)
@@ -2709,7 +2732,7 @@ class BigInteger
* @param \phpseclib\Math\BigInteger $x
* @return bool
* @access public
- * @see compare()
+ * @see self::compare()
*/
function equals($x)
{
@@ -2876,6 +2899,9 @@ class BigInteger
// calculuate "not" without regard to $this->precision
// (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
$temp = $this->toBytes();
+ if ($temp == '') {
+ return '';
+ }
$pre_msb = decbin(ord($temp[0]));
$temp = ~$temp;
$msb = decbin(ord($temp[0]));
@@ -3259,7 +3285,7 @@ class BigInteger
*
* If the current number is odd it'll be unchanged. If it's even, one will be added to it.
*
- * @see randomPrime()
+ * @see self::randomPrime()
* @access private
*/
function _make_odd()
@@ -3509,7 +3535,7 @@ class BigInteger
*
* @param \phpseclib\Math\BigInteger
* @return \phpseclib\Math\BigInteger
- * @see _trim()
+ * @see self::_trim()
* @access private
*/
function _normalize($result)
@@ -3689,7 +3715,7 @@ class BigInteger
*
* The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
*
- * @see modPow()
+ * @see self::modPow()
* @access private
* @param int $length
* @return string
diff --git a/inc/Exts/phpseclib/Net/SCP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
similarity index 94%
rename from inc/Exts/phpseclib/Net/SCP.php
rename to vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
index 4c28d8b0..f95bce6d 100644
--- a/inc/Exts/phpseclib/Net/SCP.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
@@ -32,8 +32,6 @@
namespace phpseclib\Net;
-use phpseclib\Exception\FileNotFoundException;
-
/**
* Pure-PHP implementations of SCP.
*
@@ -101,9 +99,7 @@ class SCP
*
* Connects to an SSH server
*
- * @param string $host
- * @param int $port
- * @param int $timeout
+ * @param \phpseclib\Net\SSH1|\phpseclib\Net\SSH2 $ssh
* @return \phpseclib\Net\SCP
* @access public
*/
@@ -139,7 +135,6 @@ class SCP
* @param string $data
* @param int $mode
* @param callable $callback
- * @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist
* @return bool
* @access public
*/
@@ -168,7 +163,8 @@ class SCP
$size = strlen($data);
} else {
if (!is_file($data)) {
- throw new FileNotFoundException("$data is not a valid file");
+ user_error("$data is not a valid file", E_USER_NOTICE);
+ return false;
}
$fp = @fopen($data, 'rb');
@@ -288,7 +284,6 @@ class SCP
* Receives a packet from an SSH server
*
* @return string
- * @throws \UnexpectedValueException on receipt of an unexpected packet
* @access private
*/
function _receive()
@@ -304,6 +299,9 @@ class SCP
$response = $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 $this->ssh->_string_shift($response[SSH1::RESPONSE_DATA], $length);
case NET_SSH1_SMSG_STDERR_DATA:
@@ -314,7 +312,8 @@ class SCP
$this->ssh->bitmap = 0;
return false;
default:
- throw new \UnexpectedValueException('Unknown packet received');
+ user_error('Unknown packet received', E_USER_NOTICE);
+ return false;
}
}
}
diff --git a/inc/Exts/phpseclib/Net/SFTP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
similarity index 88%
rename from inc/Exts/phpseclib/Net/SFTP.php
rename to vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
index f82decc0..1421ecb4 100644
--- a/inc/Exts/phpseclib/Net/SFTP.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
@@ -37,9 +37,6 @@
namespace phpseclib\Net;
-use phpseclib\Net\SSH2;
-use phpseclib\Exception\FileNotFoundException;
-
/**
* Pure-PHP implementations of SFTP.
*
@@ -91,7 +88,7 @@ class SFTP extends SSH2
/**
* Packet Types
*
- * @see \phpseclib\Net\SFTP::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -100,7 +97,7 @@ class SFTP extends SSH2
/**
* Status Codes
*
- * @see \phpseclib\Net\SFTP::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -113,7 +110,7 @@ class SFTP extends SSH2
* concurrent actions, so it's somewhat academic, here.
*
* @var int
- * @see \phpseclib\Net\SFTP::_send_sftp_packet()
+ * @see self::_send_sftp_packet()
* @access private
*/
var $request_id = false;
@@ -125,7 +122,7 @@ class SFTP extends SSH2
* concurrent actions, so it's somewhat academic, here.
*
* @var int
- * @see \phpseclib\Net\SFTP::_get_sftp_packet()
+ * @see self::_get_sftp_packet()
* @access private
*/
var $packet_type = -1;
@@ -134,7 +131,7 @@ class SFTP extends SSH2
* Packet Buffer
*
* @var string
- * @see \phpseclib\Net\SFTP::_get_sftp_packet()
+ * @see self::_get_sftp_packet()
* @access private
*/
var $packet_buffer = '';
@@ -143,7 +140,7 @@ class SFTP extends SSH2
* Extensions supported by the server
*
* @var array
- * @see \phpseclib\Net\SFTP::_initChannel()
+ * @see self::_initChannel()
* @access private
*/
var $extensions = array();
@@ -152,7 +149,7 @@ class SFTP extends SSH2
* Server SFTP version
*
* @var int
- * @see \phpseclib\Net\SFTP::_initChannel()
+ * @see self::_initChannel()
* @access private
*/
var $version;
@@ -161,8 +158,8 @@ class SFTP extends SSH2
* Current working directory
*
* @var string
- * @see \phpseclib\Net\SFTP::_realpath()
- * @see \phpseclib\Net\SFTP::chdir()
+ * @see self::_realpath()
+ * @see self::chdir()
* @access private
*/
var $pwd = false;
@@ -170,7 +167,7 @@ class SFTP extends SSH2
/**
* Packet Type Log
*
- * @see \phpseclib\Net\SFTP::getLog()
+ * @see self::getLog()
* @var array
* @access private
*/
@@ -179,7 +176,7 @@ class SFTP extends SSH2
/**
* Packet Log
*
- * @see \phpseclib\Net\SFTP::getLog()
+ * @see self::getLog()
* @var array
* @access private
*/
@@ -188,8 +185,8 @@ class SFTP extends SSH2
/**
* Error information
*
- * @see \phpseclib\Net\SFTP::getSFTPErrors()
- * @see \phpseclib\Net\SFTP::getLastSFTPError()
+ * @see self::getSFTPErrors()
+ * @see self::getLastSFTPError()
* @var string
* @access private
*/
@@ -201,9 +198,9 @@ class SFTP extends SSH2
* Rather than always having to open a directory and close it immediately there after to see if a file is a directory
* we'll cache the results.
*
- * @see \phpseclib\Net\SFTP::_update_stat_cache()
- * @see \phpseclib\Net\SFTP::_remove_from_stat_cache()
- * @see \phpseclib\Net\SFTP::_query_stat_cache()
+ * @see self::_update_stat_cache()
+ * @see self::_remove_from_stat_cache()
+ * @see self::_query_stat_cache()
* @var array
* @access private
*/
@@ -212,8 +209,8 @@ class SFTP extends SSH2
/**
* Max SFTP Packet Size
*
- * @see \phpseclib\Net\SFTP::__construct()
- * @see \phpseclib\Net\SFTP::get()
+ * @see self::__construct()
+ * @see self::get()
* @var array
* @access private
*/
@@ -222,8 +219,8 @@ class SFTP extends SSH2
/**
* Stat Cache Flag
*
- * @see \phpseclib\Net\SFTP::disableStatCache()
- * @see \phpseclib\Net\SFTP::enableStatCache()
+ * @see self::disableStatCache()
+ * @see self::enableStatCache()
* @var bool
* @access private
*/
@@ -232,8 +229,8 @@ class SFTP extends SSH2
/**
* Sort Options
*
- * @see \phpseclib\Net\SFTP::_comparator()
- * @see \phpseclib\Net\SFTP::setListOrder()
+ * @see self::_comparator()
+ * @see self::setListOrder()
* @var array
* @access private
*/
@@ -342,7 +339,7 @@ class SFTP extends SSH2
);
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
// the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
- // the array for that $this->open5_flags and similarily alter the constant names.
+ // the array for that $this->open5_flags and similarly alter the constant names.
$this->open_flags = array(
0x00000001 => 'NET_SFTP_OPEN_READ',
0x00000002 => 'NET_SFTP_OPEN_WRITE',
@@ -375,7 +372,7 @@ class SFTP extends SSH2
);
if (!defined('NET_SFTP_QUEUE_SIZE')) {
- define('NET_SFTP_QUEUE_SIZE', 50);
+ define('NET_SFTP_QUEUE_SIZE', 32);
}
}
@@ -384,7 +381,6 @@ class SFTP extends SSH2
*
* @param string $username
* @param string $password
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -472,14 +468,24 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_VERSION) {
- throw new \UnexpectedValueException('Expected SSH_FXP_VERSION');
+ user_error('Expected SSH_FXP_VERSION');
+ 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;
@@ -590,12 +596,15 @@ class SFTP extends 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 {
@@ -603,15 +612,29 @@ class SFTP extends SSH2
}
}
+ /**
+ * Returns canonicalized absolute pathname
+ *
+ * realpath() expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the input
+ * path and returns the canonicalized absolute pathname.
+ *
+ * @param string $path
+ * @return mixed
+ * @access public
+ */
+ function realpath($path)
+ {
+ return $this->_realpath($path);
+ }
+
/**
* Canonicalize the Server-Side Path Name
*
* SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
* the absolute (canonicalized) path.
*
- * @see \phpseclib\Net\SFTP::chdir()
+ * @see self::chdir()
* @param string $path
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access private
*/
@@ -630,13 +653,17 @@ 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.
$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:
$this->_logError($response);
return false;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
+ return false;
}
}
@@ -667,7 +694,6 @@ class SFTP extends SSH2
* Changes the current directory
*
* @param string $dir
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -712,7 +738,8 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
}
if (!$this->_close_handle($handle)) {
@@ -751,7 +778,7 @@ class SFTP extends SSH2
{
$files = $this->_list($dir, false);
- if (!$recursive) {
+ if (!$recursive || $files === false) {
return $files;
}
@@ -814,7 +841,6 @@ class SFTP extends SSH2
* @param string $dir
* @param bool $raw
* @return mixed
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _list($dir, $raw = true)
@@ -846,7 +872,8 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
}
$this->_update_stat_cache($dir, array());
@@ -863,10 +890,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', $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);
@@ -893,6 +929,9 @@ class SFTP extends 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);
@@ -900,7 +939,8 @@ class SFTP extends SSH2
}
break 2;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
+ return false;
}
}
@@ -1259,7 +1299,6 @@ class SFTP extends SSH2
*
* @param string $filename
* @param int $type
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access private
*/
@@ -1280,7 +1319,8 @@ class SFTP extends SSH2
return false;
}
- throw new \UnexpectedValueException('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
+ return false;
}
/**
@@ -1306,7 +1346,6 @@ class SFTP extends SSH2
* @param string $filename
* @param int $time
* @param int $atime
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -1343,7 +1382,8 @@ class SFTP extends SSH2
$this->_logError($response);
break;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
}
return $this->_setstat($filename, $attr, false);
@@ -1396,7 +1436,6 @@ class SFTP extends SSH2
* @param int $mode
* @param string $filename
* @param bool $recursive
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access public
*/
@@ -1416,6 +1455,7 @@ class SFTP extends SSH2
return true;
}
+ $filename = $this->_realPath($filename);
// rather than return what the permissions *should* be, we'll return what they actually are. this will also
// tell us if the file actually exists.
// incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
@@ -1434,7 +1474,8 @@ class SFTP extends SSH2
return false;
}
- throw new \UnexpectedValueException('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
+ return false;
}
/**
@@ -1443,7 +1484,6 @@ class SFTP extends SSH2
* @param string $filename
* @param string $attr
* @param bool $recursive
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access private
*/
@@ -1482,9 +1522,13 @@ class SFTP extends SSH2
*/
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ 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);
@@ -1570,7 +1614,6 @@ class SFTP extends SSH2
* Return the target of a symbolic link
*
* @param string $link
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access public
*/
@@ -1594,15 +1637,22 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
+ 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);
}
@@ -1614,7 +1664,6 @@ class SFTP extends SSH2
*
* @param string $target
* @param string $link
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -1624,7 +1673,7 @@ class SFTP extends SSH2
return false;
}
- $target = $this->_realpath($target);
+ //$target = $this->_realpath($target);
$link = $this->_realpath($link);
$packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
@@ -1634,9 +1683,13 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ 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);
@@ -1686,7 +1739,6 @@ class SFTP extends SSH2
*
* @param string $dir
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _mkdir_helper($dir, $attr)
@@ -1697,9 +1749,13 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ 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);
@@ -1713,7 +1769,6 @@ class SFTP extends SSH2
* Removes a directory.
*
* @param string $dir
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -1734,9 +1789,13 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ 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?
@@ -1794,9 +1853,6 @@ class SFTP extends SSH2
* @param int $start
* @param int $local_start
* @param callable|null $progressCallback
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \BadFunctionCallException if you're uploading via a callback and the callback function is invalid
- * @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist
* @return bool
* @access public
* @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - \phpseclib\Net\SFTP::setMode().
@@ -1844,7 +1900,8 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
}
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
@@ -1852,18 +1909,26 @@ class SFTP extends SSH2
switch (true) {
case $mode & self::SOURCE_CALLBACK:
if (!is_callable($data)) {
- throw new \BadFunctionCallException("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
+ user_error("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
}
$dataCallback = $data;
// do nothing
break;
case is_resource($data):
$mode = $mode & ~self::SOURCE_LOCAL_FILE;
- $fp = $data;
+ $info = stream_get_meta_data($data);
+ if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
+ $fp = fopen('php://memory', 'w+');
+ stream_copy_to_stream($data, $fp);
+ rewind($fp);
+ } else {
+ $fp = $data;
+ }
break;
case $mode & self::SOURCE_LOCAL_FILE:
if (!is_file($data)) {
- throw new FileNotFoundException("$data is not a valid file");
+ user_error("$data is not a valid file");
+ return false;
}
$fp = @fopen($data, 'rb');
if (!$fp) {
@@ -1877,10 +1942,7 @@ class SFTP extends SSH2
if ($local_start >= 0) {
fseek($fp, $local_start);
- } elseif ($mode & self::RESUME_START) {
- // do nothing
- } else {
- fseek($fp, $offset);
+ $size-= $local_start;
}
} elseif ($dataCallback) {
$size = 0;
@@ -1895,7 +1957,7 @@ class SFTP extends SSH2
// make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header"
$sftp_packet_size-= strlen($handle) + 25;
$i = 0;
- while ($dataCallback || $sent < $size) {
+ while ($dataCallback || ($size === 0 || $sent < $size)) {
if ($dataCallback) {
$temp = call_user_func($dataCallback, $sftp_packet_size);
if (is_null($temp)) {
@@ -1903,7 +1965,11 @@ class SFTP extends SSH2
}
} else {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
+ if ($temp === false || $temp === '') {
+ break;
+ }
}
+
$subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
@@ -1951,7 +2017,6 @@ class SFTP extends SSH2
*
* @param int $i
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _read_put_responses($i)
@@ -1959,9 +2024,13 @@ class SFTP extends SSH2
while ($i--) {
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ 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);
@@ -1977,7 +2046,6 @@ class SFTP extends SSH2
*
* @param string $handle
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _close_handle($handle)
@@ -1990,9 +2058,13 @@ class SFTP extends SSH2
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ 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);
@@ -2015,7 +2087,6 @@ class SFTP extends SSH2
* @param string $local_file
* @param int $offset
* @param int $length
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access public
*/
@@ -2044,7 +2115,8 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
- throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
}
if (is_resource($local_file)) {
@@ -2066,39 +2138,68 @@ class SFTP extends SSH2
$fclose_check = $local_file !== false && !is_resource($local_file);
$start = $offset;
- $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length;
+ $read = 0;
while (true) {
- $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size);
- if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
- if ($fclose_check) {
- fclose($fp);
- }
- return false;
- }
+ $i = 0;
- $response = $this->_get_sftp_packet();
- switch ($this->packet_type) {
- case NET_SFTP_DATA:
- $temp = substr($response, 4);
- $offset+= strlen($temp);
- if ($local_file === false) {
- $content.= $temp;
- } else {
- fputs($fp, $temp);
- }
- break;
- case NET_SFTP_STATUS:
- // could, in theory, return false if !strlen($content) but we'll hold off for the time being
- $this->_logError($response);
- break 2;
- default:
+ while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
+ $tempoffset = $start + $read;
+
+ $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
+
+ $packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
+ if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
if ($fclose_check) {
fclose($fp);
}
- throw new \UnexpectedValueException('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
+ return false;
+ }
+ $packet = null;
+ $read+= $packet_size;
+ $i++;
}
- if ($length > 0 && $length <= $offset - $start) {
+ if (!$i) {
+ break;
+ }
+
+ $clear_responses = false;
+ while ($i > 0) {
+ $i--;
+
+ if ($clear_responses) {
+ $this->_get_sftp_packet();
+ continue;
+ } else {
+ $response = $this->_get_sftp_packet();
+ }
+
+ switch ($this->packet_type) {
+ case NET_SFTP_DATA:
+ $temp = substr($response, 4);
+ $offset+= strlen($temp);
+ if ($local_file === false) {
+ $content.= $temp;
+ } else {
+ fputs($fp, $temp);
+ }
+ $temp = null;
+ break;
+ case NET_SFTP_STATUS:
+ // could, in theory, return false if !strlen($content) but we'll hold off for the time being
+ $this->_logError($response);
+ $clear_responses = true; // don't break out of the loop yet, so we can read the remaining responses
+ break;
+ default:
+ if ($fclose_check) {
+ fclose($fp);
+ }
+ user_error('Expected SSH_FX_DATA or SSH_FXP_STATUS');
+ }
+ $response = null;
+ }
+
+ if ($clear_responses) {
break;
}
}
@@ -2129,7 +2230,6 @@ class SFTP extends SSH2
* @param string $path
* @param bool $recursive
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @access public
*/
function delete($path, $recursive = true)
@@ -2138,6 +2238,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;
@@ -2150,10 +2259,14 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ return false;
}
// 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);
@@ -2311,6 +2424,76 @@ class SFTP extends SSH2
return $result === NET_SFTP_TYPE_SYMLINK;
}
+ /**
+ * Tells whether a file exists and is readable
+ *
+ * @param string $path
+ * @return bool
+ * @access public
+ */
+ function is_readable($path)
+ {
+ $path = $this->_realpath($path);
+
+ $packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_READ, 0);
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
+ return false;
+ }
+
+ $response = $this->_get_sftp_packet();
+ switch ($this->packet_type) {
+ case NET_SFTP_HANDLE:
+ return true;
+ case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
+ return false;
+ default:
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
+ }
+ }
+
+ /**
+ * Tells whether the filename is writable
+ *
+ * @param string $path
+ * @return bool
+ * @access public
+ */
+ function is_writable($path)
+ {
+ $path = $this->_realpath($path);
+
+ $packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_WRITE, 0);
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
+ return false;
+ }
+
+ $response = $this->_get_sftp_packet();
+ switch ($this->packet_type) {
+ case NET_SFTP_HANDLE:
+ return true;
+ case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
+ return false;
+ default:
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
+ return false;
+ }
+ }
+
+ /**
+ * Tells whether the filename is writeable
+ *
+ * Alias of is_writable
+ *
+ * @param string $path
+ * @return bool
+ * @access public
+ */
+ function is_writeable($path)
+ {
+ return $this->is_writable($path);
+ }
+
/**
* Gets last access time of file
*
@@ -2482,7 +2665,6 @@ class SFTP extends SSH2
* @param string $oldname
* @param string $newname
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
* @access public
*/
function rename($oldname, $newname)
@@ -2505,10 +2687,14 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
- throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
+ user_error('Expected SSH_FXP_STATUS');
+ return false;
}
// 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);
@@ -2536,6 +2722,10 @@ class SFTP extends 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) {
@@ -2550,9 +2740,17 @@ class SFTP extends 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
@@ -2563,13 +2761,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', $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);
}
@@ -2661,8 +2875,8 @@ class SFTP extends SSH2
*
* @param int $type
* @param string $data
- * @see \phpseclib\Net\SFTP::_get_sftp_packet()
- * @see \phpseclib\Net\SSH2::_send_channel_packet()
+ * @see self::_get_sftp_packet()
+ * @see self::_send_channel_packet()
* @return bool
* @access private
*/
@@ -2679,13 +2893,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;
}
}
@@ -2703,7 +2917,7 @@ class SFTP extends SSH2
* There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
* messages containing one SFTP packet.
*
- * @see \phpseclib\Net\SFTP::_send_sftp_packet()
+ * @see self::_send_sftp_packet()
* @return string
* @access private
*/
@@ -2723,6 +2937,9 @@ class SFTP extends 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);
@@ -2755,13 +2972,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;
}
}
@@ -2785,10 +3002,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;
}
diff --git a/inc/Exts/phpseclib/Net/SFTP/Stream.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
similarity index 97%
rename from inc/Exts/phpseclib/Net/SFTP/Stream.php
rename to vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
index 7af7280a..08d726ca 100644
--- a/inc/Exts/phpseclib/Net/SFTP/Stream.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
@@ -19,7 +19,6 @@ namespace phpseclib\Net\SFTP;
use phpseclib\Crypt\RSA;
use phpseclib\Net\SFTP;
-use phpseclib\Net\SSH2;
/**
* SFTP Stream Wrapper
@@ -154,7 +153,18 @@ class Stream
*/
function _parse_path($path)
{
+ $orig = $path;
extract(parse_url($path) + array('port' => 22));
+ if (isset($query)) {
+ $path.= '?' . $query;
+ } elseif (preg_match('/(\?|\?#)$/', $orig)) {
+ $path.= '?';
+ }
+ if (isset($fragment)) {
+ $path.= '#' . $fragment;
+ } elseif ($orig[strlen($orig) - 1] == '#') {
+ $path.= '#';
+ }
if (!isset($host)) {
return false;
@@ -167,12 +177,13 @@ class Stream
}
}
- if (preg_match('/^{[a-z0-9]+}$/i', $host)) {
- $host = SSH2::getConnectionByResourceId($host);
- if ($host === false) {
+ if ($host[0] == '$') {
+ $host = substr($host, 1);
+ global $$host;
+ if (($$host instanceof SFTP) === false) {
return false;
}
- $this->sftp = $host;
+ $this->sftp = $$host;
} else {
if (isset($this->context)) {
$context = stream_context_get_options($this->context);
diff --git a/inc/Exts/phpseclib/Net/SSH1.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
similarity index 91%
rename from inc/Exts/phpseclib/Net/SSH1.php
rename to vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
index 91adf675..9e608f4b 100644
--- a/inc/Exts/phpseclib/Net/SSH1.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
@@ -261,7 +261,7 @@ class SSH1
*
* Logged for debug purposes
*
- * @see \phpseclib\Net\SSH1::getServerKeyPublicExponent()
+ * @see self::getServerKeyPublicExponent()
* @var string
* @access private
*/
@@ -272,7 +272,7 @@ class SSH1
*
* Logged for debug purposes
*
- * @see \phpseclib\Net\SSH1::getServerKeyPublicModulus()
+ * @see self::getServerKeyPublicModulus()
* @var string
* @access private
*/
@@ -283,7 +283,7 @@ class SSH1
*
* Logged for debug purposes
*
- * @see \phpseclib\Net\SSH1::getHostKeyPublicExponent()
+ * @see self::getHostKeyPublicExponent()
* @var string
* @access private
*/
@@ -294,7 +294,7 @@ class SSH1
*
* Logged for debug purposes
*
- * @see \phpseclib\Net\SSH1::getHostKeyPublicModulus()
+ * @see self::getHostKeyPublicModulus()
* @var string
* @access private
*/
@@ -305,7 +305,7 @@ class SSH1
*
* Logged for debug purposes
*
- * @see \phpseclib\Net\SSH1::getSupportedCiphers()
+ * @see self::getSupportedCiphers()
* @var array
* @access private
*/
@@ -324,7 +324,7 @@ class SSH1
*
* Logged for debug purposes
*
- * @see \phpseclib\Net\SSH1::getSupportedAuthentications()
+ * @see self::getSupportedAuthentications()
* @var array
* @access private
*/
@@ -338,7 +338,7 @@ class SSH1
/**
* Server Identification
*
- * @see \phpseclib\Net\SSH1::getServerIdentification()
+ * @see self::getServerIdentification()
* @var string
* @access private
*/
@@ -347,7 +347,7 @@ class SSH1
/**
* Protocol Flags
*
- * @see \phpseclib\Net\SSH1::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -356,7 +356,7 @@ class SSH1
/**
* Protocol Flag Log
*
- * @see \phpseclib\Net\SSH1::getLog()
+ * @see self::getLog()
* @var array
* @access private
*/
@@ -365,7 +365,7 @@ class SSH1
/**
* Message Log
*
- * @see \phpseclib\Net\SSH1::getLog()
+ * @see self::getLog()
* @var array
* @access private
*/
@@ -374,7 +374,7 @@ class SSH1
/**
* Real-time log file pointer
*
- * @see \phpseclib\Net\SSH1::_append_log()
+ * @see self::_append_log()
* @var resource
* @access private
*/
@@ -383,7 +383,7 @@ class SSH1
/**
* Real-time log file size
*
- * @see \phpseclib\Net\SSH1::_append_log()
+ * @see self::_append_log()
* @var int
* @access private
*/
@@ -392,7 +392,7 @@ class SSH1
/**
* Real-time log file wrap boolean
*
- * @see \phpseclib\Net\SSH1::_append_log()
+ * @see self::_append_log()
* @var bool
* @access private
*/
@@ -401,7 +401,7 @@ class SSH1
/**
* Interactive Buffer
*
- * @see \phpseclib\Net\SSH1::read()
+ * @see self::read()
* @var array
* @access private
*/
@@ -410,7 +410,7 @@ class SSH1
/**
* Timeout
*
- * @see \phpseclib\Net\SSH1::setTimeout()
+ * @see self::setTimeout()
* @access private
*/
var $timeout;
@@ -418,7 +418,7 @@ class SSH1
/**
* Current Timeout
*
- * @see \phpseclib\Net\SSH1::_get_channel_packet()
+ * @see self::_get_channel_packet()
* @access private
*/
var $curTimeout;
@@ -426,7 +426,7 @@ class SSH1
/**
* Log Boundary
*
- * @see \phpseclib\Net\SSH1::_format_log
+ * @see self::_format_log()
* @access private
*/
var $log_boundary = ':';
@@ -434,7 +434,7 @@ class SSH1
/**
* Log Long Width
*
- * @see \phpseclib\Net\SSH1::_format_log
+ * @see self::_format_log()
* @access private
*/
var $log_long_width = 65;
@@ -442,7 +442,7 @@ class SSH1
/**
* Log Short Width
*
- * @see \phpseclib\Net\SSH1::_format_log
+ * @see self::_format_log()
* @access private
*/
var $log_short_width = 16;
@@ -450,8 +450,8 @@ class SSH1
/**
* Hostname
*
- * @see \phpseclib\Net\SSH1::__construct()
- * @see \phpseclib\Net\SSH1::_connect()
+ * @see self::__construct()
+ * @see self::_connect()
* @var string
* @access private
*/
@@ -460,8 +460,8 @@ class SSH1
/**
* Port Number
*
- * @see \phpseclib\Net\SSH1::__construct()
- * @see \phpseclib\Net\SSH1::_connect()
+ * @see self::__construct()
+ * @see self::_connect()
* @var int
* @access private
*/
@@ -475,8 +475,8 @@ class SSH1
* however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
* 10 seconds. It is used by fsockopen() in that function.
*
- * @see \phpseclib\Net\SSH1::__construct()
- * @see \phpseclib\Net\SSH1::_connect()
+ * @see self::__construct()
+ * @see self::_connect()
* @var int
* @access private
*/
@@ -485,8 +485,8 @@ class SSH1
/**
* Default cipher
*
- * @see \phpseclib\Net\SSH1::__construct()
- * @see \phpseclib\Net\SSH1::_connect()
+ * @see self::__construct()
+ * @see self::_connect()
* @var int
* @access private
*/
@@ -537,15 +537,14 @@ class SSH1
* Connect to an SSHv1 server
*
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
* @access private
*/
function _connect()
{
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) {
- throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
+ user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
+ return false;
}
$this->server_identification = $init_line = fgets($this->fsock, 255);
@@ -556,45 +555,66 @@ class SSH1
}
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
- throw new \RuntimeException('Can only connect to SSH servers');
+ user_error('Can only connect to SSH servers');
+ return false;
}
if ($parts[1][0] != 1) {
- throw new \RuntimeException("Cannot connect to $parts[1] servers");
+ user_error("Cannot connect to SSH $parts[1] servers");
+ return false;
}
fputs($this->fsock, $this->identifier."\r\n");
$response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
- throw new \UnexpectedValueException('Expected SSH_SMSG_PUBLIC_KEY');
+ user_error('Expected SSH_SMSG_PUBLIC_KEY');
+ return false;
}
$anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
$this->_string_shift($response[self::RESPONSE_DATA], 4);
+ if (strlen($response[self::RESPONSE_DATA]) < 2) {
+ return false;
+ }
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$server_key_public_exponent = new BigInteger($this->_string_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', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
+
$this->server_key_public_modulus = $server_key_public_modulus;
$this->_string_shift($response[self::RESPONSE_DATA], 4);
+ if (strlen($response[self::RESPONSE_DATA]) < 2) {
+ return false;
+ }
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$host_key_public_exponent = new BigInteger($this->_string_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', $this->_string_shift($response[self::RESPONSE_DATA], 2));
$host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
+
$this->host_key_public_modulus = $host_key_public_modulus;
$this->_string_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', $this->_string_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]);
@@ -602,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', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
foreach ($this->supported_authentications as $mask => $name) {
if (($supported_authentications_mask & (1 << $mask)) == 0) {
@@ -650,7 +673,8 @@ class SSH1
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_SESSION_KEY');
+ user_error('Error sending SSH_CMSG_SESSION_KEY');
+ return false;
}
switch ($cipher) {
@@ -679,7 +703,8 @@ class SSH1
$response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
- throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
+ user_error('Expected SSH_SMSG_SUCCESS');
+ return false;
}
$this->bitmap = self::MASK_CONNECTED;
@@ -693,8 +718,6 @@ class SSH1
* @param string $username
* @param string $password
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
* @access public
*/
function login($username, $password = '')
@@ -713,7 +736,8 @@ class SSH1
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_USER');
+ user_error('Error sending SSH_CMSG_USER');
+ return false;
}
$response = $this->_get_binary_packet();
@@ -725,13 +749,15 @@ class SSH1
$this->bitmap |= self::MASK_LOGIN;
return true;
} elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
- throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
+ user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
+ return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_AUTH_PASSWORD');
+ user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
+ return false;
}
// remove the username and password from the last logged packet
@@ -751,7 +777,8 @@ class SSH1
} elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
return false;
} else {
- throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
+ user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
+ return false;
}
}
@@ -782,23 +809,24 @@ class SSH1
*
* Returns false on failure and the output, otherwise.
*
- * @see \phpseclib\Net\SSH1::interactiveRead()
- * @see \phpseclib\Net\SSH1::interactiveWrite()
+ * @see self::interactiveRead()
+ * @see self::interactiveWrite()
* @param string $cmd
* @return mixed
- * @throws \RuntimeException on error sending command
* @access public
*/
function exec($cmd, $block = true)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
- throw new \RuntimeException('Operation disallowed prior to login()');
+ user_error('Operation disallowed prior to login()');
+ return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_EXEC_CMD');
+ user_error('Error sending SSH_CMSG_EXEC_CMD');
+ return false;
}
if (!$block) {
@@ -831,11 +859,9 @@ class SSH1
/**
* Creates an interactive shell
*
- * @see \phpseclib\Net\SSH1::interactiveRead()
- * @see \phpseclib\Net\SSH1::interactiveWrite()
+ * @see self::interactiveRead()
+ * @see self::interactiveWrite()
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
* @access private
*/
function _initShell()
@@ -846,7 +872,8 @@ class SSH1
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_REQUEST_PTY');
+ user_error('Error sending SSH_CMSG_REQUEST_PTY');
+ return false;
}
$response = $this->_get_binary_packet();
@@ -855,13 +882,15 @@ class SSH1
return false;
}
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
- throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
+ user_error('Expected SSH_SMSG_SUCCESS');
+ return false;
}
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_EXEC_SHELL');
+ user_error('Error sending SSH_CMSG_EXEC_SHELL');
+ return false;
}
$this->bitmap |= self::MASK_SHELL;
@@ -874,7 +903,7 @@ class SSH1
/**
* Inputs a command into an interactive shell.
*
- * @see \phpseclib\Net\SSH1::interactiveWrite()
+ * @see self::interactiveWrite()
* @param string $cmd
* @return bool
* @access public
@@ -890,21 +919,22 @@ class SSH1
* $expect can take the form of a string literal or, if $mode == self::READ__REGEX,
* a regular expression.
*
- * @see \phpseclib\Net\SSH1::write()
+ * @see self::write()
* @param string $expect
* @param int $mode
* @return bool
- * @throws \RuntimeException on connection error
* @access public
*/
function read($expect, $mode = self::READ__SIMPLE)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
- throw new \RuntimeException('Operation disallowed prior to login()');
+ user_error('Operation disallowed prior to login()');
+ return false;
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
- throw new \RuntimeException('Unable to initiate an interactive shell session');
+ user_error('Unable to initiate an interactive shell session');
+ return false;
}
$match = $expect;
@@ -929,26 +959,28 @@ class SSH1
/**
* Inputs a command into an interactive shell.
*
- * @see \phpseclib\Net\SSH1::interactiveRead()
+ * @see self::interactiveRead()
* @param string $cmd
* @return bool
- * @throws \RuntimeException on connection error
* @access public
*/
function interactiveWrite($cmd)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
- throw new \RuntimeException('Operation disallowed prior to login()');
+ user_error('Operation disallowed prior to login()');
+ return false;
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
- throw new \RuntimeException('Unable to initiate an interactive shell session');
+ user_error('Unable to initiate an interactive shell session');
+ return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Error sending SSH_CMSG_STDIN');
+ user_error('Error sending SSH_CMSG_STDIN');
+ return false;
}
return true;
@@ -963,19 +995,20 @@ class SSH1
* does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
* there's not going to be much recourse.
*
- * @see \phpseclib\Net\SSH1::interactiveRead()
+ * @see self::interactiveRead()
* @return string
- * @throws \RuntimeException on connection error
* @access public
*/
function interactiveRead()
{
if (!($this->bitmap & self::MASK_LOGIN)) {
- throw new \RuntimeException('Operation disallowed prior to login()');
+ user_error('Operation disallowed prior to login()');
+ return false;
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
- throw new \RuntimeException('Unable to initiate an interactive shell session');
+ user_error('Unable to initiate an interactive shell session');
+ return false;
}
$read = array($this->fsock);
@@ -1051,7 +1084,7 @@ class SSH1
* Also, this function could be improved upon by adding detection for the following exploit:
* http://www.securiteam.com/securitynews/5LP042K3FY.html
*
- * @see \phpseclib\Net\SSH1::_send_binary_packet()
+ * @see self::_send_binary_packet()
* @return array
* @access private
*/
@@ -1079,7 +1112,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;
@@ -1100,6 +1137,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) ) {
@@ -1127,7 +1167,7 @@ class SSH1
*
* Returns true on success, false on failure.
*
- * @see \phpseclib\Net\SSH1::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @param string $data
* @return bool
* @access private
@@ -1174,8 +1214,8 @@ class SSH1
* we've reimplemented it. A more detailed discussion of the differences can be found after
* $crc_lookup_table's initialization.
*
- * @see \phpseclib\Net\SSH1::_get_binary_packet()
- * @see \phpseclib\Net\SSH1::_send_binary_packet()
+ * @see self::_get_binary_packet()
+ * @see self::_send_binary_packet()
* @param string $data
* @return int
* @access private
@@ -1291,7 +1331,7 @@ class SSH1
* should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
* calls this call modexp, instead, but I think this makes things clearer, maybe...
*
- * @see \phpseclib\Net\SSH1::__construct()
+ * @see self::__construct()
* @param BigInteger $m
* @param array $key
* @return BigInteger
diff --git a/inc/Exts/phpseclib/Net/SSH2.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
similarity index 86%
rename from inc/Exts/phpseclib/Net/SSH2.php
rename to vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
index 81af5d79..937c38cc 100644
--- a/inc/Exts/phpseclib/Net/SSH2.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
@@ -60,7 +60,6 @@ use phpseclib\Crypt\TripleDES;
use phpseclib\Crypt\Twofish;
use phpseclib\Math\BigInteger; // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
use phpseclib\System\SSH\Agent;
-use phpseclib\Exception\NoSupportedAlgorithmsException;
/**
* Pure-PHP implementation of SSHv2.
@@ -177,8 +176,8 @@ class SSH2
/**
* Error information
*
- * @see \phpseclib\Net\SSH2::getErrors()
- * @see \phpseclib\Net\SSH2::getLastError()
+ * @see self::getErrors()
+ * @see self::getLastError()
* @var string
* @access private
*/
@@ -187,7 +186,7 @@ class SSH2
/**
* Server Identifier
*
- * @see \phpseclib\Net\SSH2::getServerIdentification()
+ * @see self::getServerIdentification()
* @var array|false
* @access private
*/
@@ -196,7 +195,7 @@ class SSH2
/**
* Key Exchange Algorithms
*
- * @see \phpseclib\Net\SSH2::getKexAlgorithims()
+ * @see self::getKexAlgorithims()
* @var array|false
* @access private
*/
@@ -205,7 +204,7 @@ class SSH2
/**
* Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
- * @see Net_SSH2::_key_exchange()
+ * @see self::_key_exchange()
* @var int
* @access private
*/
@@ -214,7 +213,7 @@ class SSH2
/**
* Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
- * @see Net_SSH2::_key_exchange()
+ * @see self::_key_exchange()
* @var int
* @access private
*/
@@ -223,7 +222,7 @@ class SSH2
/**
* Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
- * @see Net_SSH2::_key_exchange()
+ * @see self::_key_exchange()
* @var int
* @access private
*/
@@ -232,7 +231,7 @@ class SSH2
/**
* Server Host Key Algorithms
*
- * @see \phpseclib\Net\SSH2::getServerHostKeyAlgorithms()
+ * @see self::getServerHostKeyAlgorithms()
* @var array|false
* @access private
*/
@@ -241,7 +240,7 @@ class SSH2
/**
* Encryption Algorithms: Client to Server
*
- * @see \phpseclib\Net\SSH2::getEncryptionAlgorithmsClient2Server()
+ * @see self::getEncryptionAlgorithmsClient2Server()
* @var array|false
* @access private
*/
@@ -250,7 +249,7 @@ class SSH2
/**
* Encryption Algorithms: Server to Client
*
- * @see \phpseclib\Net\SSH2::getEncryptionAlgorithmsServer2Client()
+ * @see self::getEncryptionAlgorithmsServer2Client()
* @var array|false
* @access private
*/
@@ -259,7 +258,7 @@ class SSH2
/**
* MAC Algorithms: Client to Server
*
- * @see \phpseclib\Net\SSH2::getMACAlgorithmsClient2Server()
+ * @see self::getMACAlgorithmsClient2Server()
* @var array|false
* @access private
*/
@@ -268,7 +267,7 @@ class SSH2
/**
* MAC Algorithms: Server to Client
*
- * @see \phpseclib\Net\SSH2::getMACAlgorithmsServer2Client()
+ * @see self::getMACAlgorithmsServer2Client()
* @var array|false
* @access private
*/
@@ -277,7 +276,7 @@ class SSH2
/**
* Compression Algorithms: Client to Server
*
- * @see \phpseclib\Net\SSH2::getCompressionAlgorithmsClient2Server()
+ * @see self::getCompressionAlgorithmsClient2Server()
* @var array|false
* @access private
*/
@@ -286,7 +285,7 @@ class SSH2
/**
* Compression Algorithms: Server to Client
*
- * @see \phpseclib\Net\SSH2::getCompressionAlgorithmsServer2Client()
+ * @see self::getCompressionAlgorithmsServer2Client()
* @var array|false
* @access private
*/
@@ -295,7 +294,7 @@ class SSH2
/**
* Languages: Server to Client
*
- * @see \phpseclib\Net\SSH2::getLanguagesServer2Client()
+ * @see self::getLanguagesServer2Client()
* @var array|false
* @access private
*/
@@ -304,7 +303,7 @@ class SSH2
/**
* Languages: Client to Server
*
- * @see \phpseclib\Net\SSH2::getLanguagesClient2Server()
+ * @see self::getLanguagesClient2Server()
* @var array|false
* @access private
*/
@@ -320,8 +319,8 @@ class SSH2
*
* -- http://tools.ietf.org/html/rfc4253#section-6
*
- * @see \phpseclib\Net\SSH2::__construct()
- * @see \phpseclib\Net\SSH2::_send_binary_packet()
+ * @see self::__construct()
+ * @see self::_send_binary_packet()
* @var int
* @access private
*/
@@ -330,8 +329,8 @@ class SSH2
/**
* Block Size for Client to Server Encryption
*
- * @see \phpseclib\Net\SSH2::__construct()
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::__construct()
+ * @see self::_get_binary_packet()
* @var int
* @access private
*/
@@ -340,7 +339,7 @@ class SSH2
/**
* Server to Client Encryption Object
*
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @var object
* @access private
*/
@@ -349,7 +348,7 @@ class SSH2
/**
* Client to Server Encryption Object
*
- * @see \phpseclib\Net\SSH2::_send_binary_packet()
+ * @see self::_send_binary_packet()
* @var object
* @access private
*/
@@ -358,7 +357,7 @@ class SSH2
/**
* Client to Server HMAC Object
*
- * @see \phpseclib\Net\SSH2::_send_binary_packet()
+ * @see self::_send_binary_packet()
* @var object
* @access private
*/
@@ -367,7 +366,7 @@ class SSH2
/**
* Server to Client HMAC Object
*
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @var object
* @access private
*/
@@ -380,7 +379,7 @@ class SSH2
* For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
* append it.
*
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @var int
* @access private
*/
@@ -389,14 +388,14 @@ class SSH2
/**
* Server Public Host Key
*
- * @see \phpseclib\Net\SSH2::getServerPublicHostKey()
+ * @see self::getServerPublicHostKey()
* @var string
* @access private
*/
var $server_public_host_key;
/**
- * Session identifer
+ * Session identifier
*
* "The exchange hash H from the first key exchange is additionally
* used as the session identifier, which is a unique identifier for
@@ -404,7 +403,7 @@ class SSH2
*
* -- http://tools.ietf.org/html/rfc4253#section-7.2
*
- * @see \phpseclib\Net\SSH2::_key_exchange()
+ * @see self::_key_exchange()
* @var string
* @access private
*/
@@ -415,7 +414,7 @@ class SSH2
*
* The current exchange hash
*
- * @see \phpseclib\Net\SSH2::_key_exchange()
+ * @see self::_key_exchange()
* @var string
* @access private
*/
@@ -424,7 +423,7 @@ class SSH2
/**
* Message Numbers
*
- * @see \phpseclib\Net\SSH2::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -433,7 +432,7 @@ class SSH2
/**
* Disconnection Message 'reason codes' defined in RFC4253
*
- * @see \phpseclib\Net\SSH2::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -442,7 +441,7 @@ class SSH2
/**
* SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
*
- * @see \phpseclib\Net\SSH2::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -452,7 +451,7 @@ class SSH2
* Terminal Modes
*
* @link http://tools.ietf.org/html/rfc4254#section-8
- * @see \phpseclib\Net\SSH2::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -462,7 +461,7 @@ class SSH2
* SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
*
* @link http://tools.ietf.org/html/rfc4254#section-5.2
- * @see \phpseclib\Net\SSH2::__construct()
+ * @see self::__construct()
* @var array
* @access private
*/
@@ -473,7 +472,7 @@ class SSH2
*
* See 'Section 6.4. Data Integrity' of rfc4253 for more info.
*
- * @see \phpseclib\Net\SSH2::_send_binary_packet()
+ * @see self::_send_binary_packet()
* @var int
* @access private
*/
@@ -484,7 +483,7 @@ class SSH2
*
* See 'Section 6.4. Data Integrity' of rfc4253 for more info.
*
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @var int
* @access private
*/
@@ -495,8 +494,8 @@ class SSH2
*
* Maps client channels to server channels
*
- * @see \phpseclib\Net\SSH2::_get_channel_packet()
- * @see \phpseclib\Net\SSH2::exec()
+ * @see self::_get_channel_packet()
+ * @see self::exec()
* @var array
* @access private
*/
@@ -508,8 +507,8 @@ class SSH2
* If a client requests a packet from one channel but receives two packets from another those packets should
* be placed in a buffer
*
- * @see \phpseclib\Net\SSH2::_get_channel_packet()
- * @see \phpseclib\Net\SSH2::exec()
+ * @see self::_get_channel_packet()
+ * @see self::exec()
* @var array
* @access private
*/
@@ -520,7 +519,7 @@ class SSH2
*
* Contains the type of the last sent message
*
- * @see \phpseclib\Net\SSH2::_get_channel_packet()
+ * @see self::_get_channel_packet()
* @var array
* @access private
*/
@@ -531,7 +530,7 @@ class SSH2
*
* Maximum packet size indexed by channel
*
- * @see \phpseclib\Net\SSH2::_send_channel_packet()
+ * @see self::_send_channel_packet()
* @var array
* @access private
*/
@@ -540,7 +539,7 @@ class SSH2
/**
* Message Number Log
*
- * @see \phpseclib\Net\SSH2::getLog()
+ * @see self::getLog()
* @var array
* @access private
*/
@@ -549,7 +548,7 @@ class SSH2
/**
* Message Log
*
- * @see \phpseclib\Net\SSH2::getLog()
+ * @see self::getLog()
* @var array
* @access private
*/
@@ -561,8 +560,8 @@ class SSH2
* Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB)
*
* @var int
- * @see \phpseclib\Net\SSH2::_send_channel_packet()
- * @see \phpseclib\Net\SSH2::exec()
+ * @see self::_send_channel_packet()
+ * @see self::exec()
* @access private
*/
var $window_size = 0x7FFFFFFF;
@@ -572,7 +571,7 @@ class SSH2
*
* Window size indexed by channel
*
- * @see \phpseclib\Net\SSH2::_send_channel_packet()
+ * @see self::_send_channel_packet()
* @var array
* @access private
*/
@@ -583,7 +582,7 @@ class SSH2
*
* Window size indexed by channel
*
- * @see \phpseclib\Net\SSH2::_get_channel_packet()
+ * @see self::_get_channel_packet()
* @var array
* @access private
*/
@@ -594,7 +593,7 @@ class SSH2
*
* Verified against $this->session_id
*
- * @see \phpseclib\Net\SSH2::getServerPublicHostKey()
+ * @see self::getServerPublicHostKey()
* @var string
* @access private
*/
@@ -605,7 +604,7 @@ class SSH2
*
* ssh-rsa or ssh-dss.
*
- * @see \phpseclib\Net\SSH2::getServerPublicHostKey()
+ * @see self::getServerPublicHostKey()
* @var string
* @access private
*/
@@ -614,7 +613,7 @@ class SSH2
/**
* Interactive Buffer
*
- * @see \phpseclib\Net\SSH2::read()
+ * @see self::read()
* @var array
* @access private
*/
@@ -625,8 +624,8 @@ class SSH2
*
* Should never exceed self::LOG_MAX_SIZE
*
- * @see \phpseclib\Net\SSH2::_send_binary_packet()
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_send_binary_packet()
+ * @see self::_get_binary_packet()
* @var int
* @access private
*/
@@ -635,7 +634,7 @@ class SSH2
/**
* Timeout
*
- * @see \phpseclib\Net\SSH2::setTimeout()
+ * @see self::setTimeout()
* @access private
*/
var $timeout;
@@ -643,7 +642,7 @@ class SSH2
/**
* Current Timeout
*
- * @see \phpseclib\Net\SSH2::_get_channel_packet()
+ * @see self::_get_channel_packet()
* @access private
*/
var $curTimeout;
@@ -651,7 +650,7 @@ class SSH2
/**
* Real-time log file pointer
*
- * @see \phpseclib\Net\SSH2::_append_log()
+ * @see self::_append_log()
* @var resource
* @access private
*/
@@ -660,7 +659,7 @@ class SSH2
/**
* Real-time log file size
*
- * @see \phpseclib\Net\SSH2::_append_log()
+ * @see self::_append_log()
* @var int
* @access private
*/
@@ -669,7 +668,7 @@ class SSH2
/**
* Has the signature been validated?
*
- * @see \phpseclib\Net\SSH2::getServerPublicHostKey()
+ * @see self::getServerPublicHostKey()
* @var bool
* @access private
*/
@@ -678,7 +677,7 @@ class SSH2
/**
* Real-time log file wrap boolean
*
- * @see \phpseclib\Net\SSH2::_append_log()
+ * @see self::_append_log()
* @access private
*/
var $realtime_log_wrap;
@@ -686,7 +685,7 @@ class SSH2
/**
* Flag to suppress stderr from output
*
- * @see \phpseclib\Net\SSH2::enableQuietMode()
+ * @see self::enableQuietMode()
* @access private
*/
var $quiet_mode = false;
@@ -711,7 +710,7 @@ class SSH2
* Flag to request a PTY when using exec()
*
* @var bool
- * @see \phpseclib\Net\SSH2::enablePTY()
+ * @see self::enablePTY()
* @access private
*/
var $request_pty = false;
@@ -743,7 +742,7 @@ class SSH2
/**
* The Last Interactive Response
*
- * @see \phpseclib\Net\SSH2::_keyboard_interactive_process()
+ * @see self::_keyboard_interactive_process()
* @var string
* @access private
*/
@@ -752,7 +751,7 @@ class SSH2
/**
* Keyboard Interactive Request / Responses
*
- * @see \phpseclib\Net\SSH2::_keyboard_interactive_process()
+ * @see self::_keyboard_interactive_process()
* @var array
* @access private
*/
@@ -764,8 +763,8 @@ class SSH2
* Quoting from the RFC, "in some jurisdictions, sending a warning message before
* authentication may be relevant for getting legal protection."
*
- * @see \phpseclib\Net\SSH2::_filter()
- * @see \phpseclib\Net\SSH2::getBannerMessage()
+ * @see self::_filter()
+ * @see self::getBannerMessage()
* @var string
* @access private
*/
@@ -774,7 +773,7 @@ class SSH2
/**
* Did read() timeout or return normally?
*
- * @see \phpseclib\Net\SSH2::isTimeout()
+ * @see self::isTimeout()
* @var bool
* @access private
*/
@@ -783,7 +782,7 @@ class SSH2
/**
* Log Boundary
*
- * @see \phpseclib\Net\SSH2::_format_log()
+ * @see self::_format_log()
* @var string
* @access private
*/
@@ -792,7 +791,7 @@ class SSH2
/**
* Log Long Width
*
- * @see \phpseclib\Net\SSH2::_format_log()
+ * @see self::_format_log()
* @var int
* @access private
*/
@@ -801,7 +800,7 @@ class SSH2
/**
* Log Short Width
*
- * @see \phpseclib\Net\SSH2::_format_log()
+ * @see self::_format_log()
* @var int
* @access private
*/
@@ -810,8 +809,8 @@ class SSH2
/**
* Hostname
*
- * @see \phpseclib\Net\SSH2::__construct()
- * @see \phpseclib\Net\SSH2::_connect()
+ * @see self::__construct()
+ * @see self::_connect()
* @var string
* @access private
*/
@@ -820,8 +819,8 @@ class SSH2
/**
* Port Number
*
- * @see \phpseclib\Net\SSH2::__construct()
- * @see \phpseclib\Net\SSH2::_connect()
+ * @see self::__construct()
+ * @see self::_connect()
* @var int
* @access private
*/
@@ -830,9 +829,9 @@ class SSH2
/**
* Number of columns for terminal window size
*
- * @see \phpseclib\Net\SSH2::getWindowColumns()
- * @see \phpseclib\Net\SSH2::setWindowColumns()
- * @see \phpseclib\Net\SSH2::setWindowSize()
+ * @see self::getWindowColumns()
+ * @see self::setWindowColumns()
+ * @see self::setWindowSize()
* @var int
* @access private
*/
@@ -841,9 +840,9 @@ class SSH2
/**
* Number of columns for terminal window size
*
- * @see \phpseclib\Net\SSH2::getWindowRows()
- * @see \phpseclib\Net\SSH2::setWindowRows()
- * @see \phpseclib\Net\SSH2::setWindowSize()
+ * @see self::getWindowRows()
+ * @see self::setWindowRows()
+ * @see self::setWindowSize()
* @var int
* @access private
*/
@@ -852,8 +851,8 @@ class SSH2
/**
* Crypto Engine
*
- * @see Net_SSH2::setCryptoEngine()
- * @see Net_SSH2::_key_exchange()
+ * @see self::setCryptoEngine()
+ * @see self::_key_exchange()
* @var int
* @access private
*/
@@ -867,14 +866,6 @@ class SSH2
*/
var $agent;
- /**
- * Connection storage to replicates ssh2 extension functionality:
- * {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
- *
- * @var SSH2[]
- */
- static $connections;
-
/**
* Default Constructor.
*
@@ -883,7 +874,7 @@ class SSH2
* @param mixed $host
* @param int $port
* @param int $timeout
- * @see \phpseclib\Net\SSH2::login()
+ * @see self::login()
* @return \phpseclib\Net\SSH2
* @access public
*/
@@ -968,8 +959,6 @@ class SSH2
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
);
- self::$connections[$this->getResourceId()] = $this;
-
if (is_resource($host)) {
$this->fsock = $host;
return;
@@ -1000,8 +989,6 @@ class SSH2
* Connect to an SSHv2 server
*
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
* @access private
*/
function _connect()
@@ -1018,10 +1005,14 @@ 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"));
+ user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
+ return false;
}
$elapsed = microtime(true) - $start;
@@ -1033,6 +1024,10 @@ class SSH2
}
}
+ $this->identifier = $this->_generate_identifier();
+
+ fputs($this->fsock, $this->identifier . "\r\n");
+
/* According to the SSH2 specs,
"The server MAY send other lines of data before sending the version
@@ -1040,66 +1035,84 @@ class SSH2
Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
MUST be able to process such lines." */
- $temp = '';
- $extra = '';
- while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
- if (substr($temp, -2) == "\r\n") {
- $extra.= $temp;
- $temp = '';
+ $data = '';
+ while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms', $data, $matches)) {
+ $line = '';
+ while (true) {
+ if ($this->curTimeout) {
+ if ($this->curTimeout < 0) {
+ $this->is_timeout = true;
+ return false;
+ }
+ $read = array($this->fsock);
+ $write = $except = null;
+ $start = microtime(true);
+ $sec = floor($this->curTimeout);
+ $usec = 1000000 * ($this->curTimeout - $sec);
+ // on windows this returns a "Warning: Invalid CRT parameters detected" error
+ // the !count() is done as a workaround for
+ if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
+ $this->is_timeout = true;
+ return false;
+ }
+ $elapsed = microtime(true) - $start;
+ $this->curTimeout-= $elapsed;
+ }
+
+ $temp = stream_get_line($this->fsock, 255, "\n");
+ if (strlen($temp) == 255) {
+ continue;
+ }
+
+ $line.= "$temp\n";
+
+ // quoting RFC4253, "Implementers who wish to maintain
+ // compatibility with older, undocumented versions of this protocol may
+ // want to process the identification string without expecting the
+ // presence of the carriage return character for reasons described in
+ // Section 5 of this document."
+
+ //if (substr($line, -2) == "\r\n") {
+ // break;
+ //}
+
+ break;
}
- if ($this->curTimeout) {
- if ($this->curTimeout < 0) {
- $this->is_timeout = true;
- return false;
- }
- $read = array($this->fsock);
- $write = $except = null;
- $start = microtime(true);
- $sec = floor($this->curTimeout);
- $usec = 1000000 * ($this->curTimeout - $sec);
- // on windows this returns a "Warning: Invalid CRT parameters detected" error
- // the !count() is done as a workaround for
- if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
- $this->is_timeout = true;
- return false;
- }
- $elapsed = microtime(true) - $start;
- $this->curTimeout-= $elapsed;
- }
-
- $temp.= fgets($this->fsock, 255);
+ $data.= $line;
}
if (feof($this->fsock)) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
- $this->identifier = $this->_generate_identifier();
+ $extra = $matches[1];
if (defined('NET_SSH2_LOGGING')) {
- $this->_append_log('<-', $extra . $temp);
+ $this->_append_log('<-', $matches[0]);
$this->_append_log('->', $this->identifier . "\r\n");
}
$this->server_identifier = trim($temp, "\r\n");
if (strlen($extra)) {
- $this->errors[] = utf8_decode($extra);
+ $this->errors[] = utf8_decode($data);
}
- if ($matches[1] != '1.99' && $matches[1] != '2.0') {
- throw new \RuntimeException("Cannot connect to SSH $matches[1] servers");
+ if ($matches[3] != '1.99' && $matches[3] != '2.0') {
+ user_error("Cannot connect to SSH $matches[3] servers");
+ return false;
}
- fputs($this->fsock, $this->identifier . "\r\n");
-
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
- if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
- throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
+ if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
+ user_error('Expected SSH_MSG_KEXINIT');
+ return false;
}
if (!$this->_key_exchange($response)) {
@@ -1151,9 +1164,6 @@ class SSH2
* Key Exchange
*
* @param string $kexinit_payload_server
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
- * @throws \phpseclib\Exception\NoSupportedAlgorithmsException when none of the algorithms phpseclib has loaded are compatible
* @access private
*/
function _key_exchange($kexinit_payload_server)
@@ -1171,7 +1181,7 @@ class SSH2
'diffie-hellman-group-exchange-sha1', // RFC 4419
'diffie-hellman-group-exchange-sha256', // RFC 4419
);
- if (!class_exists('\Sodium')) {
+ if (!function_exists('\\Sodium\\library_version_major')) {
$kex_algorithms = array_diff(
$kex_algorithms,
array('curve25519-sha256@libssh.org')
@@ -1297,36 +1307,69 @@ class 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;
@@ -1365,28 +1408,27 @@ class SSH2
// here ends the second place.
// we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
-
// we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
// diffie-hellman key exchange as fast as possible
$decrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_server_to_client);
$decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
if ($decryptKeyLength === null) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible server to client encryption algorithms found');
+ user_error('No compatible server to client encryption algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$encrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_client_to_server);
$encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
if ($encryptKeyLength === null) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible client to server encryption algorithms found');
+ user_error('No compatible client to server encryption algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
// through diffie-hellman key exchange a symmetric key is obtained
$kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
if ($kex_algorithm === false) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible key exchange algorithms found');
+ user_error('No compatible key exchange algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
// Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
@@ -1394,7 +1436,7 @@ class SSH2
if ($kex_algorithm === 'curve25519-sha256@libssh.org') {
$x = Random::string(32);
- $eBytes = \Sodium::crypto_box_publickey_from_secretkey($x);
+ $eBytes = \Sodium\crypto_box_publickey_from_secretkey($x);
$clientKexInitMessage = NET_SSH2_MSG_KEX_ECDH_INIT;
$serverKexReplyMessage = NET_SSH2_MSG_KEX_ECDH_REPLY;
$kexHash = new Hash('sha256');
@@ -1426,10 +1468,16 @@ class SSH2
return false;
}
+ if (strlen($response) < 4) {
+ return false;
+ }
extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
$primeBytes = $this->_string_shift($response, $primeLength);
$prime = new 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 BigInteger($gBytes, -256);
@@ -1503,31 +1551,52 @@ class SSH2
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
if (!$this->_send_binary_packet($data)) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
+ }
+ if (!strlen($response)) {
+ return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != $serverKexReplyMessage) {
- throw new \UnexpectedValueException('Expected SSH_MSG_KEXDH_REPLY');
+ user_error('Expected SSH_MSG_KEXDH_REPLY');
+ 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']);
+ 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']);
@@ -1536,8 +1605,8 @@ class SSH2
user_error('Received curve25519 public key of invalid length.');
return false;
}
- $key = new BigInteger(\Sodium::crypto_scalarmult($x, $fBytes), 256);
- \Sodium::sodium_memzero($x);
+ $key = new BigInteger(\Sodium\crypto_scalarmult($x, $fBytes), 256);
+ \Sodium\memzero($x);
} else {
$f = new BigInteger($fBytes, -256);
$key = $f->modPow($x, $prime);
@@ -1573,13 +1642,13 @@ class SSH2
$server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
if ($server_host_key_algorithm === false) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible server host key algorithms found');
+ user_error('No compatible server host key algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new \RuntimeException('Server Host Key Algorithm Mismatch');
+ user_error('Server Host Key Algorithm Mismatch');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$packet = pack(
@@ -1594,13 +1663,18 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ 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_NEWKEYS) {
- throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS');
+ user_error('Expected SSH_MSG_NEWKEYS');
+ return false;
}
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
@@ -1669,8 +1743,8 @@ class SSH2
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
if ($mac_algorithm === false) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible client to server message authentication algorithms found');
+ user_error('No compatible client to server message authentication algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$createKeyLength = 0; // ie. $mac_algorithm == 'none'
@@ -1698,8 +1772,8 @@ class SSH2
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_server_to_client);
if ($mac_algorithm === false) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible server to client message authentication algorithms found');
+ user_error('No compatible server to client message authentication algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$checkKeyLength = 0;
@@ -1745,15 +1819,15 @@ class SSH2
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
if ($compression_algorithm === false) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible server to client compression algorithms found');
+ user_error('No compatible server to client compression algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$this->decompress = $compression_algorithm == 'zlib';
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
if ($compression_algorithm === false) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new NoSupportedAlgorithmsException('No compatible client to server compression algorithms found');
+ user_error('No compatible client to server compression algorithms found');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$this->compress = $compression_algorithm == 'zlib';
@@ -1852,7 +1926,7 @@ class SSH2
* @param mixed $password
* @param mixed $...
* @return bool
- * @see _login
+ * @see self::_login()
* @access public
*/
function login($username)
@@ -1868,7 +1942,7 @@ class SSH2
* @param mixed $password
* @param mixed $...
* @return bool
- * @see _login_helper
+ * @see self::_login_helper()
* @access private
*/
function _login($username)
@@ -1898,8 +1972,6 @@ class SSH2
* @param string $username
* @param string $password
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
* @access private
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
* by sending dummy SSH_MSG_IGNORE messages.
@@ -1924,13 +1996,18 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
+ if (strlen($response) < 4) {
+ return false;
+ }
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
- throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT');
+ user_error('Expected SSH_MSG_SERVICE_ACCEPT');
+ return false;
}
$this->bitmap |= self::MASK_LOGIN_REQ;
}
@@ -1971,9 +2048,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
+ if (!strlen($response)) {
+ return false;
+ }
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
@@ -2025,9 +2106,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
+ if (!strlen($response)) {
+ return false;
+ }
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
@@ -2035,14 +2120,23 @@ 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', $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;
@@ -2101,7 +2195,6 @@ class SSH2
*
* @param string $responses...
* @return bool
- * @throws \RuntimeException on connection error
* @access private
*/
function _keyboard_interactive_process()
@@ -2113,20 +2206,36 @@ class SSH2
} else {
$orig = $response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
}
+ 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++) {
@@ -2141,6 +2250,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', $this->_string_shift($response, 4)));
// prompt - ie. "Password: "; must not be empty
$prompt = $this->_string_shift($response, $length);
@@ -2237,7 +2349,6 @@ class SSH2
* @param string $username
* @param \phpseclib\Crypt\RSA $password
* @return bool
- * @throws \RuntimeException on connection error
* @access private
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
* by sending dummy SSH_MSG_IGNORE messages.
@@ -2283,13 +2394,20 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ 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;
@@ -2317,9 +2435,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
+ if (!strlen($response)) {
+ return false;
+ }
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
@@ -2367,7 +2489,6 @@ class SSH2
* @param string $command
* @param Callback $callback
* @return string
- * @throws \RuntimeException on connection error
* @access public
*/
function exec($command, $callback = null)
@@ -2376,13 +2497,18 @@ 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;
}
// 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 transfering more than 2GB, you probably shouldn't be using phpseclib, anyway.
+ // honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway.
// see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
$this->window_size_server_to_client[self::CHANNEL_EXEC] = $this->window_size;
// 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
@@ -2435,9 +2561,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
+ if (!strlen($response)) {
+ return false;
+ }
list(, $type) = unpack('C', $this->_string_shift($response, 1));
switch ($type) {
@@ -2445,8 +2575,8 @@ class SSH2
break;
case NET_SSH2_MSG_CHANNEL_FAILURE:
default:
- $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
- throw new \RuntimeException('Unable to request pseudo-terminal');
+ user_error('Unable to request pseudo-terminal');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
$this->in_request_pty_exec = true;
}
@@ -2511,11 +2641,9 @@ class SSH2
/**
* Creates an interactive shell
*
- * @see \phpseclib\Net\SSH2::read()
- * @see \phpseclib\Net\SSH2::write()
+ * @see self::read()
+ * @see self::write()
* @return bool
- * @throws \UnexpectedValueException on receipt of unexpected packets
- * @throws \RuntimeException on other errors
* @access private
*/
function _initShell()
@@ -2572,9 +2700,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
+ if (!strlen($response)) {
+ return false;
+ }
list(, $type) = unpack('C', $this->_string_shift($response, 1));
switch ($type) {
@@ -2583,8 +2715,8 @@ class SSH2
case NET_SSH2_MSG_CHANNEL_FAILURE:
break;
default:
- $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
- throw new \UnexpectedValueException('Unable to request pseudo-terminal');
+ user_error('Unable to request pseudo-terminal');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
$packet = pack(
@@ -2616,8 +2748,8 @@ class SSH2
/**
* Return the channel to be used with read() / write()
*
- * @see \phpseclib\Net\SSH2::read()
- * @see \phpseclib\Net\SSH2::write()
+ * @see self::read()
+ * @see self::write()
* @return int
* @access public
*/
@@ -2657,11 +2789,10 @@ class SSH2
* Returns when there's a match for $expect, which can take the form of a string literal or,
* if $mode == self::READ_REGEX, a regular expression.
*
- * @see \phpseclib\Net\SSH2::write()
+ * @see self::write()
* @param string $expect
* @param int $mode
* @return string
- * @throws \RuntimeException on connection error
* @access public
*/
function read($expect = '', $mode = self::READ_SIMPLE)
@@ -2669,12 +2800,14 @@ class SSH2
$this->curTimeout = $this->timeout;
$this->is_timeout = false;
- if (!($this->bitmap & self::MASK_LOGIN)) {
- throw new \RuntimeException('Operation disallowed prior to login()');
+ if (!$this->isAuthenticated()) {
+ user_error('Operation disallowed prior to login()');
+ return false;
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
- throw new \RuntimeException('Unable to initiate an interactive shell session');
+ user_error('Unable to initiate an interactive shell session');
+ return false;
}
$channel = $this->_get_interactive_channel();
@@ -2702,20 +2835,21 @@ class SSH2
/**
* Inputs a command into an interactive shell.
*
- * @see \phpseclib\Net\SSH2::read()
+ * @see self::read()
* @param string $cmd
* @return bool
- * @throws \RuntimeException on connection error
* @access public
*/
function write($cmd)
{
- if (!($this->bitmap & self::MASK_LOGIN)) {
- throw new \RuntimeException('Operation disallowed prior to login()');
+ if (!$this->isAuthenticated()) {
+ user_error('Operation disallowed prior to login()');
+ return false;
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
- throw new \RuntimeException('Unable to initiate an interactive shell session');
+ user_error('Unable to initiate an interactive shell session');
+ return false;
}
return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
@@ -2730,7 +2864,7 @@ class SSH2
* returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented
* if there's sufficient demand for such a feature.
*
- * @see \phpseclib\Net\SSH2::stopSubsystem()
+ * @see self::stopSubsystem()
* @param string $subsystem
* @return bool
* @access public
@@ -2793,7 +2927,7 @@ class SSH2
/**
* Stops a subsystem.
*
- * @see \phpseclib\Net\SSH2::startSubsystem()
+ * @see self::startSubsystem()
* @return bool
* @access public
*/
@@ -2839,7 +2973,6 @@ class SSH2
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
fclose($this->realtime_log_file);
}
- unset(self::$connections[$this->getResourceId()]);
}
/**
@@ -2866,25 +2999,36 @@ class SSH2
return (bool) ($this->bitmap & self::MASK_CONNECTED);
}
+ /**
+ * Have you successfully been logged in?
+ *
+ * @return bool
+ * @access public
+ */
+ function isAuthenticated()
+ {
+ return (bool) ($this->bitmap & self::MASK_LOGIN);
+ }
+
/**
* Gets Binary Packets
*
* See '6. Binary Packet Protocol' of rfc4253 for more info.
*
- * @see \phpseclib\Net\SSH2::_send_binary_packet()
+ * @see self::_send_binary_packet()
* @return string
- * @throws \RuntimeException on connection errors
* @access private
*/
function _get_binary_packet()
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
+ user_error('Connection closed prematurely');
$this->bitmap = 0;
- throw new \RuntimeException('Connection closed prematurely');
+ return false;
}
$start = microtime(true);
- $raw = fread($this->fsock, $this->decrypt_block_size);
+ $raw = stream_get_contents($this->fsock, $this->decrypt_block_size);
if (!strlen($raw)) {
return '';
@@ -2894,9 +3038,13 @@ class SSH2
$raw = $this->decrypt->decrypt($raw);
}
if ($raw === false) {
- throw new \RuntimeException('Unable to decrypt content');
+ user_error('Unable to decrypt content');
+ 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;
@@ -2905,15 +3053,17 @@ class SSH2
// "implementations SHOULD check that the packet length is reasonable"
// PuTTY uses 0x9000 as the actual max packet size and so to shall we
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
- throw new \RuntimeException('Invalid size');
+ user_error('Invalid size');
+ return false;
}
$buffer = '';
while ($remaining_length > 0) {
- $temp = fread($this->fsock, $remaining_length);
+ $temp = stream_get_contents($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) {
+ user_error('Error reading from socket');
$this->bitmap = 0;
- throw new \RuntimeException('Error reading from socket');
+ return false;
}
$buffer.= $temp;
$remaining_length-= strlen($temp);
@@ -2927,12 +3077,14 @@ class SSH2
$padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
if ($this->hmac_check !== false) {
- $hmac = fread($this->fsock, $this->hmac_size);
+ $hmac = stream_get_contents($this->fsock, $this->hmac_size);
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
+ user_error('Error reading socket');
$this->bitmap = 0;
- throw new \RuntimeException('Error reading socket');
+ return false;
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
- throw new \RuntimeException('Invalid HMAC');
+ user_error('Invalid HMAC');
+ return false;
}
}
@@ -2959,7 +3111,7 @@ class SSH2
*
* Because some binary packets need to be ignored...
*
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @return string
* @access private
*/
@@ -2968,6 +3120,9 @@ class 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;
@@ -2977,6 +3132,9 @@ class 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();
@@ -2994,17 +3152,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) {
$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();
}
// 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', $this->_string_shift($payload, 4)));
$this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length);
@@ -3016,8 +3180,14 @@ class 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':
@@ -3025,6 +3195,9 @@ class SSH2
if (isset($this->agent)) {
$new_channel = self::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)));
@@ -3070,6 +3243,9 @@ class 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;
@@ -3108,9 +3284,8 @@ class SSH2
/**
* Returns whether Quiet Mode is enabled or not
*
- * @see \phpseclib\Net\SSH2::enableQuietMode()
- * @see \phpseclib\Net\SSH2::disableQuietMode()
- *
+ * @see self::enableQuietMode()
+ * @see self::disableQuietMode()
* @access public
* @return bool
*/
@@ -3136,15 +3311,18 @@ class SSH2
*/
function disablePTY()
{
+ if ($this->in_request_pty_exec) {
+ $this->_close_channel(self::CHANNEL_EXEC);
+ $this->in_request_pty_exec = false;
+ }
$this->request_pty = false;
}
/**
* Returns whether request-pty is enabled or not
*
- * @see \phpseclib\Net\SSH2::enablePTY()
- * @see \phpseclib\Net\SSH2::disablePTY()
- *
+ * @see self::enablePTY()
+ * @see self::disablePTY()
* @access public
* @return bool
*/
@@ -3160,7 +3338,6 @@ class SSH2
*
* @param $client_channel
* @return mixed
- * @throws \RuntimeException on connection error
* @access private
*/
function _get_channel_packet($client_channel, $skip_extended = false)
@@ -3193,7 +3370,8 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
- throw new \RuntimeException('Connection closed by server');
+ user_error('Connection closed by server');
+ return false;
}
if ($client_channel == -1 && $response === true) {
return true;
@@ -3202,8 +3380,14 @@ class 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 {
@@ -3227,14 +3411,23 @@ 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', $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);
@@ -3242,8 +3435,8 @@ class SSH2
return $result;
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
default:
- $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
- throw new \RuntimeException('Unable to open channel');
+ user_error('Unable to open channel');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
break;
case NET_SSH2_MSG_CHANNEL_REQUEST:
@@ -3253,8 +3446,8 @@ class SSH2
case NET_SSH2_MSG_CHANNEL_FAILURE:
return false;
default:
- $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
- throw new \RuntimeException('Unable to fulfill channel request');
+ user_error('Unable to fulfill channel request');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
case NET_SSH2_MSG_CHANNEL_CLOSE:
return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended);
@@ -3274,6 +3467,9 @@ class 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);
@@ -3300,6 +3496,9 @@ 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', $this->_string_shift($response, 8)));
$data = $this->_string_shift($response, $length);
$this->stdErrorLog.= $data;
@@ -3315,14 +3514,23 @@ class 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);
@@ -3335,6 +3543,9 @@ class 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;
@@ -3359,12 +3570,14 @@ class SSH2
}
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
- return true;
+ if ($client_channel == $channel) {
+ return true;
+ }
case NET_SSH2_MSG_CHANNEL_EOF:
break;
default:
- $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
- throw new \RuntimeException('Error reading channel data');
+ user_error('Error reading channel data');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
}
@@ -3376,15 +3589,16 @@ class SSH2
*
* @param string $data
* @param string $logged
- * @see \phpseclib\Net\SSH2::_get_binary_packet()
+ * @see self::_get_binary_packet()
* @return bool
* @access private
*/
function _send_binary_packet($data, $logged = null)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
+ user_error('Connection closed prematurely');
$this->bitmap = 0;
- throw new \RuntimeException('Connection closed prematurely');
+ return false;
}
//if ($this->compress) {
@@ -3665,10 +3879,9 @@ class SSH2
switch (NET_SSH2_LOGGING) {
case self::LOG_SIMPLE:
return $this->message_number_log;
- break;
case self::LOG_COMPLEX:
- return $this->_format_log($this->message_log, $this->message_number_log);
- break;
+ $log = $this->_format_log($this->message_log, $this->message_number_log);
+ return PHP_SAPI == 'cli' ? $log : '' . $log . '
';
default:
return false;
}
@@ -3760,7 +3973,7 @@ class SSH2
/**
* Returns all errors
*
- * @return string
+ * @return string[]
* @access public
*/
function getErrors()
@@ -3776,7 +3989,11 @@ class SSH2
*/
function getLastError()
{
- return $this->errors[count($this->errors) - 1];
+ $count = count($this->errors);
+
+ if ($count > 0) {
+ return $this->errors[$count - 1];
+ }
}
/**
@@ -3943,8 +4160,6 @@ class SSH2
* is recommended. Returns false if the server signature is not signed correctly with the public host key.
*
* @return mixed
- * @throws \RuntimeException on badly formatted keys
- * @throws \phpseclib\Exception\NoSupportedAlgorithmsException when the key isn't in a supported format
* @access public
*/
function getServerPublicHostKey()
@@ -3958,6 +4173,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', $this->_string_shift($server_public_host_key, 4)));
$this->_string_shift($server_public_host_key, $length);
@@ -3973,15 +4191,27 @@ class SSH2
case 'ssh-dss':
$zero = new BigInteger();
+ if (strlen($server_public_host_key) < 4) {
+ return false;
+ }
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$p = new 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 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 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 BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
@@ -3990,8 +4220,8 @@ class SSH2
padding, unsigned, and in network byte order). */
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
if ($temp['length'] != 40) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new \RuntimeException('Invalid signature');
+ user_error('Invalid signature');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$r = new BigInteger($this->_string_shift($signature, 20), 256);
@@ -4002,8 +4232,8 @@ class SSH2
case $r->compare($q) >= 0:
case $s->equals($zero):
case $s->compare($q) >= 0:
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new \RuntimeException('Invalid signature');
+ user_error('Invalid signature');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$w = $s->modInverse($q);
@@ -4022,21 +4252,30 @@ class SSH2
list(, $v) = $v->divide($q);
if (!$v->equals($r)) {
- //user_error('Bad server signature');
+ user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
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 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 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']);
@@ -4044,11 +4283,14 @@ class SSH2
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
$rsa->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW);
if (!$rsa->verify($this->exchange_hash, $signature)) {
- //user_error('Bad server signature');
+ user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
*/
+ if (strlen($signature) < 4) {
+ return false;
+ }
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
$s = new BigInteger($this->_string_shift($signature, $temp['length']), 256);
@@ -4059,8 +4301,8 @@ class SSH2
// also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
- $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
- throw new \RuntimeException('Invalid signature');
+ user_error('Invalid signature');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$s = $s->modPow($e, $n);
@@ -4070,13 +4312,13 @@ class SSH2
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) {
- //user_error('Bad server signature');
+ user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
default:
- $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
- throw new NoSupportedAlgorithmsException('Unsupported signature format');
+ user_error('Unsupported signature format');
+ return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
@@ -4152,47 +4394,4 @@ class SSH2
$this->windowColumns = $columns;
$this->windowRows = $rows;
}
-
- /**
- * @return string
- */
- function __toString()
- {
- return $this->getResourceId();
- }
-
- /**
- * We use {} because that symbols should not be in URL according to
- * {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}.
- * It will safe us from any conflicts, because otherwise regexp will
- * match all alphanumeric domains.
- *
- * @return string
- */
- function getResourceId()
- {
- return '{' . spl_object_hash($this) . '}';
- }
-
- /**
- * Return existing connection
- *
- * @param string $id
- *
- * @return bool|SSH2 will return false if no such connection
- */
- static function getConnectionByResourceId($id)
- {
- return isset(self::$connections[$id]) ? self::$connections[$id] : false;
- }
-
- /**
- * Return all excising connections
- *
- * @return SSH2[]
- */
- static function getConnections()
- {
- return self::$connections;
- }
}
diff --git a/inc/Exts/phpseclib/System/SSH/Agent.php b/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
similarity index 90%
rename from inc/Exts/phpseclib/System/SSH/Agent.php
rename to vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
index 11a1f83f..a4ff0549 100644
--- a/inc/Exts/phpseclib/System/SSH/Agent.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
@@ -115,8 +115,6 @@ class Agent
* Default Constructor
*
* @return \phpseclib\System\SSH\Agent
- * @throws \phpseclib\Exception\BadConfigurationException if SSH_AUTH_SOCK cannot be found
- * @throws \RuntimeException on connection errors
* @access public
*/
function __construct()
@@ -129,12 +127,13 @@ class Agent
$address = $_ENV['SSH_AUTH_SOCK'];
break;
default:
- throw new \BadConfigurationException('SSH_AUTH_SOCK not found');
+ user_error('SSH_AUTH_SOCK not found');
+ return false;
}
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
if (!$this->fsock) {
- throw new \RuntimeException("Unable to connect to ssh-agent (Error $errno: $errstr)");
+ user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
}
@@ -145,7 +144,6 @@ class Agent
* Returns an array containing zero or more \phpseclib\System\SSH\Agent\Identity objects
*
* @return array
- * @throws \RuntimeException on receipt of unexpected packets
* @access public
*/
function requestIdentities()
@@ -156,13 +154,13 @@ class Agent
$packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
- throw new \RuntimeException('Connection closed while requesting identities');
+ user_error('Connection closed while requesting identities');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
- throw new \RuntimeException('Unable to request identities');
+ user_error('Unable to request identities');
}
$identities = array();
@@ -170,14 +168,17 @@ class Agent
for ($i = 0; $i < $keyCount; $i++) {
$length = current(unpack('N', fread($this->fsock, 4)));
$key_blob = fread($this->fsock, $length);
+ $key_str = 'ssh-rsa ' . base64_encode($key_blob);
$length = current(unpack('N', fread($this->fsock, 4)));
- $key_comment = fread($this->fsock, $length);
+ if ($length) {
+ $key_str.= ' ' . fread($this->fsock, $length);
+ }
$length = current(unpack('N', substr($key_blob, 0, 4)));
$key_type = substr($key_blob, 4, $length);
switch ($key_type) {
case 'ssh-rsa':
$key = new RSA();
- $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment);
+ $key->loadKey($key_str);
break;
case 'ssh-dss':
// not currently supported
@@ -273,7 +274,6 @@ class Agent
*
* @param string $data
* @return data from SSH Agent
- * @throws \RuntimeException on connection errors
* @access private
*/
function _forward_data($data)
@@ -292,7 +292,7 @@ class Agent
}
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
- throw new \RuntimeException('Connection closed attempting to forward data to SSH agent');
+ user_error('Connection closed attempting to forward data to SSH agent');
}
$this->socket_buffer = '';
diff --git a/inc/Exts/phpseclib/System/SSH/Agent/Identity.php b/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php
similarity index 87%
rename from inc/Exts/phpseclib/System/SSH/Agent/Identity.php
rename to vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php
index 42a4dae2..b8cc6cde 100644
--- a/inc/Exts/phpseclib/System/SSH/Agent/Identity.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php
@@ -23,9 +23,8 @@ use phpseclib\System\SSH\Agent;
* Instantiation should only be performed by \phpseclib\System\SSH\Agent class.
* This could be thought of as implementing an interface that phpseclib\Crypt\RSA
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
- * The methods in this interface would be getPublicKey, setSignatureMode
- * and sign since those are the methods phpseclib looks for to perform
- * public key authentication.
+ * The methods in this interface would be getPublicKey and sign since those are the
+ * methods phpseclib looks for to perform public key authentication.
*
* @package SSH\Agent
* @author Jim Wigginton
@@ -38,7 +37,7 @@ class Identity
*
* @var \phpseclib\Crypt\RSA
* @access private
- * @see \phpseclib\System\SSH\Agent\Identity::getPublicKey()
+ * @see self::getPublicKey()
*/
var $key;
@@ -47,7 +46,7 @@ class Identity
*
* @var string
* @access private
- * @see \phpseclib\System\SSH\Agent\Identity::sign()
+ * @see self::sign()
*/
var $key_blob;
@@ -56,7 +55,7 @@ class Identity
*
* @var resource
* @access private
- * @see \phpseclib\System\SSH\Agent\Identity::sign()
+ * @see self::sign()
*/
var $fsock;
@@ -134,7 +133,6 @@ class Identity
*
* @param string $message
* @return string
- * @throws \RuntimeException on connection errors
* @access public
*/
function sign($message)
@@ -143,13 +141,13 @@ class Identity
$packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
- throw new \RuntimeException('Connection closed during signing');
+ user_error('Connection closed during signing');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
- throw new \RuntimeException('Unable to retreive signature');
+ user_error('Unable to retrieve signature');
}
$signature_blob = fread($this->fsock, $length - 1);
diff --git a/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php b/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php
new file mode 100644
index 00000000..0da0999f
--- /dev/null
+++ b/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php
@@ -0,0 +1,16 @@
+