summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorDavid Rothstein <drothstein@gmail.com>2013-11-20 15:45:59 -0500
committerDavid Rothstein <drothstein@gmail.com>2013-11-20 15:45:59 -0500
commit782d1155c62c0a879bf587c7e40c3a13bcf6879c (patch)
tree380060c81a7ebd76870cfd7fb566933b3a7c6efd /modules
parentbf704d6ffe55d66a440a55a9d43e8846d46d2440 (diff)
downloadbrdo-782d1155c62c0a879bf587c7e40c3a13bcf6879c.tar.gz
brdo-782d1155c62c0a879bf587c7e40c3a13bcf6879c.tar.bz2
Drupal 7.24
Diffstat (limited to 'modules')
-rw-r--r--modules/color/color.module49
-rw-r--r--modules/image/image.field.inc2
-rw-r--r--modules/openid/openid.inc23
-rw-r--r--modules/openid/openid.test7
-rw-r--r--modules/openid/tests/openid_test.install2
-rw-r--r--modules/overlay/overlay.module4
-rw-r--r--modules/simpletest/tests/file.test2
-rw-r--r--modules/simpletest/tests/form.test20
-rw-r--r--modules/system/system.install37
-rw-r--r--modules/system/system.test47
-rw-r--r--modules/user/user.module6
-rw-r--r--modules/user/user.pages.inc2
12 files changed, 168 insertions, 33 deletions
diff --git a/modules/color/color.module b/modules/color/color.module
index 53c54fbf6..5b441aabd 100644
--- a/modules/color/color.module
+++ b/modules/color/color.module
@@ -240,6 +240,7 @@ function color_scheme_form($complete_form, &$form_state, $theme) {
$form['palette'][$name] = array(
'#type' => 'textfield',
'#title' => check_plain($names[$name]),
+ '#value_callback' => 'color_palette_color_value',
'#default_value' => $value,
'#size' => 8,
);
@@ -295,6 +296,52 @@ function theme_color_scheme_form($variables) {
}
/**
+ * Determines the value for a palette color field.
+ *
+ * @param $element
+ * The form element whose value is being populated.
+ * @param $input
+ * The incoming input to populate the form element. If this is FALSE,
+ * the element's default value should be returned.
+ * @param $form_state
+ * A keyed array containing the current state of the form.
+ *
+ * @return
+ * The data that will appear in the $form_state['values'] collection for this
+ * element. Return nothing to use the default.
+ */
+function color_palette_color_value($element, $input = FALSE, $form_state = array()) {
+ // If we suspect a possible cross-site request forgery attack, only accept
+ // hexadecimal CSS color strings from user input, to avoid problems when this
+ // value is used in the JavaScript preview.
+ if ($input !== FALSE) {
+ // Start with the provided value for this textfield, and validate that if
+ // necessary, falling back on the default value.
+ $value = form_type_textfield_value($element, $input, $form_state);
+ if (!$value || !isset($form_state['complete form']['#token']) || color_valid_hexadecimal_string($value) || drupal_valid_token($form_state['values']['form_token'], $form_state['complete form']['#token'])) {
+ return $value;
+ }
+ else {
+ return $element['#default_value'];
+ }
+ }
+}
+
+/**
+ * Determines if a hexadecimal CSS color string is valid.
+ *
+ * @param $color
+ * The string to check.
+ *
+ * @return
+ * TRUE if the string is a valid hexadecimal CSS color string, or FALSE if it
+ * isn't.
+ */
+function color_valid_hexadecimal_string($color) {
+ return preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color);
+}
+
+/**
* Form validation handler for color_scheme_form().
*
* @see color_scheme_form_submit()
@@ -302,7 +349,7 @@ function theme_color_scheme_form($variables) {
function color_scheme_form_validate($form, &$form_state) {
// Only accept hexadecimal CSS color strings to avoid XSS upon use.
foreach ($form_state['values']['palette'] as $key => $color) {
- if (!preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color)) {
+ if (!color_valid_hexadecimal_string($color)) {
form_set_error('palette][' . $key, t('%name must be a valid hexadecimal CSS color value.', array('%name' => $form['color']['palette'][$key]['#title'])));
}
}
diff --git a/modules/image/image.field.inc b/modules/image/image.field.inc
index 23547385d..6d1867cb0 100644
--- a/modules/image/image.field.inc
+++ b/modules/image/image.field.inc
@@ -351,7 +351,7 @@ function image_field_widget_form(&$form, &$form_state, $field, $instance, $langc
if ($field['cardinality'] == 1) {
// If there's only one field, return it as delta 0.
if (empty($elements[0]['#default_value']['fid'])) {
- $elements[0]['#description'] = theme('file_upload_help', array('description' => $instance['description'], 'upload_validators' => $elements[0]['#upload_validators']));
+ $elements[0]['#description'] = theme('file_upload_help', array('description' => field_filter_xss($instance['description']), 'upload_validators' => $elements[0]['#upload_validators']));
}
}
else {
diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc
index 74a08d576..d7ef663b4 100644
--- a/modules/openid/openid.inc
+++ b/modules/openid/openid.inc
@@ -380,6 +380,9 @@ function _openid_parse_message($message) {
/**
* Return a nonce value - formatted per OpenID spec.
+ *
+ * NOTE: This nonce is not cryptographically secure and only suitable for use
+ * by the test framework.
*/
function _openid_nonce() {
// YYYY-MM-DDThh:mm:ssZ, plus some optional extra unique characters.
@@ -549,7 +552,7 @@ function _openid_dh_rand($stop) {
}
do {
- $bytes = "\x00" . _openid_get_bytes($nbytes);
+ $bytes = "\x00" . drupal_random_bytes($nbytes);
$n = _openid_dh_binary_to_long($bytes);
// Keep looping if this value is in the low duplicated range.
} while (_openid_math_cmp($n, $duplicate) < 0);
@@ -558,23 +561,7 @@ function _openid_dh_rand($stop) {
}
function _openid_get_bytes($num_bytes) {
- $f = &drupal_static(__FUNCTION__);
- $bytes = '';
- if (!isset($f)) {
- $f = @fopen(OPENID_RAND_SOURCE, "r");
- }
- if (!$f) {
- // pseudorandom used
- $bytes = '';
- for ($i = 0; $i < $num_bytes; $i += 4) {
- $bytes .= pack('L', mt_rand());
- }
- $bytes = substr($bytes, 0, $num_bytes);
- }
- else {
- $bytes = fread($f, $num_bytes);
- }
- return $bytes;
+ return drupal_random_bytes($num_bytes);
}
function _openid_response($str = NULL) {
diff --git a/modules/openid/openid.test b/modules/openid/openid.test
index 292c5317c..41af3f82f 100644
--- a/modules/openid/openid.test
+++ b/modules/openid/openid.test
@@ -695,13 +695,6 @@ class OpenIDTestCase extends DrupalWebTestCase {
}
/**
- * Test _openid_get_bytes().
- */
- function testOpenidGetBytes() {
- $this->assertEqual(strlen(_openid_get_bytes(20)), 20, '_openid_get_bytes() returned expected result.');
- }
-
- /**
* Test _openid_signature().
*/
function testOpenidSignature() {
diff --git a/modules/openid/tests/openid_test.install b/modules/openid/tests/openid_test.install
index 3bd4978f1..d30e2dc4d 100644
--- a/modules/openid/tests/openid_test.install
+++ b/modules/openid/tests/openid_test.install
@@ -13,5 +13,5 @@ function openid_test_install() {
// Generate a MAC key (Message Authentication Code) used for signing messages.
// The variable is base64-encoded, because variables cannot contain non-UTF-8
// data.
- variable_set('openid_test_mac_key', base64_encode(_openid_get_bytes(20)));
+ variable_set('openid_test_mac_key', drupal_random_key(20));
}
diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module
index 728198680..7b2fc9393 100644
--- a/modules/overlay/overlay.module
+++ b/modules/overlay/overlay.module
@@ -146,6 +146,10 @@ function overlay_init() {
// If this page shouldn't be rendered inside the overlay, redirect to the
// parent.
elseif (!path_is_admin($current_path)) {
+ // Prevent open redirects by ensuring the current path is not an absolute URL.
+ if (url_is_external($current_path)) {
+ $current_path = '<front>';
+ }
overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('q', 'render'))));
}
diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test
index 0f2cdb64b..7802be3f2 100644
--- a/modules/simpletest/tests/file.test
+++ b/modules/simpletest/tests/file.test
@@ -952,7 +952,7 @@ class FileDirectoryTest extends FileTestCase {
$this->assertTrue(is_file(file_default_scheme() . '://.htaccess'), 'Successfully re-created the .htaccess file in the files directory.', 'File');
// Verify contents of .htaccess file.
$file = file_get_contents(file_default_scheme() . '://.htaccess');
- $this->assertEqual($file, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks", 'The .htaccess file contains the proper content.', 'File');
+ $this->assertEqual($file, file_htaccess_lines(FALSE), 'The .htaccess file contains the proper content.', 'File');
}
/**
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index a1506ccdc..8b63be4fc 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -82,6 +82,10 @@ class FormsTestCase extends DrupalWebTestCase {
$form_state['input'][$element] = $empty;
$form_state['input']['form_id'] = $form_id;
$form_state['method'] = 'post';
+
+ // The form token CSRF protection should not interfere with this test,
+ // so we bypass it by marking this test form as programmed.
+ $form_state['programmed'] = TRUE;
drupal_prepare_form($form_id, $form, $form_state);
drupal_process_form($form_id, $form, $form_state);
$errors = form_get_errors();
@@ -614,6 +618,18 @@ class FormValidationTestCase extends DrupalWebTestCase {
$this->drupalPost(NULL, array(), 'Save');
$this->assertNoFieldByName('name', 'Form element was hidden.');
$this->assertText('Name value: element_validate_access', 'Value for inaccessible form element exists.');
+
+ // Verify that #validate handlers don't run if the CSRF token is invalid.
+ $this->drupalLogin($this->drupalCreateUser());
+ $this->drupalGet('form-test/validate');
+ $edit = array(
+ 'name' => 'validate',
+ 'form_token' => 'invalid token'
+ );
+ $this->drupalPost(NULL, $edit, 'Save');
+ $this->assertNoFieldByName('name', '#value changed by #validate', 'Form element #value was not altered.');
+ $this->assertNoText('Name value: value changed by form_set_value() in #validate', 'Form element value in $form_state was not altered.');
+ $this->assertText('The form has become outdated. Copy any unsaved work in the form below');
}
/**
@@ -941,6 +957,10 @@ class FormsElementsTableSelectFunctionalTest extends DrupalWebTestCase {
$form_state['input'] = $edit;
$form_state['input']['form_id'] = $form_id;
+ // The form token CSRF protection should not interfere with this test,
+ // so we bypass it by marking this test form as programmed.
+ $form_state['programmed'] = TRUE;
+
drupal_prepare_form($form_id, $form, $form_state);
drupal_process_form($form_id, $form, $form_state);
diff --git a/modules/system/system.install b/modules/system/system.install
index a58e855ad..afe4ebc0e 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -258,6 +258,39 @@ function system_requirements($phase) {
$requirements['settings.php']['title'] = $t('Configuration file');
}
+ // Test the contents of the .htaccess files.
+ if ($phase == 'runtime') {
+ // Try to write the .htaccess files first, to prevent false alarms in case
+ // (for example) the /tmp directory was wiped.
+ file_ensure_htaccess();
+ $htaccess_files['public://.htaccess'] = array(
+ 'title' => $t('Public files directory'),
+ 'directory' => variable_get('file_public_path', conf_path() . '/files'),
+ );
+ if ($private_files_directory = variable_get('file_private_path')) {
+ $htaccess_files['private://.htaccess'] = array(
+ 'title' => $t('Private files directory'),
+ 'directory' => $private_files_directory,
+ );
+ }
+ $htaccess_files['temporary://.htaccess'] = array(
+ 'title' => $t('Temporary files directory'),
+ 'directory' => variable_get('file_temporary_path', file_directory_temp()),
+ );
+ foreach ($htaccess_files as $htaccess_file => $info) {
+ // Check for the string which was added to the recommended .htaccess file
+ // in the latest security update.
+ if (!file_exists($htaccess_file) || !($contents = @file_get_contents($htaccess_file)) || strpos($contents, 'Drupal_Security_Do_Not_Remove_See_SA_2013_003') === FALSE) {
+ $requirements[$htaccess_file] = array(
+ 'title' => $info['title'],
+ 'value' => $t('Not fully protected'),
+ 'severity' => REQUIREMENT_ERROR,
+ 'description' => $t('See <a href="@url">@url</a> for information about the recommended .htaccess file which should be added to the %directory directory to help protect against arbitrary code execution.', array('@url' => 'http://drupal.org/SA-CORE-2013-003', '%directory' => $info['directory'])),
+ );
+ }
+ }
+ }
+
// Report cron status.
if ($phase == 'runtime') {
// Cron warning threshold defaults to two days.
@@ -516,7 +549,7 @@ function system_install() {
->execute();
// Populate the cron key variable.
- $cron_key = drupal_hash_base64(drupal_random_bytes(55));
+ $cron_key = drupal_random_key();
variable_set('cron_key', $cron_key);
}
@@ -1743,7 +1776,7 @@ function system_update_7000() {
* Generate a cron key and save it in the variables table.
*/
function system_update_7001() {
- variable_set('cron_key', drupal_hash_base64(drupal_random_bytes(55)));
+ variable_set('cron_key', drupal_random_key());
}
/**
diff --git a/modules/system/system.test b/modules/system/system.test
index 99e0cbe95..f4fb047d1 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -2712,3 +2712,50 @@ class TokenScanTest extends DrupalWebTestCase {
}
}
+/**
+ * Test case for drupal_valid_token().
+ */
+class SystemValidTokenTest extends DrupalUnitTestCase {
+
+ /**
+ * Flag to indicate whether PHP error reportings should be asserted.
+ *
+ * @var bool
+ */
+ protected $assertErrors = TRUE;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Token validation',
+ 'description' => 'Test the security token validation.',
+ 'group' => 'System',
+ );
+ }
+
+ /**
+ * Tests invalid invocations of drupal_valid_token() that must return FALSE.
+ */
+ public function testTokenValidation() {
+ // The following checks will throw PHP notices, so we disable error
+ // assertions.
+ $this->assertErrors = FALSE;
+ $this->assertFalse(drupal_valid_token(NULL, new stdClass()), 'Token NULL, value object returns FALSE.');
+ $this->assertFalse(drupal_valid_token(0, array()), 'Token 0, value array returns FALSE.');
+ $this->assertFalse(drupal_valid_token('', array()), "Token '', value array returns FALSE.");
+ $this->assertFalse('' === drupal_get_token(array()), 'Token generation does not return an empty string on invalid parameters.');
+ $this->assertErrors = TRUE;
+
+ $this->assertFalse(drupal_valid_token(TRUE, 'foo'), 'Token TRUE, value foo returns FALSE.');
+ $this->assertFalse(drupal_valid_token(0, 'foo'), 'Token 0, value foo returns FALSE.');
+ }
+
+ /**
+ * Overrides DrupalTestCase::errorHandler().
+ */
+ public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
+ if ($this->assertErrors) {
+ return parent::errorHandler($severity, $message, $file, $line);
+ }
+ return TRUE;
+ }
+}
diff --git a/modules/user/user.module b/modules/user/user.module
index 512420706..7227a1e74 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -717,10 +717,14 @@ function user_password($length = 10) {
// Loop the number of times specified by $length.
for ($i = 0; $i < $length; $i++) {
+ do {
+ // Find a secure random number within the range needed.
+ $index = ord(drupal_random_bytes(1));
+ } while ($index > $len);
// Each iteration, pick a random character from the
// allowable string and append it to the password:
- $pass .= $allowable_characters[mt_rand(0, $len)];
+ $pass .= $allowable_characters[$index];
}
return $pass;
diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc
index 4cdbc40fa..c14548cf4 100644
--- a/modules/user/user.pages.inc
+++ b/modules/user/user.pages.inc
@@ -137,7 +137,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
// Let the user's password be changed without the current password check.
- $token = drupal_hash_base64(drupal_random_bytes(55));
+ $token = drupal_random_key();
$_SESSION['pass_reset_' . $user->uid] = $token;
drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
}