core security update
This commit is contained in:
@@ -688,6 +688,13 @@ function drupal_goto($path = '', array $options = array(), $http_response_code =
|
||||
$options['fragment'] = $destination['fragment'];
|
||||
}
|
||||
|
||||
// In some cases modules call drupal_goto(current_path()). We need to ensure
|
||||
// that such a redirect is not to an external URL.
|
||||
if ($path === current_path() && empty($options['external']) && url_is_external($path)) {
|
||||
// Force url() to generate a non-external URL.
|
||||
$options['external'] = FALSE;
|
||||
}
|
||||
|
||||
drupal_alter('drupal_goto', $path, $options, $http_response_code);
|
||||
|
||||
// The 'Location' HTTP header must be absolute.
|
||||
@@ -753,7 +760,8 @@ function drupal_access_denied() {
|
||||
* - headers: An array containing request headers to send as name/value pairs.
|
||||
* - method: A string containing the request method. Defaults to 'GET'.
|
||||
* - data: A string containing the request body, formatted as
|
||||
* 'param=value¶m=value&...'. Defaults to NULL.
|
||||
* 'param=value¶m=value&...'; to generate this, use http_build_query().
|
||||
* Defaults to NULL.
|
||||
* - max_redirects: An integer representing how many times a redirect
|
||||
* may be followed. Defaults to 3.
|
||||
* - timeout: A float representing the maximum number of seconds the function
|
||||
@@ -778,6 +786,8 @@ function drupal_access_denied() {
|
||||
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
|
||||
* easy access the array keys are returned in lower case.
|
||||
* - data: A string containing the response body that was received.
|
||||
*
|
||||
* @see http_build_query()
|
||||
*/
|
||||
function drupal_http_request($url, array $options = array()) {
|
||||
// Allow an alternate HTTP client library to replace Drupal's default
|
||||
@@ -1057,6 +1067,12 @@ function drupal_http_request($url, array $options = array()) {
|
||||
|
||||
switch ($code) {
|
||||
case 200: // OK
|
||||
case 201: // Created
|
||||
case 202: // Accepted
|
||||
case 203: // Non-Authoritative Information
|
||||
case 204: // No Content
|
||||
case 205: // Reset Content
|
||||
case 206: // Partial Content
|
||||
case 304: // Not modified
|
||||
break;
|
||||
case 301: // Moved permanently
|
||||
@@ -1522,7 +1538,7 @@ function _filter_xss_split($m, $store = FALSE) {
|
||||
return '<';
|
||||
}
|
||||
|
||||
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
||||
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
||||
// Seriously malformed.
|
||||
return '';
|
||||
}
|
||||
@@ -1754,9 +1770,15 @@ function format_rss_item($title, $link, $description, $args = array()) {
|
||||
* - 'key': element name
|
||||
* - 'value': element contents
|
||||
* - 'attributes': associative array of element attributes
|
||||
* - 'encoded': TRUE if 'value' is already encoded
|
||||
*
|
||||
* In both cases, 'value' can be a simple string, or it can be another array
|
||||
* with the same format as $array itself for nesting.
|
||||
*
|
||||
* If 'encoded' is TRUE it is up to the caller to ensure that 'value' is either
|
||||
* entity-encoded or CDATA-escaped. Using this option is not recommended when
|
||||
* working with untrusted user input, since failing to escape the data
|
||||
* correctly has security implications.
|
||||
*/
|
||||
function format_xml_elements($array) {
|
||||
$output = '';
|
||||
@@ -1769,7 +1791,7 @@ function format_xml_elements($array) {
|
||||
}
|
||||
|
||||
if (isset($value['value']) && $value['value'] != '') {
|
||||
$output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : check_plain($value['value'])) . '</' . $value['key'] . ">\n";
|
||||
$output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : (!empty($value['encoded']) ? $value['value'] : check_plain($value['value']))) . '</' . $value['key'] . ">\n";
|
||||
}
|
||||
else {
|
||||
$output .= " />\n";
|
||||
@@ -2214,20 +2236,8 @@ function url($path = NULL, array $options = array()) {
|
||||
'prefix' => ''
|
||||
);
|
||||
|
||||
// A duplicate of the code from url_is_external() to avoid needing another
|
||||
// function call, since performance inside url() is critical.
|
||||
if (!isset($options['external'])) {
|
||||
// Return an external link if $path contains an allowed absolute URL. Avoid
|
||||
// calling drupal_strip_dangerous_protocols() if there is any slash (/),
|
||||
// hash (#) or question_mark (?) before the colon (:) occurrence - if any -
|
||||
// as this would clearly mean it is not a URL. If the path starts with 2
|
||||
// slashes then it is always considered an external URL without an explicit
|
||||
// protocol part.
|
||||
$colonpos = strpos($path, ':');
|
||||
$options['external'] = (strpos($path, '//') === 0)
|
||||
|| ($colonpos !== FALSE
|
||||
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
|
||||
&& drupal_strip_dangerous_protocols($path) == $path);
|
||||
$options['external'] = url_is_external($path);
|
||||
}
|
||||
|
||||
// Preserve the original path before altering or aliasing.
|
||||
@@ -2347,12 +2357,18 @@ function url($path = NULL, array $options = array()) {
|
||||
*/
|
||||
function url_is_external($path) {
|
||||
$colonpos = strpos($path, ':');
|
||||
// Avoid calling drupal_strip_dangerous_protocols() if there is any slash (/),
|
||||
// hash (#) or question_mark (?) before the colon (:) occurrence - if any - as
|
||||
// this would clearly mean it is not a URL. If the path starts with 2 slashes
|
||||
// then it is always considered an external URL without an explicit protocol
|
||||
// part.
|
||||
// Some browsers treat \ as / so normalize to forward slashes.
|
||||
$path = str_replace('\\', '/', $path);
|
||||
// If the path starts with 2 slashes then it is always considered an external
|
||||
// URL without an explicit protocol part.
|
||||
return (strpos($path, '//') === 0)
|
||||
// Leading control characters may be ignored or mishandled by browsers, so
|
||||
// assume such a path may lead to an external location. The \p{C} character
|
||||
// class matches all UTF-8 control, unassigned, and private characters.
|
||||
|| (preg_match('/^\p{C}/u', $path) !== 0)
|
||||
// Avoid calling drupal_strip_dangerous_protocols() if there is any slash
|
||||
// (/), hash (#) or question_mark (?) before the colon (:) occurrence - if
|
||||
// any - as this would clearly mean it is not a URL.
|
||||
|| ($colonpos !== FALSE
|
||||
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
|
||||
&& drupal_strip_dangerous_protocols($path) == $path);
|
||||
@@ -2637,6 +2653,15 @@ function drupal_deliver_html_page($page_callback_result) {
|
||||
global $language;
|
||||
drupal_add_http_header('Content-Language', $language->language);
|
||||
|
||||
// By default, do not allow the site to be rendered in an iframe on another
|
||||
// domain, but provide a variable to override this. If the code running for
|
||||
// this page request already set the X-Frame-Options header earlier, don't
|
||||
// overwrite it here.
|
||||
$frame_options = variable_get('x_frame_options', 'SAMEORIGIN');
|
||||
if ($frame_options && is_null(drupal_get_http_header('X-Frame-Options'))) {
|
||||
drupal_add_http_header('X-Frame-Options', $frame_options);
|
||||
}
|
||||
|
||||
// Menu status constants are integers; page content is a string or array.
|
||||
if (is_int($page_callback_result)) {
|
||||
// @todo: Break these up into separate functions?
|
||||
@@ -2751,6 +2776,7 @@ function drupal_page_footer() {
|
||||
_registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
|
||||
drupal_cache_system_paths();
|
||||
module_implements_write_cache();
|
||||
drupal_file_scan_write_cache();
|
||||
system_run_automated_cron();
|
||||
}
|
||||
|
||||
@@ -2812,11 +2838,11 @@ function drupal_map_assoc($array, $function = NULL) {
|
||||
* into script execution a call such as set_time_limit(20) is made, the
|
||||
* script will run for a total of 45 seconds before timing out.
|
||||
*
|
||||
* It also means that it is possible to decrease the total time limit if
|
||||
* the sum of the new time limit and the current time spent running the
|
||||
* script is inferior to the original time limit. It is inherent to the way
|
||||
* set_time_limit() works, it should rather be called with an appropriate
|
||||
* value every time you need to allocate a certain amount of time
|
||||
* If the current time limit is not unlimited it is possible to decrease the
|
||||
* total time limit if the sum of the new time limit and the current time spent
|
||||
* running the script is inferior to the original time limit. It is inherent to
|
||||
* the way set_time_limit() works, it should rather be called with an
|
||||
* appropriate value every time you need to allocate a certain amount of time
|
||||
* to execute a task than only once at the beginning of the script.
|
||||
*
|
||||
* Before calling set_time_limit(), we check if this function is available
|
||||
@@ -2833,7 +2859,11 @@ function drupal_map_assoc($array, $function = NULL) {
|
||||
*/
|
||||
function drupal_set_time_limit($time_limit) {
|
||||
if (function_exists('set_time_limit')) {
|
||||
@set_time_limit($time_limit);
|
||||
$current = ini_get('max_execution_time');
|
||||
// Do not set time limit if it is currently unlimited.
|
||||
if ($current != 0) {
|
||||
@set_time_limit($time_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3014,6 +3044,13 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
|
||||
*/
|
||||
function drupal_add_css($data = NULL, $options = NULL) {
|
||||
$css = &drupal_static(__FUNCTION__, array());
|
||||
$count = &drupal_static(__FUNCTION__ . '_count', 0);
|
||||
|
||||
// If the $css variable has been reset with drupal_static_reset(), there is
|
||||
// no longer any CSS being tracked, so set the counter back to 0 also.
|
||||
if (count($css) === 0) {
|
||||
$count = 0;
|
||||
}
|
||||
|
||||
// Construct the options, taking the defaults into consideration.
|
||||
if (isset($options)) {
|
||||
@@ -3049,7 +3086,8 @@ function drupal_add_css($data = NULL, $options = NULL) {
|
||||
}
|
||||
|
||||
// Always add a tiny value to the weight, to conserve the insertion order.
|
||||
$options['weight'] += count($css) / 1000;
|
||||
$options['weight'] += $count / 1000;
|
||||
$count++;
|
||||
|
||||
// Add the data to the CSS array depending on the type.
|
||||
switch ($options['type']) {
|
||||
@@ -3802,7 +3840,7 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
|
||||
|
||||
// Replaces @import commands with the actual stylesheet content.
|
||||
// This happens recursively but omits external files.
|
||||
$contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
|
||||
$contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)(?!\/\/)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
|
||||
return $contents;
|
||||
}
|
||||
|
||||
@@ -3862,6 +3900,21 @@ function drupal_delete_file_if_stale($uri) {
|
||||
* The cleaned identifier.
|
||||
*/
|
||||
function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
$drupal_static_fast['allow_css_double_underscores'] = &drupal_static(__FUNCTION__ . ':allow_css_double_underscores');
|
||||
}
|
||||
$allow_css_double_underscores = &$drupal_static_fast['allow_css_double_underscores'];
|
||||
if (!isset($allow_css_double_underscores)) {
|
||||
$allow_css_double_underscores = variable_get('allow_css_double_underscores', FALSE);
|
||||
}
|
||||
|
||||
// Preserve BEM-style double-underscores depending on custom setting.
|
||||
if ($allow_css_double_underscores) {
|
||||
$filter['__'] = '__';
|
||||
}
|
||||
|
||||
// By default, we filter using Drupal's coding standards.
|
||||
$identifier = strtr($identifier, $filter);
|
||||
|
||||
@@ -5212,6 +5265,11 @@ function _drupal_bootstrap_full() {
|
||||
fix_gpc_magic();
|
||||
// Load all enabled modules
|
||||
module_load_all();
|
||||
// Reset drupal_alter() and module_implements() static caches as these
|
||||
// include implementations for vital modules only when called early on
|
||||
// in the bootstrap.
|
||||
drupal_static_reset('drupal_alter');
|
||||
drupal_static_reset('module_implements');
|
||||
// Make sure all stream wrappers are registered.
|
||||
file_get_stream_wrappers();
|
||||
// Ensure mt_rand is reseeded, to prevent random values from one page load
|
||||
@@ -5308,8 +5366,8 @@ function drupal_page_set_cache() {
|
||||
*
|
||||
* Do not call this function from a test. Use $this->cronRun() instead.
|
||||
*
|
||||
* @return
|
||||
* TRUE if cron ran successfully.
|
||||
* @return bool
|
||||
* TRUE if cron ran successfully and FALSE if cron is already running.
|
||||
*/
|
||||
function drupal_cron_run() {
|
||||
// Allow execution to continue even if the request gets canceled.
|
||||
@@ -5371,12 +5429,12 @@ function drupal_cron_run() {
|
||||
// Do not run if queue wants to skip.
|
||||
continue;
|
||||
}
|
||||
$function = $info['worker callback'];
|
||||
$callback = $info['worker callback'];
|
||||
$end = time() + (isset($info['time']) ? $info['time'] : 15);
|
||||
$queue = DrupalQueue::get($queue_name);
|
||||
while (time() < $end && ($item = $queue->claimItem())) {
|
||||
try {
|
||||
$function($item->data);
|
||||
call_user_func($callback, $item->data);
|
||||
$queue->deleteItem($item);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
@@ -6329,13 +6387,21 @@ function drupal_render_cid_parts($granularity = NULL) {
|
||||
}
|
||||
|
||||
if (!empty($granularity)) {
|
||||
$cache_per_role = $granularity & DRUPAL_CACHE_PER_ROLE;
|
||||
$cache_per_user = $granularity & DRUPAL_CACHE_PER_USER;
|
||||
// User 1 has special permissions outside of the role system, so when
|
||||
// caching per role is requested, it should cache per user instead.
|
||||
if ($user->uid == 1 && $cache_per_role) {
|
||||
$cache_per_user = TRUE;
|
||||
$cache_per_role = FALSE;
|
||||
}
|
||||
// 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be a
|
||||
// resource drag for sites with many users, so when a module is being
|
||||
// equivocal, we favor the less expensive 'PER_ROLE' pattern.
|
||||
if ($granularity & DRUPAL_CACHE_PER_ROLE) {
|
||||
if ($cache_per_role) {
|
||||
$cid_parts[] = 'r.' . implode(',', array_keys($user->roles));
|
||||
}
|
||||
elseif ($granularity & DRUPAL_CACHE_PER_USER) {
|
||||
elseif ($cache_per_user) {
|
||||
$cid_parts[] = "u.$user->uid";
|
||||
}
|
||||
|
||||
@@ -7075,7 +7141,8 @@ function drupal_uninstall_schema($module) {
|
||||
* specification of a schema, as it was defined in a module's
|
||||
* hook_schema(). No additional default values will be set,
|
||||
* hook_schema_alter() is not invoked and these unprocessed
|
||||
* definitions won't be cached.
|
||||
* definitions won't be cached. To retrieve the schema after
|
||||
* hook_schema_alter() has been invoked use drupal_get_schema().
|
||||
*
|
||||
* This function can be used to retrieve a schema specification in
|
||||
* hook_schema(), so it allows you to derive your tables from existing
|
||||
@@ -7137,6 +7204,24 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the type for every field in a table schema.
|
||||
*
|
||||
* @param $table
|
||||
* The name of the table from which to retrieve type information.
|
||||
*
|
||||
* @return
|
||||
* An array of types, keyed by field name.
|
||||
*/
|
||||
function drupal_schema_field_types($table) {
|
||||
$table_schema = drupal_get_schema($table);
|
||||
$field_types = array();
|
||||
foreach ($table_schema['fields'] as $field_name => $field_info) {
|
||||
$field_types[$field_name] = isset($field_info['type']) ? $field_info['type'] : NULL;
|
||||
}
|
||||
return $field_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of fields from a table schema.
|
||||
*
|
||||
@@ -7338,7 +7423,16 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
|
||||
* Information stored in a module .info file:
|
||||
* - name: The real name of the module for display purposes.
|
||||
* - description: A brief description of the module.
|
||||
* - dependencies: An array of shortnames of other modules this module requires.
|
||||
* - dependencies: An array of dependency strings. Each is in the form
|
||||
* 'project:module (versions)'; with the following meanings:
|
||||
* - project: (optional) Project shortname, recommended to ensure uniqueness,
|
||||
* if the module is part of a project hosted on drupal.org. If omitted,
|
||||
* also omit the : that follows. The project name is currently ignored by
|
||||
* Drupal core but is used for automated testing.
|
||||
* - module: (required) Module shortname within the project.
|
||||
* - (versions): Optional version information, consisting of one or more
|
||||
* comma-separated operator/value pairs or simply version numbers, which
|
||||
* can contain "x" as a wildcard. Examples: (>=7.22, <7.28), (7.x-3.x).
|
||||
* - package: The name of the package of modules this module belongs to.
|
||||
*
|
||||
* See forum.info for an example of a module .info file.
|
||||
@@ -7418,7 +7512,6 @@ function drupal_parse_info_file($filename) {
|
||||
*/
|
||||
function drupal_parse_info_format($data) {
|
||||
$info = array();
|
||||
$constants = get_defined_constants();
|
||||
|
||||
if (preg_match_all('
|
||||
@^\s* # Start at the beginning of a line, ignoring leading whitespace
|
||||
@@ -7458,8 +7551,8 @@ function drupal_parse_info_format($data) {
|
||||
}
|
||||
|
||||
// Handle PHP constants.
|
||||
if (isset($constants[$value])) {
|
||||
$value = $constants[$value];
|
||||
if (preg_match('/^\w+$/i', $value) && defined($value)) {
|
||||
$value = constant($value);
|
||||
}
|
||||
|
||||
// Insert actual value.
|
||||
@@ -7623,7 +7716,12 @@ function debug($data, $label = NULL, $print_r = FALSE) {
|
||||
* Parses a dependency for comparison by drupal_check_incompatibility().
|
||||
*
|
||||
* @param $dependency
|
||||
* A dependency string, for example 'foo (>=7.x-4.5-beta5, 3.x)'.
|
||||
* A dependency string, which specifies a module dependency, and optionally
|
||||
* the project it comes from and versions that are supported. Supported
|
||||
* formats include:
|
||||
* - 'module'
|
||||
* - 'project:module'
|
||||
* - 'project:module (>=version, version)'
|
||||
*
|
||||
* @return
|
||||
* An associative array with three keys:
|
||||
@@ -7638,6 +7736,12 @@ function debug($data, $label = NULL, $print_r = FALSE) {
|
||||
* @see drupal_check_incompatibility()
|
||||
*/
|
||||
function drupal_parse_dependency($dependency) {
|
||||
$value = array();
|
||||
// Split out the optional project name.
|
||||
if (strpos($dependency, ':')) {
|
||||
list($project_name, $dependency) = explode(':', $dependency);
|
||||
$value['project'] = $project_name;
|
||||
}
|
||||
// We use named subpatterns and support every op that version_compare
|
||||
// supports. Also, op is optional and defaults to equals.
|
||||
$p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
|
||||
@@ -7646,7 +7750,6 @@ function drupal_parse_dependency($dependency) {
|
||||
$p_major = '(?P<major>\d+)';
|
||||
// By setting the minor version to x, branches can be matched.
|
||||
$p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
|
||||
$value = array();
|
||||
$parts = explode('(', $dependency, 2);
|
||||
$value['name'] = trim($parts[0]);
|
||||
if (isset($parts[1])) {
|
||||
@@ -7761,6 +7864,7 @@ function entity_get_info($entity_type = NULL) {
|
||||
// Prepare entity schema fields SQL info for
|
||||
// DrupalEntityControllerInterface::buildQuery().
|
||||
if (isset($entity_info[$name]['base table'])) {
|
||||
$entity_info[$name]['base table field types'] = drupal_schema_field_types($entity_info[$name]['base table']);
|
||||
$entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
|
||||
if (isset($entity_info[$name]['revision table'])) {
|
||||
$entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
|
||||
|
||||
Reference in New Issue
Block a user