security update core+modules
This commit is contained in:
@@ -15,10 +15,9 @@
|
||||
* reference the form builder function using \@see. For examples, of this see
|
||||
* system_modules_uninstall() or user_pass(), the latter of which has the
|
||||
* following in its doxygen documentation:
|
||||
*
|
||||
* \@ingroup forms
|
||||
* \@see user_pass_validate().
|
||||
* \@see user_pass_submit().
|
||||
* - \@ingroup forms
|
||||
* - \@see user_pass_validate()
|
||||
* - \@see user_pass_submit()
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@@ -168,6 +167,12 @@ function drupal_get_form($form_id) {
|
||||
* processed.
|
||||
* - base_form_id: Identification for a base form, as declared in a
|
||||
* hook_forms() implementation.
|
||||
* - immutable: If this flag is set to TRUE, a new form build id is
|
||||
* generated when the form is loaded from the cache. If it is subsequently
|
||||
* saved to the cache again, it will have another cache id and therefore
|
||||
* the original form and form-state will remain unaltered. This is
|
||||
* important when page caching is enabled in order to prevent form state
|
||||
* from leaking between anonymous users.
|
||||
* - rebuild_info: Internal. Similar to 'build_info', but pertaining to
|
||||
* drupal_rebuild_form().
|
||||
* - rebuild: Normally, after the entire form processing is completed and
|
||||
@@ -235,6 +240,12 @@ function drupal_get_form($form_id) {
|
||||
* likely to occur during Ajax operations.
|
||||
* - programmed: If TRUE, the form was submitted programmatically, usually
|
||||
* invoked via drupal_form_submit(). Defaults to FALSE.
|
||||
* - programmed_bypass_access_check: If TRUE, programmatic form submissions
|
||||
* are processed without taking #access into account. Set this to FALSE
|
||||
* when submitting a form programmatically with values that may have been
|
||||
* input by the user executing the current request; this will cause #access
|
||||
* to be respected as it would on a normal form submission. Defaults to
|
||||
* TRUE.
|
||||
* - process_input: Boolean flag. TRUE signifies correct form submission.
|
||||
* This is always TRUE for programmed forms coming from drupal_form_submit()
|
||||
* (see 'programmed' key), or if the form_id coming from the $_POST data is
|
||||
@@ -402,6 +413,7 @@ function form_state_defaults() {
|
||||
'submitted' => FALSE,
|
||||
'executed' => FALSE,
|
||||
'programmed' => FALSE,
|
||||
'programmed_bypass_access_check' => TRUE,
|
||||
'cache'=> FALSE,
|
||||
'method' => 'post',
|
||||
'groups' => array(),
|
||||
@@ -452,17 +464,25 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
|
||||
$form = drupal_retrieve_form($form_id, $form_state);
|
||||
|
||||
// If only parts of the form will be returned to the browser (e.g., Ajax or
|
||||
// RIA clients), re-use the old #build_id to not require client-side code to
|
||||
// manually update the hidden 'build_id' input element.
|
||||
// RIA clients), or if the form already had a new build ID regenerated when it
|
||||
// was retrieved from the form cache, reuse the existing #build_id.
|
||||
// Otherwise, a new #build_id is generated, to not clobber the previous
|
||||
// build's data in the form cache; also allowing the user to go back to an
|
||||
// earlier build, make changes, and re-submit.
|
||||
// @see drupal_prepare_form()
|
||||
if (isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id'])) {
|
||||
$enforce_old_build_id = isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id']);
|
||||
$old_form_is_mutable_copy = isset($old_form['#build_id_old']);
|
||||
if ($enforce_old_build_id || $old_form_is_mutable_copy) {
|
||||
$form['#build_id'] = $old_form['#build_id'];
|
||||
if ($old_form_is_mutable_copy) {
|
||||
$form['#build_id_old'] = $old_form['#build_id_old'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
|
||||
if (isset($old_form['#build_id'])) {
|
||||
$form['#build_id_old'] = $old_form['#build_id'];
|
||||
}
|
||||
$form['#build_id'] = 'form-' . drupal_random_key();
|
||||
}
|
||||
|
||||
// #action defaults to request_uri(), but in case of Ajax and other partial
|
||||
@@ -516,6 +536,15 @@ function form_get_cache($form_build_id, &$form_state) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generate a new #build_id if the cached form was rendered on a cacheable
|
||||
// page.
|
||||
if (!empty($form_state['build_info']['immutable'])) {
|
||||
$form['#build_id_old'] = $form['#build_id'];
|
||||
$form['#build_id'] = 'form-' . drupal_random_key();
|
||||
$form['form_build_id']['#value'] = $form['#build_id'];
|
||||
$form['form_build_id']['#id'] = $form['#build_id'];
|
||||
unset($form_state['build_info']['immutable']);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
@@ -528,15 +557,28 @@ function form_set_cache($form_build_id, $form, $form_state) {
|
||||
// 6 hours cache life time for forms should be plenty.
|
||||
$expire = 21600;
|
||||
|
||||
// Ensure that the form build_id embedded in the form structure is the same as
|
||||
// the one passed in as a parameter. This is an additional safety measure to
|
||||
// prevent legacy code operating directly with form_get_cache and
|
||||
// form_set_cache from accidentally overwriting immutable form state.
|
||||
if ($form['#build_id'] != $form_build_id) {
|
||||
watchdog('form', 'Form build-id mismatch detected while attempting to store a form in the cache.', array(), WATCHDOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache form structure.
|
||||
if (isset($form)) {
|
||||
if ($GLOBALS['user']->uid) {
|
||||
$form['#cache_token'] = drupal_get_token();
|
||||
}
|
||||
unset($form['#build_id_old']);
|
||||
cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire);
|
||||
}
|
||||
|
||||
// Cache form state.
|
||||
if (variable_get('cache', 0) && drupal_page_is_cacheable()) {
|
||||
$form_state['build_info']['immutable'] = TRUE;
|
||||
}
|
||||
if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) {
|
||||
cache_set('form_state_' . $form_build_id, $data, 'cache_form', REQUEST_TIME + $expire);
|
||||
}
|
||||
@@ -727,8 +769,9 @@ function drupal_retrieve_form($form_id, &$form_state) {
|
||||
// Record the filepath of the include file containing the original form, so
|
||||
// the form builder callbacks can be loaded when the form is being rebuilt
|
||||
// from cache on a different path (such as 'system/ajax'). See
|
||||
// form_get_cache().
|
||||
// $menu_get_item() is not available during installation.
|
||||
// form_get_cache(). Don't do this in maintenance mode as Drupal may not be
|
||||
// fully bootstrapped (i.e. during installation) in which case
|
||||
// menu_get_item() is not available.
|
||||
if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
|
||||
$item = menu_get_item();
|
||||
if (!empty($item['include_file'])) {
|
||||
@@ -895,7 +938,7 @@ function drupal_process_form($form_id, &$form, &$form_state) {
|
||||
// after the batch is processed.
|
||||
}
|
||||
|
||||
// Set a flag to indicate the the form has been processed and executed.
|
||||
// Set a flag to indicate that the form has been processed and executed.
|
||||
$form_state['executed'] = TRUE;
|
||||
|
||||
// Redirect the form based on values in $form_state.
|
||||
@@ -976,7 +1019,7 @@ function drupal_prepare_form($form_id, &$form, &$form_state) {
|
||||
// @see drupal_build_form()
|
||||
// @see drupal_rebuild_form()
|
||||
if (!isset($form['#build_id'])) {
|
||||
$form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
|
||||
$form['#build_id'] = 'form-' . drupal_random_key();
|
||||
}
|
||||
$form['form_build_id'] = array(
|
||||
'#type' => 'hidden',
|
||||
@@ -1128,6 +1171,12 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
|
||||
|
||||
// Setting this error will cause the form to fail validation.
|
||||
form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url)));
|
||||
|
||||
// Stop here and don't run any further validation handlers, because they
|
||||
// could invoke non-safe operations which opens the door for CSRF
|
||||
// vulnerabilities.
|
||||
$validated_forms[$form_id] = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1978,7 +2027,7 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) {
|
||||
// #access=FALSE on an element usually allow access for some users, so forms
|
||||
// submitted with drupal_form_submit() may bypass access restriction and be
|
||||
// treated as high-privilege users instead.
|
||||
$process_input = empty($element['#disabled']) && ($form_state['programmed'] || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
|
||||
$process_input = empty($element['#disabled']) && (($form_state['programmed'] && $form_state['programmed_bypass_access_check']) || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
|
||||
|
||||
// Set the element's #value property.
|
||||
if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
|
||||
@@ -2402,6 +2451,17 @@ function form_type_password_confirm_value($element, $input = FALSE) {
|
||||
$element += array('#default_value' => array());
|
||||
return $element['#default_value'] + array('pass1' => '', 'pass2' => '');
|
||||
}
|
||||
$value = array('pass1' => '', 'pass2' => '');
|
||||
// Throw out all invalid array keys; we only allow pass1 and pass2.
|
||||
foreach ($value as $allowed_key => $default) {
|
||||
// These should be strings, but allow other scalars since they might be
|
||||
// valid input in programmatic form submissions. Any nested array values
|
||||
// are ignored.
|
||||
if (isset($input[$allowed_key]) && is_scalar($input[$allowed_key])) {
|
||||
$value[$allowed_key] = (string) $input[$allowed_key];
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2445,6 +2505,27 @@ function form_type_select_value($element, $input = FALSE) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the value for a textarea form element.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element whose value is being populated.
|
||||
* @param mixed $input
|
||||
* The incoming input to populate the form element. If this is FALSE,
|
||||
* the element's default value should be returned.
|
||||
*
|
||||
* @return string
|
||||
* The data that will appear in the $element_state['values'] collection
|
||||
* for this element. Return nothing to use the default.
|
||||
*/
|
||||
function form_type_textarea_value($element, $input = FALSE) {
|
||||
if ($input !== FALSE) {
|
||||
// This should be a string, but allow other scalars since they might be
|
||||
// valid input in programmatic form submissions.
|
||||
return is_scalar($input) ? (string) $input : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the value for a textfield form element.
|
||||
*
|
||||
@@ -2460,9 +2541,12 @@ function form_type_select_value($element, $input = FALSE) {
|
||||
*/
|
||||
function form_type_textfield_value($element, $input = FALSE) {
|
||||
if ($input !== FALSE && $input !== NULL) {
|
||||
// Equate $input to the form value to ensure it's marked for
|
||||
// validation.
|
||||
return str_replace(array("\r", "\n"), '', $input);
|
||||
// This should be a string, but allow other scalars since they might be
|
||||
// valid input in programmatic form submissions.
|
||||
if (!is_scalar($input)) {
|
||||
$input = '';
|
||||
}
|
||||
return str_replace(array("\r", "\n"), '', (string) $input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2650,17 +2734,43 @@ function theme_select($variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a select form element's options array into HTML.
|
||||
* Converts an array of options into HTML, for use in select list form elements.
|
||||
*
|
||||
* @param $element
|
||||
* An associative array containing the properties of the element.
|
||||
* @param $choices
|
||||
* Mixed: Either an associative array of items to list as choices, or an
|
||||
* object with an 'option' member that is an associative array. This
|
||||
* parameter is only used internally and should not be passed.
|
||||
* This function calls itself recursively to obtain the values for each optgroup
|
||||
* within the list of options and when the function encounters an object with
|
||||
* an 'options' property inside $element['#options'].
|
||||
*
|
||||
* @return
|
||||
* An HTML string of options for the select form element.
|
||||
* @param array $element
|
||||
* An associative array containing the following key-value pairs:
|
||||
* - #multiple: Optional Boolean indicating if the user may select more than
|
||||
* one item.
|
||||
* - #options: An associative array of options to render as HTML. Each array
|
||||
* value can be a string, an array, or an object with an 'option' property:
|
||||
* - A string or integer key whose value is a translated string is
|
||||
* interpreted as a single HTML option element. Do not use placeholders
|
||||
* that sanitize data: doing so will lead to double-escaping. Note that
|
||||
* the key will be visible in the HTML and could be modified by malicious
|
||||
* users, so don't put sensitive information in it.
|
||||
* - A translated string key whose value is an array indicates a group of
|
||||
* options. The translated string is used as the label attribute for the
|
||||
* optgroup. Do not use placeholders to sanitize data: doing so will lead
|
||||
* to double-escaping. The array should contain the options you wish to
|
||||
* group and should follow the syntax of $element['#options'].
|
||||
* - If the function encounters a string or integer key whose value is an
|
||||
* object with an 'option' property, the key is ignored, the contents of
|
||||
* the option property are interpreted as $element['#options'], and the
|
||||
* resulting HTML is added to the output.
|
||||
* - #value: Optional integer, string, or array representing which option(s)
|
||||
* to pre-select when the list is first displayed. The integer or string
|
||||
* must match the key of an option in the '#options' list. If '#multiple' is
|
||||
* TRUE, this can be an array of integers or strings.
|
||||
* @param array|null $choices
|
||||
* (optional) Either an associative array of options in the same format as
|
||||
* $element['#options'] above, or NULL. This parameter is only used internally
|
||||
* and is not intended to be passed in to the initial function call.
|
||||
*
|
||||
* @return string
|
||||
* An HTML string of options and optgroups for use in a select form element.
|
||||
*/
|
||||
function form_select_options($element, $choices = NULL) {
|
||||
if (!isset($choices)) {
|
||||
@@ -2673,7 +2783,7 @@ function form_select_options($element, $choices = NULL) {
|
||||
$options = '';
|
||||
foreach ($choices as $key => $choice) {
|
||||
if (is_array($choice)) {
|
||||
$options .= '<optgroup label="' . $key . '">';
|
||||
$options .= '<optgroup label="' . check_plain($key) . '">';
|
||||
$options .= form_select_options($element, $choice);
|
||||
$options .= '</optgroup>';
|
||||
}
|
||||
@@ -3051,14 +3161,12 @@ function form_process_radios($element) {
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - element: An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #return_value, #description, #required,
|
||||
* #attributes, #checked.
|
||||
* Properties used: #id, #name, #attributes, #checked, #return_value.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_checkbox($variables) {
|
||||
$element = $variables['element'];
|
||||
$t = get_t();
|
||||
$element['#attributes']['type'] = 'checkbox';
|
||||
element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
|
||||
|
||||
@@ -3238,6 +3346,8 @@ function form_process_container($element, &$form_state) {
|
||||
*/
|
||||
function theme_container($variables) {
|
||||
$element = $variables['element'];
|
||||
// Ensure #attributes is set.
|
||||
$element += array('#attributes' => array());
|
||||
|
||||
// Special handling for form elements.
|
||||
if (isset($element['#array_parents'])) {
|
||||
@@ -3662,35 +3772,6 @@ function form_pre_render_fieldset($element) {
|
||||
/**
|
||||
* Creates a group formatted as vertical tabs.
|
||||
*
|
||||
* Note that autocomplete callbacks should include special handling as the
|
||||
* user's input may contain forward slashes. If the user-submitted string has a
|
||||
* '/' in the text that is sent in the autocomplete request, the menu system
|
||||
* will split the text and pass it to the callback as multiple arguments.
|
||||
*
|
||||
* Suppose your autocomplete path in the menu system is 'mymodule_autocomplete.'
|
||||
* In your form you have:
|
||||
* @code
|
||||
* '#autocomplete_path' => 'mymodule_autocomplete/' . $some_key . '/' . $some_id,
|
||||
* @endcode
|
||||
* The user types in "keywords" so the full path called is:
|
||||
* 'mymodule_autocomplete/$some_key/$some_id/keywords'
|
||||
*
|
||||
* You should include code similar to the following to handle slashes in the
|
||||
* input:
|
||||
* @code
|
||||
* function mymodule_autocomplete_callback($arg1, $arg2, $keywords) {
|
||||
* $args = func_get_args();
|
||||
* // We need to remove $arg1 and $arg2 from the beginning of the array so we
|
||||
* // are left with the keywords.
|
||||
* array_shift($args);
|
||||
* array_shift($args);
|
||||
* // We store the user's original input in $keywords, including any slashes.
|
||||
* $keywords = implode('/', $args);
|
||||
*
|
||||
* // Your code here.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param $element
|
||||
* An associative array containing the properties and children of the
|
||||
* fieldset.
|
||||
@@ -4039,8 +4120,6 @@ function theme_file($variables) {
|
||||
*/
|
||||
function theme_form_element($variables) {
|
||||
$element = &$variables['element'];
|
||||
// This is also used in the installer, pre-database setup.
|
||||
$t = get_t();
|
||||
|
||||
// This function is invoked as theme wrapper, but the rendered form element
|
||||
// may not necessarily have been processed by form_builder().
|
||||
@@ -4199,7 +4278,7 @@ function _form_set_class(&$element, $class = array()) {
|
||||
if (!empty($element['#required'])) {
|
||||
$element['#attributes']['class'][] = 'required';
|
||||
}
|
||||
if (isset($element['#parents']) && form_get_error($element) !== NULL) {
|
||||
if (isset($element['#parents']) && form_get_error($element) !== NULL && !empty($element['#validated'])) {
|
||||
$element['#attributes']['class'][] = 'error';
|
||||
}
|
||||
}
|
||||
@@ -4276,7 +4355,7 @@ function element_validate_number($element, &$form_state) {
|
||||
* returns any user input in the 'results' or 'message' keys of $context,
|
||||
* it must also sanitize them first.
|
||||
*
|
||||
* Sample batch operations:
|
||||
* Sample callback_batch_operation():
|
||||
* @code
|
||||
* // Simple and artificial: load a node of a given type for a given user
|
||||
* function my_function_1($uid, $type, &$context) {
|
||||
@@ -4328,7 +4407,7 @@ function element_validate_number($element, &$form_state) {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Sample 'finished' callback:
|
||||
* Sample callback_batch_finished():
|
||||
* @code
|
||||
* function batch_test_finished($success, $results, $operations) {
|
||||
* // The 'success' parameter means no fatal PHP errors were detected. All
|
||||
@@ -4367,12 +4446,14 @@ function element_validate_number($element, &$form_state) {
|
||||
* @param $batch_definition
|
||||
* An associative array defining the batch, with the following elements (all
|
||||
* are optional except as noted):
|
||||
* - operations: (required) Array of function calls to be performed.
|
||||
* - operations: (required) Array of operations to be performed, where each
|
||||
* item is an array consisting of the name of an implementation of
|
||||
* callback_batch_operation() and an array of parameter.
|
||||
* Example:
|
||||
* @code
|
||||
* array(
|
||||
* array('my_function_1', array($arg1)),
|
||||
* array('my_function_2', array($arg2_1, $arg2_2)),
|
||||
* array('callback_batch_operation_1', array($arg1)),
|
||||
* array('callback_batch_operation_2', array($arg2_1, $arg2_2)),
|
||||
* )
|
||||
* @endcode
|
||||
* - title: A safe, translated string to use as the title for the progress
|
||||
@@ -4384,10 +4465,10 @@ function element_validate_number($element, &$form_state) {
|
||||
* @elapsed. Defaults to t('Completed @current of @total.').
|
||||
* - error_message: Message displayed if an error occurred while processing
|
||||
* the batch. Defaults to t('An error has occurred.').
|
||||
* - finished: Name of a function to be executed after the batch has
|
||||
* completed. This should be used to perform any result massaging that may
|
||||
* be needed, and possibly save data in $_SESSION for display after final
|
||||
* page redirection.
|
||||
* - finished: Name of an implementation of callback_batch_finished(). This is
|
||||
* executed after the batch has completed. This should be used to perform
|
||||
* any result massaging that may be needed, and possibly save data in
|
||||
* $_SESSION for display after final page redirection.
|
||||
* - file: Path to the file containing the definitions of the 'operations' and
|
||||
* 'finished' functions, for instance if they don't reside in the main
|
||||
* .module file. The path should be relative to base_path(), and thus should
|
||||
|
||||
Reference in New Issue
Block a user