parent
1769d1cca9
commit
83b80acad8
|
@ -1,3 +1,6 @@
|
||||||
|
Drupal 7.29, 2014-07-16
|
||||||
|
----------------------
|
||||||
|
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-003.
|
||||||
|
|
||||||
Drupal 7.28, 2014-05-08
|
Drupal 7.28, 2014-05-08
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
/**
|
/**
|
||||||
* The current system version.
|
* The current system version.
|
||||||
*/
|
*/
|
||||||
define('VERSION', '7.28');
|
define('VERSION', '7.29');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core API compatibility.
|
* Core API compatibility.
|
||||||
|
@ -700,7 +700,14 @@ function drupal_environment_initialize() {
|
||||||
* TRUE if only containing valid characters, or FALSE otherwise.
|
* TRUE if only containing valid characters, or FALSE otherwise.
|
||||||
*/
|
*/
|
||||||
function drupal_valid_http_host($host) {
|
function drupal_valid_http_host($host) {
|
||||||
return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
|
// Limit the length of the host name to 1000 bytes to prevent DoS attacks with
|
||||||
|
// long host names.
|
||||||
|
return strlen($host) <= 1000
|
||||||
|
// Limit the number of subdomains and port separators to prevent DoS attacks
|
||||||
|
// in conf_path().
|
||||||
|
&& substr_count($host, '.') <= 100
|
||||||
|
&& substr_count($host, ':') <= 100
|
||||||
|
&& preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1999,23 +1999,7 @@ function file_download() {
|
||||||
$target = implode('/', $args);
|
$target = implode('/', $args);
|
||||||
$uri = $scheme . '://' . $target;
|
$uri = $scheme . '://' . $target;
|
||||||
if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
|
if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
|
||||||
// Let other modules provide headers and controls access to the file.
|
$headers = file_download_headers($uri);
|
||||||
// module_invoke_all() uses array_merge_recursive() which merges header
|
|
||||||
// values into a new array. To avoid that and allow modules to override
|
|
||||||
// headers instead, use array_merge() to merge the returned arrays.
|
|
||||||
$headers = array();
|
|
||||||
foreach (module_implements('file_download') as $module) {
|
|
||||||
$function = $module . '_file_download';
|
|
||||||
$result = $function($uri);
|
|
||||||
if ($result == -1) {
|
|
||||||
// Throw away the headers received so far.
|
|
||||||
$headers = array();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isset($result) && is_array($result)) {
|
|
||||||
$headers = array_merge($headers, $result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count($headers)) {
|
if (count($headers)) {
|
||||||
file_transfer($uri, $headers);
|
file_transfer($uri, $headers);
|
||||||
}
|
}
|
||||||
|
@ -2027,6 +2011,69 @@ function file_download() {
|
||||||
drupal_exit();
|
drupal_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves headers for a private file download.
|
||||||
|
*
|
||||||
|
* Calls all module implementations of hook_file_download() to retrieve headers
|
||||||
|
* for files by the module that originally provided the file. The presence of
|
||||||
|
* returned headers indicates the current user has access to the file.
|
||||||
|
*
|
||||||
|
* @param $uri
|
||||||
|
* The URI for the file whose headers should be retrieved.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* If access is allowed, headers for the file, suitable for passing to
|
||||||
|
* file_transfer(). If access is not allowed, an empty array will be returned.
|
||||||
|
*
|
||||||
|
* @see file_transfer()
|
||||||
|
* @see file_download_access()
|
||||||
|
* @see hook_file_downlaod()
|
||||||
|
*/
|
||||||
|
function file_download_headers($uri) {
|
||||||
|
// Let other modules provide headers and control access to the file.
|
||||||
|
// module_invoke_all() uses array_merge_recursive() which merges header
|
||||||
|
// values into a new array. To avoid that and allow modules to override
|
||||||
|
// headers instead, use array_merge() to merge the returned arrays.
|
||||||
|
$headers = array();
|
||||||
|
foreach (module_implements('file_download') as $module) {
|
||||||
|
$function = $module . '_file_download';
|
||||||
|
$result = $function($uri);
|
||||||
|
if ($result == -1) {
|
||||||
|
// Throw away the headers received so far.
|
||||||
|
$headers = array();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isset($result) && is_array($result)) {
|
||||||
|
$headers = array_merge($headers, $result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the current user has access to a particular file.
|
||||||
|
*
|
||||||
|
* The return value of this function hinges on the return value from
|
||||||
|
* file_download_headers(), which is the function responsible for collecting
|
||||||
|
* access information through hook_file_download().
|
||||||
|
*
|
||||||
|
* If immediately transferring the file to the browser and the headers will
|
||||||
|
* need to be retrieved, the return value of file_download_headers() should be
|
||||||
|
* used to determine access directly, so that access checks will not be run
|
||||||
|
* twice.
|
||||||
|
*
|
||||||
|
* @param $uri
|
||||||
|
* The URI for the file whose access should be retrieved.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Boolean TRUE if access is allowed. FALSE if access is not allowed.
|
||||||
|
*
|
||||||
|
* @see file_download_headers()
|
||||||
|
* @see hook_file_download()
|
||||||
|
*/
|
||||||
|
function file_download_access($uri) {
|
||||||
|
return count(file_download_headers($uri)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all files that match a given mask in a given directory.
|
* Finds all files that match a given mask in a given directory.
|
||||||
|
|
|
@ -2722,7 +2722,7 @@ function form_select_options($element, $choices = NULL) {
|
||||||
$options = '';
|
$options = '';
|
||||||
foreach ($choices as $key => $choice) {
|
foreach ($choices as $key => $choice) {
|
||||||
if (is_array($choice)) {
|
if (is_array($choice)) {
|
||||||
$options .= '<optgroup label="' . $key . '">';
|
$options .= '<optgroup label="' . check_plain($key) . '">';
|
||||||
$options .= form_select_options($element, $choice);
|
$options .= form_select_options($element, $choice);
|
||||||
$options .= '</optgroup>';
|
$options .= '</optgroup>';
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,7 +348,7 @@ Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) {
|
||||||
// this is only needed for IFRAME submissions.
|
// this is only needed for IFRAME submissions.
|
||||||
var v = $.fieldValue(this.element);
|
var v = $.fieldValue(this.element);
|
||||||
if (v !== null) {
|
if (v !== null) {
|
||||||
options.extraData[this.element.name] = v;
|
options.extraData[this.element.name] = Drupal.checkPlain(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -510,8 +510,9 @@ function file_managed_file_value(&$element, $input = FALSE, $form_state = NULL)
|
||||||
$callback($element, $input, $form_state);
|
$callback($element, $input, $form_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Load file if the FID has changed to confirm it exists.
|
// Load file and check access if the FID has changed, to confirm it
|
||||||
if (isset($input['fid']) && $file = file_load($input['fid'])) {
|
// exists and that the current user has access to it.
|
||||||
|
if (isset($input['fid']) && ($file = file_load($input['fid'])) && file_download_access($file->uri)) {
|
||||||
$fid = $file->fid;
|
$fid = $file->fid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1167,5 +1167,18 @@ class FilePrivateTestCase extends FileFieldTestCase {
|
||||||
// Ensure the file cannot be downloaded.
|
// Ensure the file cannot be downloaded.
|
||||||
$this->drupalGet(file_create_url($node_file->uri));
|
$this->drupalGet(file_create_url($node_file->uri));
|
||||||
$this->assertResponse(403, 'Confirmed that access is denied for the file without view field access permission.');
|
$this->assertResponse(403, 'Confirmed that access is denied for the file without view field access permission.');
|
||||||
|
|
||||||
|
// Attempt to reuse the existing file when creating a new node, and confirm
|
||||||
|
// that access is still denied.
|
||||||
|
$edit = array();
|
||||||
|
$edit['title'] = $this->randomName(8);
|
||||||
|
$edit[$field_name . '[' . LANGUAGE_NONE . '][0][fid]'] = $node_file->fid;
|
||||||
|
$this->drupalPost('node/add/page', $edit, t('Save'));
|
||||||
|
$new_node = $this->drupalGetNodeByTitle($edit['title']);
|
||||||
|
$this->assertTrue(!empty($new_node), 'Node was created.');
|
||||||
|
$this->assertUrl('node/' . $new_node->nid);
|
||||||
|
$this->assertNoRaw($node_file->filename, 'File without view field access permission does not appear after attempting to attach it to a new node.');
|
||||||
|
$this->drupalGet(file_create_url($node_file->uri));
|
||||||
|
$this->assertResponse(403, 'Confirmed that access is denied for the file without view field access permission after attempting to attach it to a new node.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,11 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase {
|
||||||
$this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid');
|
$this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid');
|
||||||
$this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with < is invalid');
|
$this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with < is invalid');
|
||||||
$this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid');
|
$this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid');
|
||||||
|
// Verifies that host names are shorter than 1000 characters.
|
||||||
|
$this->assertFalse(drupal_valid_http_host(str_repeat('x', 1001)), 'HTTP_HOST with more than 1000 characters is invalid.');
|
||||||
|
$this->assertFalse(drupal_valid_http_host(str_repeat('.', 101)), 'HTTP_HOST with more than 100 subdomains is invalid.');
|
||||||
|
$this->assertFalse(drupal_valid_http_host(str_repeat(':', 101)), 'HTTP_HOST with more than 100 portseparators is invalid.');
|
||||||
|
|
||||||
// IPv6 loopback address
|
// IPv6 loopback address
|
||||||
$this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid');
|
$this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue