contrib modules security updates

This commit is contained in:
Bachir Soussi Chiadmi
2016-10-13 12:10:40 +02:00
parent ffd758abc9
commit 747127f643
732 changed files with 67976 additions and 23207 deletions

View File

@@ -66,6 +66,8 @@ class ParserCSVIterator implements Iterator {
*/
class ParserCSV {
private $delimiter;
private $fromEncoding;
private $toEncoding;
private $skipFirstLine;
private $columnNames;
private $timeout;
@@ -73,9 +75,12 @@ class ParserCSV {
private $startByte;
private $lineLimit;
private $lastLinePos;
private $useMbString;
public function __construct() {
$this->delimiter = ',';
$this->fromEncoding = 'UTF-8';
$this->toEncoding = 'UTF-8';
$this->skipFirstLine = FALSE;
$this->columnNames = FALSE;
$this->timeout = FALSE;
@@ -83,6 +88,10 @@ class ParserCSV {
$this->startByte = 0;
$this->lineLimit = 0;
$this->lastLinePos = 0;
ini_set('auto_detect_line_endings', TRUE);
if (extension_loaded('mbstring') && variable_get('feeds_use_mbstring', TRUE)) {
$this->useMbString = TRUE;
}
}
/**
@@ -93,6 +102,18 @@ class ParserCSV {
$this->delimiter = $delimiter;
}
/**
* Sets the source file encoding.
*
* By default, the encoding is UTF-8.
*
* @param string $encoding
* The encoding to set.
*/
public function setEncoding($encoding) {
$this->fromEncoding = $encoding;
}
/**
* Set this to TRUE if the parser should skip the first line of the CSV text,
* which might be desired if the first line contains the column names.
@@ -196,7 +217,7 @@ class ParserCSV {
for ($lineIterator->rewind($this->startByte); $lineIterator->valid(); $lineIterator->next()) {
// Make really sure we've got lines without trailing newlines.
$line = trim($lineIterator->current(), "\r\n");
$line = trim($this->fixEncoding($lineIterator->current()), "\r\n");
// Skip empty lines.
if (empty($line)) {
@@ -236,7 +257,7 @@ class ParserCSV {
}
// Ok, so, on with fetching the next line, as mentioned above.
$currentField .= "\n";
$line = trim($lineIterator->current(), "\r\n");
$line = trim($this->fixEncoding($lineIterator->current()), "\r\n");
$currentIndex = 0;
continue;
}
@@ -324,4 +345,38 @@ class ParserCSV {
}
return $rows;
}
/**
* Converts encoding of input data.
*
* @param string $data
* A chunk of data.
*
* @return string
* The encoded data.
*
* @throws ParserCSVEncodingException
* Thrown when a given encoding does not match.
*/
public function fixEncoding($data) {
if ($this->useMbString) {
if (mb_check_encoding($data, $this->fromEncoding)) {
if ($this->toEncoding != $this->fromEncoding) {
// Convert encoding. The conversion is to UTF-8 by default to prevent
// SQL errors.
$data = mb_convert_encoding($data, $this->toEncoding, $this->fromEncoding);
}
}
else {
throw new ParserCSVEncodingException(t('Source file is not in %encoding encoding.', array('%encoding' => $this->fromEncoding)));
}
}
return $data;
}
}
/**
* Exception thrown when an encoding error occurs during parsing.
*/
class ParserCSVEncodingException extends Exception {}

View File

@@ -161,7 +161,7 @@ class PuSHSubscriber {
if (isset($_SERVER['HTTP_X_HUB_SIGNATURE']) && ($sub = $this->subscription())) {
$result = array();
parse_str($_SERVER['HTTP_X_HUB_SIGNATURE'], $result);
if (isset($result['sha1']) && $result['sha1'] == hash_hmac('sha1', $raw, $sub->secret)) {
if (isset($result['sha1']) && $result['sha1'] === hash_hmac('sha1', $raw, $sub->secret)) {
return $raw;
}
else {
@@ -183,47 +183,44 @@ class PuSHSubscriber {
* method handles the challenge.
*/
public function verifyRequest() {
if (isset($_GET['hub_challenge'])) {
/**
* If a subscription is present, compare the verify token. If the token
* matches, set the status on the subscription record and confirm
* positive.
*
* If we cannot find a matching subscription and the hub checks on
* 'unsubscribe' confirm positive.
*
* In all other cases confirm negative.
*/
if ($sub = $this->subscription()) {
if ($_GET['hub_verify_token'] == $sub->post_fields['hub.verify_token']) {
if ($_GET['hub_mode'] == 'subscribe' && $sub->status == 'subscribe') {
$sub->status = 'subscribed';
$sub->post_fields = array();
$sub->save();
$this->log('Verified "subscribe" request.');
$verify = TRUE;
}
elseif ($_GET['hub_mode'] == 'unsubscribe' && $sub->status == 'unsubscribe') {
$sub->status = 'unsubscribed';
$sub->post_fields = array();
$sub->save();
$this->log('Verified "unsubscribe" request.');
$verify = TRUE;
}
}
}
elseif ($_GET['hub_mode'] == 'unsubscribe') {
$this->log('Verified "unsubscribe" request.');
$verify = TRUE;
}
if ($verify) {
header('HTTP/1.1 200 "Found"', NULL, 200);
print $_GET['hub_challenge'];
drupal_exit();
}
if (!isset($_GET['hub_challenge'])) {
return $this->rejectRequest();
}
header('HTTP/1.1 404 "Not Found"', NULL, 404);
$this->log('Could not verify subscription.', 'error');
// Don't accept modes of 'subscribed' or 'unsubscribed'.
if ($_GET['hub_mode'] !== 'subscribe' && $_GET['hub_mode'] !== 'unsubscribe') {
return $this->rejectRequest();
}
// No available subscription.
if (!$sub = $this->subscription()) {
return $this->rejectRequest();
}
// Not what we asked for.
if ($_GET['hub_mode'] !== $sub->status) {
return $this->rejectRequest();
}
// Wrong URL.
if ($_GET['hub_topic'] !== $sub->topic) {
return $this->rejectRequest();
}
if ($sub->status === 'subscribe') {
$sub->status = 'subscribed';
$this->log('Verified "subscribe" request.');
}
else {
$sub->status = 'unsubscribed';
$this->log('Verified "unsubscribe" request.');
}
$sub->post_fields = array();
$sub->save();
header('HTTP/1.1 200 "Found"', NULL, 200);
print check_plain($_GET['hub_challenge']);
drupal_exit();
}
@@ -244,7 +241,7 @@ class PuSHSubscriber {
* @todo Make concurrency safe.
*/
protected function request($hub, $topic, $mode, $callback_url) {
$secret = hash('sha1', uniqid(rand(), TRUE));
$secret = drupal_random_key(40);
$post_fields = array(
'hub.callback' => $callback_url,
'hub.mode' => $mode,
@@ -252,7 +249,6 @@ class PuSHSubscriber {
'hub.verify' => 'sync',
'hub.lease_seconds' => '', // Permanent subscription.
'hub.secret' => $secret,
'hub.verify_token' => md5(session_id() . rand()),
);
$sub = new $this->subscription_class($this->domain, $this->subscriber_id, $hub, $topic, $secret, $mode, $post_fields);
$sub->save();
@@ -310,6 +306,16 @@ class PuSHSubscriber {
protected function log($msg, $level = 'status') {
$this->env->log("{$this->domain}:{$this->subscriber_id}\t$msg", $level);
}
/**
* Rejects a request subscription request.
*/
protected function rejectRequest() {
header('HTTP/1.1 404 "Not Found"', NULL, 404);
$this->log('Could not verify subscription.', 'error');
drupal_exit();
}
}
/**

View File

@@ -19,12 +19,7 @@
* stdClass The structured datas extracted from the feed.
*/
function common_syndication_parser_parse($string) {
if (!defined('LIBXML_VERSION') || (version_compare(phpversion(), '5.1.0', '<'))) {
@ $xml = simplexml_load_string($string, NULL);
}
else {
@ $xml = simplexml_load_string($string, NULL, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NOCDATA);
}
@ $xml = simplexml_load_string($string, NULL, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NOCDATA);
// Got a malformed XML.
if ($xml === FALSE || is_null($xml)) {
@@ -43,18 +38,6 @@ function common_syndication_parser_parse($string) {
return FALSE;
}
/**
* Get the cached version of the <var>$url</var>
*/
function _parser_common_syndication_cache_get($url) {
$cache_file = _parser_common_syndication_sanitize_cache() . '/' . md5($url);
if (file_exists($cache_file)) {
$file_content = file_get_contents($cache_file);
return unserialize($file_content);
}
return FALSE;
}
/**
* Determine the feed format of a SimpleXML parsed object structure.
*
@@ -182,16 +165,14 @@ function _parser_common_syndication_atom10_parse($feed_XML) {
}
}
$author_found = FALSE;
$original_author = '';
if (!empty($news->source->author->name)) {
$original_author = "{$news->source->author->name}";
$author_found = TRUE;
}
elseif (!empty($news->author->name)) {
$original_author = "{$news->author->name}";
$author_found = TRUE;
}
if (!empty($feed_XML->author->name) && !$author_found) {
elseif (!empty($feed_XML->author->name)) {
$original_author = "{$feed_XML->author->name}";
}
@@ -262,9 +243,8 @@ function _parser_common_syndication_RDF10_parse($feed_XML) {
'rss' => 'http://purl.org/rss/1.0/',
);
// Get all namespaces declared in the feed element, with special handling
// for PHP versions prior to 5.1.2 as they don't handle namespaces.
$namespaces = version_compare(phpversion(), '5.1.2', '<') ? array() : $feed_XML->getNamespaces(TRUE);
// Get all namespaces declared in the feed element.
$namespaces = $feed_XML->getNamespaces(TRUE);
// Process the <rss:channel> resource containing feed metadata:
foreach ($feed_XML->children($canonical_namespaces['rss'])->channel as $rss_channel) {
@@ -379,11 +359,9 @@ function _parser_common_syndication_RSS20_parse($feed_XML) {
$category = $news->xpath('category');
// Get children for current namespace.
if (version_compare(phpversion(), '5.1.2', '>')) {
$content = (array)$news->children($ns["content"]);
$dc = (array)$news->children($ns["dc"]);
$georss = (array)$news->children($ns["georss"]);
}
$content = (array)$news->children($ns["content"]);
$dc = (array)$news->children($ns["dc"]);
$georss = (array)$news->children($ns["georss"]);
$news = (array) $news;
$news['category'] = $category;
@@ -505,12 +483,25 @@ function _parser_common_syndication_RSS20_parse($feed_XML) {
*/
function _parser_common_syndication_parse_date($date_str) {
// PHP < 5.3 doesn't like the GMT- notation for parsing timezones.
$date_str = str_replace("GMT-", "-", $date_str);
$date_str = str_replace("GMT+", "+", $date_str);
$date_str = str_replace('GMT-', '-', $date_str);
$date_str = str_replace('GMT+', '+', $date_str);
$parsed_date = strtotime($date_str);
if ($parsed_date === FALSE || $parsed_date == -1) {
$parsed_date = _parser_common_syndication_parse_w3cdtf($date_str);
}
if (($parsed_date === FALSE || $parsed_date == -1)) {
// PHP does not support the UT timezone. Fake it. The system that generated
// this, Google Groups, probably meant UTC.
$date_str = strtolower(trim($date_str));
$last_three = substr($date_str, strlen($date_str) - 3, 3);
if ($last_three == ' ut') {
$parsed_date = strtotime($date_str . 'c');
}
}
return $parsed_date === FALSE ? time() : $parsed_date;
}

View File

@@ -24,8 +24,10 @@ define('HTTP_REQUEST_PCRE_TAG_ATTRIBUTES', '/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\
class HRCurlException extends Exception {}
/**
* Discover RSS or atom feeds at the given URL. If document in given URL is an
* HTML document, function attempts to discover RSS or Atom feeds.
* Discovers RSS or atom feeds at the given URL.
*
* If document in given URL is an HTML document, function attempts to discover
* RSS or Atom feeds.
*
* @param string $url
* The url of the feed to retrieve.
@@ -36,7 +38,7 @@ class HRCurlException extends Exception {}
* The discovered feed, or FALSE if the URL is not reachable or there was an
* error.
*/
function http_request_get_common_syndication($url, $settings = NULL) {
function http_request_get_common_syndication($url, $settings = array()) {
$accept_invalid_cert = isset($settings['accept_invalid_cert']) ? $settings['accept_invalid_cert'] : FALSE;
$download = http_request_get($url, NULL, NULL, $accept_invalid_cert);
@@ -47,12 +49,12 @@ function http_request_get_common_syndication($url, $settings = NULL) {
return FALSE;
}
// Drop the data into a seperate variable so all manipulations of the html
// Drop the data into a separate variable so all manipulations of the html
// will not effect the actual object that exists in the static cache.
// @see http_request_get.
$downloaded_string = $download->data;
// If this happens to be a feed then just return the url.
if (http_request_is_feed($download->headers['content-type'], $downloaded_string)) {
if (isset($download->headers['content-type']) && http_request_is_feed($download->headers['content-type'], $downloaded_string)) {
return $url;
}
@@ -77,11 +79,13 @@ function http_request_get_common_syndication($url, $settings = NULL) {
* If the URL uses authentication, supply the password.
* @param bool $accept_invalid_cert
* Whether to accept invalid certificates.
* @param integer $timeout
* Timeout in seconds to wait for an HTTP get request to finish.
*
* @return stdClass
* An object that describes the data downloaded from $url.
*/
function http_request_get($url, $username = NULL, $password = NULL, $accept_invalid_cert = FALSE) {
function http_request_get($url, $username = NULL, $password = NULL, $accept_invalid_cert = FALSE, $timeout = NULL) {
// Intra-pagedownload cache, avoid to download the same content twice within
// one page download (it's possible, compatible and parse calls).
static $download_cache = array();
@@ -89,12 +93,15 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
return $download_cache[$url];
}
// Determine request timeout.
$request_timeout = !empty($timeout) ? $timeout : variable_get('http_request_timeout', 30);
if (!$username && valid_url($url, TRUE)) {
// Handle password protected feeds.
$url_parts = parse_url($url);
if (!empty($url_parts['user'])) {
$password = $url_parts['pass'];
$username = $url_parts['user'];
$password = urldecode($url_parts['pass']);
$username = urldecode($url_parts['user']);
}
}
@@ -103,7 +110,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
// Only download and parse data if really needs refresh.
// Based on "Last-Modified" and "If-Modified-Since".
$headers = array();
if ($cache = cache_get('feeds_http_download_' . md5($url))) {
if ($cache = http_request_get_cache($url)) {
$last_result = $cache->data;
$last_headers = array_change_key_case($last_result->headers);
@@ -134,6 +141,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
if ($curl) {
$headers[] = 'User-Agent: Drupal (+http://drupal.org/)';
$result = new stdClass();
$result->headers = array();
// Parse the URL and make sure we can handle the schema.
// cURL can only support either http:// or https://.
@@ -149,6 +157,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
case 'https':
// Valid scheme.
break;
default:
$result->error = 'invalid schema ' . $uri['scheme'];
$result->code = -1003;
@@ -168,9 +177,26 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
curl_setopt($download, CURLOPT_HEADER, TRUE);
curl_setopt($download, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($download, CURLOPT_ENCODING, '');
curl_setopt($download, CURLOPT_TIMEOUT, variable_get('http_request_timeout', 30));
curl_setopt($download, CURLOPT_TIMEOUT, $request_timeout);
$proxy_server = variable_get('proxy_server');
if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
curl_setopt($download, CURLOPT_PROXY, $proxy_server);
curl_setopt($download, CURLOPT_PROXYPORT, variable_get('proxy_port', 8080));
// Proxy user/password.
if ($proxy_username = variable_get('proxy_username')) {
$username_password = $proxy_username . ':' . variable_get('proxy_password', '');
curl_setopt($download, CURLOPT_PROXYUSERPWD, $username_password);
curl_setopt($download, CURLOPT_PROXYAUTH, variable_get('proxy_auth_method', CURLAUTH_BASIC));
}
}
if ($accept_invalid_cert) {
curl_setopt($download, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($download, CURLOPT_SSL_VERIFYHOST, 0);
}
$header = '';
$data = curl_exec($download);
@@ -179,18 +205,35 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
t('cURL error (@code) @error for @url', array(
'@code' => curl_errno($download),
'@error' => curl_error($download),
'@url' => $url
'@url' => $url,
)), curl_errno($download)
);
}
// When using a proxy, remove extra data from the header which is not
// considered by CURLINFO_HEADER_SIZE (possibly cURL bug).
// This data is only added when to HTTP header when working with a proxy.
// Example string added: <HTTP/1.0 200 Connection established\r\n\r\n>
// This was fixed in libcurl version 7.30.0 (0x71e00) (April 12, 2013),
// so this workaround only removes the proxy-added headers if we are using
// an older version of libcurl.
$curl_ver = curl_version();
if ($proxy_server && $curl_ver['version_number'] < 0x71e00 && _drupal_http_use_proxy($uri['host'])) {
$http_header_break = "\r\n\r\n";
$response = explode($http_header_break, $data);
if (count($response) > 2) {
$data = substr($data, strlen($response[0] . $http_header_break), strlen($data));
}
}
$header_size = curl_getinfo($download, CURLINFO_HEADER_SIZE);
$header = substr($data, 0, $header_size - 1);
$result->data = substr($data, $header_size);
$headers = preg_split("/(\r\n){2}/", $header);
$header_lines = preg_split("/\r\n|\n|\r/", end($headers));
$result->headers = array();
array_shift($header_lines); // skip HTTP response status
// Skip HTTP response status.
array_shift($header_lines);
while ($line = trim(array_shift($header_lines))) {
list($header, $value) = explode(':', $line, 2);
@@ -212,7 +255,8 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
}
}
else {
$result = drupal_http_request($url, array('headers' => $headers, 'timeout' => variable_get('http_request_timeout', 30)));
$result = drupal_http_request($url, array('headers' => $headers, 'timeout' => $request_timeout));
$result->headers = isset($result->headers) ? $result->headers : array();
}
$result->code = isset($result->code) ? $result->code : 200;
@@ -227,13 +271,13 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
else {
// It's a tragedy, this file must exist and contain good data.
// In this case, clear cache and repeat.
cache_clear_all('feeds_http_download_' . md5($url), 'cache');
return http_request_get($url, $username, $password);
http_request_clear_cache($url);
return http_request_get($url, $username, $password, $accept_invalid_cert, $request_timeout);
}
}
// Set caches.
cache_set('feeds_http_download_' . md5($url), $result);
http_request_set_cache($url, $result);
$download_cache[$url] = $result;
return $result;
@@ -243,7 +287,7 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
* Decides if it's possible to use cURL or not.
*
* @return bool
* TRUE if curl is available, FALSE otherwise.
* TRUE if cURL may be used, FALSE otherwise.
*/
function http_request_use_curl() {
// Allow site administrators to choose to not use cURL.
@@ -251,29 +295,67 @@ function http_request_use_curl() {
return FALSE;
}
// Check availability of cURL on the system.
$basedir = ini_get("open_basedir");
return function_exists('curl_init') && !ini_get('safe_mode') && empty($basedir);
// Check that the PHP cURL extension has been enabled.
if (!extension_loaded('curl')) {
return FALSE;
}
// cURL below PHP 5.6.0 must not have open_basedir or safe_mode enabled.
if (version_compare(PHP_VERSION, '5.6.0', '<')) {
return !ini_get('safe_mode') && !ini_get('open_basedir');
}
// cURL in PHP 5.6.0 and above re-enables CURLOPT_FOLLOWLOCATION with
// open_basedir so there is no need to check for this.
return TRUE;
}
/**
* Clear cache for a specific URL.
*
* @param string $url
* The URL to clear.
*/
function http_request_clear_cache($url) {
cache_clear_all('feeds_http_download_' . md5($url), 'cache');
cache_clear_all(hash('sha256', $url), 'cache_feeds_http');
}
/**
* Gets the cache for a specific URL.
*
* @param string $url
* The URL to find the cached item.
*
* @return object|false
* The cache or FALSE on failure.
*/
function http_request_get_cache($url) {
return cache_get(hash('sha256', $url), 'cache_feeds_http');
}
/**
* Sets the cache for a specific URL.
*
* @param string $url
* The URL to cache.
* @param stdClass $result
* The result of the HTTP request.
*/
function http_request_set_cache($url, stdClass $result) {
cache_set(hash('sha256', $url), $result, 'cache_feeds_http');
}
/**
* Returns if the provided $content_type is a feed.
*
* @param string $content_type
* The Content-Type header.
* The Content-Type header.
*
* @param string $data
* The actual data from the http request.
* The actual data from the http request.
*
* @return bool
* Returns TRUE if this is a parsable feed.
* Returns TRUE if this is a parsable feed.
*/
function http_request_is_feed($content_type, $data) {
$pos = strpos($content_type, ';');
@@ -294,10 +376,10 @@ function http_request_is_feed($content_type, $data) {
* Finds potential feed tags in the HTML document.
*
* @param string $html
* The html string to search.
* The html string to search.
*
* @return array
* An array of href to feeds.
* An array of href to feeds.
*/
function http_request_find_feeds($html) {
$matches = array();
@@ -313,7 +395,11 @@ function http_request_find_feeds($html) {
preg_match_all(HTTP_REQUEST_PCRE_TAG_ATTRIBUTES, $link_tag, $attributes, PREG_SET_ORDER);
foreach ($attributes as $attribute) {
// Find the key value pairs, attribute[1] is key and attribute[2] is the
// value.
// value. However, if the link tag used single quotes, the value might
// be in attribute[3] instead.
if (empty($attribute[2])) {
$attribute[2] = $attribute[3];
}
if (!empty($attribute[1]) && !empty($attribute[2])) {
$candidate[drupal_strtolower($attribute[1])] = drupal_strtolower(decode_entities($attribute[2]));
}
@@ -355,27 +441,48 @@ function http_request_create_absolute_url($url, $base_url) {
// Produces variables $scheme, $host, $user, $pass, $path, $query and
// $fragment.
$parsed_url = parse_url($base_url);
if ($parsed_url === FALSE) {
// Invalid $base_url.
return FALSE;
}
$path = dirname($parsed_url['path']);
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
if (strlen($path) > 0 && substr($path, -1) != '/') {
// Path ends not with '/', so remove all before previous '/'.
$path = dirname($path);
}
// Adding to the existing path.
$cparts = array();
if ($url{0} == '/') {
$cparts = array_filter(explode("/", $url));
}
else {
// Backtracking from the existing path.
$cparts = array_merge(array_filter(explode("/", $path)), array_filter(explode("/", $url)));
foreach ($cparts as $i => $part) {
if ($part == '.') {
$cparts[$i] = NULL;
}
if ($part == '..') {
$cparts[$i - 1] = NULL;
$cparts[$i] = NULL;
}
}
$cparts = array_filter($cparts);
$path_cparts = array_filter(explode("/", $path));
$url_cparts = array_filter(explode("/", $url));
$cparts = array_merge($path_cparts, $url_cparts);
}
$remove_parts = 0;
// Start from behind.
$reverse_cparts = array_reverse($cparts);
foreach ($reverse_cparts as $i => &$part) {
if ($part == '.') {
$part = NULL;
}
elseif ($part == '..') {
$part = NULL;
$remove_parts++;
}
elseif ($remove_parts > 0) {
// If the current part isn't "..", and we had ".." before, then delete
// the part.
$part = NULL;
$remove_parts--;
}
}
$cparts = array_filter(array_reverse($reverse_cparts));
$path = implode("/", $cparts);
// Build the prefix to the path.