Commit e71f947b authored by Gerhard Killesreiter's avatar Gerhard Killesreiter

remove trailing spaces

parent 5d52b0b2
// $Id$
Drupal 4.7.4, 2006-10-18
------------------------
- fixed security issue (XSS), see SA-2006-024
- fixed security issue (CSRF), see SA-2006-025
- fixed security issue (Form action attribute injection), see SA-2006-026
Drupal 4.7.3, 2006-08-02
------------------------
- fixed security issue (XSS), see SA-2006-011
......
......@@ -980,8 +980,9 @@ function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) {
}
// Return an external link if $path contains an allowed absolute URL.
// Only call the slow filter_xss_bad_protocol if $path contains a ':'.
if (strpos($path, ':') !== FALSE && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
// Only call the slow filter_xss_bad_protocol if $path contains a ':' before any / ? or #.
$colonpos = strpos($path, ':');
if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
// Split off the fragment
if (strpos($path, '#') !== FALSE) {
list($path, $old_fragment) = explode('#', $path, 2);
......@@ -1326,6 +1327,49 @@ function drupal_urlencode($text) {
}
}
/**
* Ensure the private key variable used to generate tokens is set.
*
* @return
* The private key
*/
function drupal_get_private_key() {
if (!($key = variable_get('drupal_private_key', 0))) {
$key = mt_rand();
variable_set('drupal_private_key', $key);
}
return $key;
}
/**
* Generate a token based on $value, the current user session and private key.
*
* @param $value
* An additional value to base the token on
*/
function drupal_get_token($value = '') {
$private_key = drupal_get_private_key();
return md5(session_id() . $value . $private_key);
}
/**
* Validate a token based on $value, the current user session and private key.
*
* @param $token
* The token to be validated.
* @param $value
* An additional value to base the token on.
* @param $skip_anonymous
* Set to true to skip token validation for anonymous users.
* @return
* True for a valid token, false for an invalid token. When $skip_anonymous is true, the return value will always be true for anonymous users.
*/
function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
global $user;
return (($skip_anonymous && $user->uid == 0) || ($token == md5(session_id() . $value . variable_get('drupal_private_key', ''))));
}
/**
* Performs one or more XML-RPC request(s).
*
......
......@@ -70,19 +70,24 @@ function drupal_get_form($form_id, &$form, $callback = NULL) {
$form_button_counter = array(0, 0);
$form['#type'] = 'form';
// Add a token to any form displayed to authenticated users.
// This ensures that any submitted form was actually requested previously by the user to protect against
// cross site request forgeries. The default token can be bypassed by setting $form['#token'] to FALSE.
if (isset($form['#token'])) {
if (variable_get('cache', 0) && !$user->uid && $_SERVER['REQUEST_METHOD'] == 'GET') {
if ($form['#token'] === FALSE || $user->uid == 0) {
unset($form['#token']);
}
else {
// Make sure that a private key is set:
if (!variable_get('drupal_private_key', '')) {
variable_set('drupal_private_key', mt_rand());
}
$form['form_token'] = array('#type' => 'hidden', '#default_value' => md5(session_id() . $form['#token'] . variable_get('drupal_private_key', '')));
$form['form_token'] = array('#type' => 'token', '#default_value' => drupal_get_token($form['#token']));
}
}
else if ($user->uid) {
$form['#token'] = $form_id;
$form['form_token'] = array('#type' => 'token', '#default_value' => drupal_get_token($form['#token']));
}
if (isset($form_id)) {
$form['form_id'] = array('#type' => 'hidden', '#value' => $form_id, '#id' => str_replace('_', '-', "edit-$form_id"));
}
......@@ -177,8 +182,9 @@ function drupal_validate_form($form_id, $form, $callback = NULL) {
return;
}
// Check whether the form token is valid.
if (isset($form['#token'])) {
if ($form_values['form_token'] != md5(session_id() . $form['#token'] . variable_get('drupal_private_key', ''))) {
if (!drupal_valid_token($form_values['form_token'], $form['#token'])) {
// setting this error will cause the form to fail validation
form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
}
......@@ -376,6 +382,9 @@ function form_builder($form_id, $form) {
$form['#value'] = $edit;
}
break;
case 'token':
$form['#value'] = (string)$edit;
break;
default:
if (isset($edit)) {
$form['#value'] = $edit;
......@@ -1001,6 +1010,10 @@ function theme_hidden($element) {
return '<input type="hidden" name="'. $element['#name'] . '" id="'. $element['#id'] . '" value="'. check_plain($element['#value']) ."\" " . drupal_attributes($element['#attributes']) ." />\n";
}
function theme_token($element) {
return theme('hidden', $element);
}
/**
* Format a textfield.
*
......
......@@ -128,7 +128,7 @@ function drupal_xml_parser_create(&$data) {
$data = ereg_replace('^(<\?xml[^>]+encoding)="([^"]+)"', '\\1="utf-8"', $out);
}
else {
watchdog('php', t("Could not convert XML encoding '%s' to UTF-8.", array('%s' => $encoding)), WATCHDOG_WARNING);
watchdog('php', t("Could not convert XML encoding '%s' to UTF-8.", array('%s' => theme('placeholder', $encoding))), WATCHDOG_WARNING);
return 0;
}
}
......
......@@ -302,7 +302,7 @@ function theme_block_admin_display($form) {
$last_region = '';
$last_status = 1;
foreach (element_children($form) as $i) {
$block = $form[$i];
$block = &$form[$i];
// Only take form elements that are blocks.
if (is_array($block['info'])) {
// Fetch values
......@@ -346,10 +346,7 @@ function theme_block_admin_display($form) {
$output = theme('table', $header, $rows, array('id' => 'blocks'));
$output .= form_render($form['submit']);
// Also render the form_id as there is no form_render($form) call (as form_render does not appear to handle the
// multi-dimensional block form array very well).
$output .= form_render($form['form_id']);
$output .= form_render($form);
return $output;
}
......
......@@ -138,7 +138,7 @@ function blog_page_user($uid) {
$account = user_load(array((is_numeric($uid) ? 'uid' : 'name') => $uid, 'status' => 1));
if ($account->uid) {
drupal_set_title($title = t("%name's blog", array('%name' => $account->name)));
drupal_set_title($title = t("%name's blog", array('%name' => check_plain($account->name))));
if (($account->uid == $user->uid) && user_access('edit own blog')) {
$output = '<li>'. l(t('Post new blog entry.'), "node/add/blog") .'</li>';
......
......@@ -872,28 +872,14 @@ function comment_render($node, $cid = 0) {
*/
function comment_delete($cid) {
$comment = db_fetch_object(db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', $cid));
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$output = '';
// We'll only delete if the user has confirmed the
// deletion using the form in our else clause below.
if (is_object($comment) && is_numeric($comment->cid) && $_POST['edit']['confirm']) {
drupal_set_message(t('The comment and all its replies have been deleted.'));
// Delete comment and its replies.
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->nid);
// Clear the cache so an anonymous user sees that his comment was deleted.
cache_clear_all();
drupal_goto("node/$comment->nid");
}
else if (is_object($comment) && is_numeric($comment->cid)) {
if (is_object($comment) && is_numeric($comment->cid)) {
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
$form = array();
$form['comment'] = array('#type' => 'value', '#value' => $comment);
$output = confirm_form('comment_confirm_delete',
array(),
$form,
t('Are you sure you want to delete the comment %title?', array('%title' => theme('placeholder', $comment->subject))),
'node/'. $comment->nid,
t('Any replies to this comment will be lost. This action cannot be undone.'),
......@@ -907,6 +893,20 @@ function comment_delete($cid) {
return $output;
}
function comment_confirm_delete_submit($form_id, $form_values) {
$comment = $form_values['comment'];
// Delete comment and its replies.
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->nid);
// Clear the cache so an anonymous user sees that his comment was deleted.
cache_clear_all();
drupal_set_message(t('The comment and all its replies have been deleted.'));
return "node/$comment->nid";
}
/**
* Comment operations. We offer different update operations depending on
* which comment administration page we're on.
......
......@@ -305,10 +305,10 @@ function contact_mail_user() {
drupal_access_denied();
}
else if (!$account->contact && !$admin_access) {
$output = t('%name is not accepting e-mails.', array('%name' => $account->name));
$output = t('%name is not accepting e-mails.', array('%name' => check_plain($account->name)));
}
else if (!$user->uid) {
$output = t('Please <a href="%login">login</a> or <a href="%register">register</a> to send %name a message.', array('%login' => url('user/login'), '%register' => url('user/register'), '%name' => $account->name));
$output = t('Please <a href="%login">login</a> or <a href="%register">register</a> to send %name a message.', array('%login' => url('user/login'), '%register' => url('user/register'), '%name' => check_plain($account->name)));
}
else if (!valid_email_address($user->mail)) {
$output = t('You need to provide a valid e-mail address to contact other users. Please update your <a href="%url">user information</a> and try again.', array('%url' => url("user/$user->uid/edit")));
......@@ -317,16 +317,16 @@ function contact_mail_user() {
$output = t('You cannot contact more than %number users per hour. Please try again later.', array('%number' => variable_get('contact_hourly_threshold', 3)));
}
else {
drupal_set_title($account->name);
drupal_set_title(check_plain($account->name));
$form['#token'] = $user->name . $user->mail;
$form['from'] = array('#type' => 'item',
'#title' => t('From'),
'#value' => $user->name .' &lt;'. $user->mail .'&gt;',
'#value' => check_plain($user->name) .' &lt;'. $user->mail .'&gt;',
);
$form['to'] = array('#type' => 'item',
'#title' => t('To'),
'#value' => $account->name,
'#value' => check_plain($account->name),
);
$form['subject'] = array('#type' => 'textfield',
'#title' => t('Subject'),
......
......@@ -1348,15 +1348,20 @@ function filter_xss_bad_protocol($string, $decode = TRUE) {
if ($decode) {
$string = decode_entities($string);
}
// Remove soft hyphen
$string = str_replace(chr(194) . chr(173), '', $string);
// Strip protocols
// Iteratively remove any invalid protocol found.
do {
$before = $string;
$colonpos = strpos($string, ':');
if ($colonpos > 0) {
// We found a colon, possibly a protocol. Verify.
$protocol = substr($string, 0, $colonpos);
// If a colon is preceded by a slash, question mark or hash, it cannot
// possibly be part of the URL scheme. This must be a relative URL,
// which inherits the (safe) protocol of the base document.
if (preg_match('![/?#]!', $protocol)) {
break;
}
// Check if this is a disallowed protocol
if (!isset($allowed_protocols[$protocol])) {
$string = substr($string, $colonpos + 1);
}
......
......@@ -873,7 +873,7 @@ function theme_forum_display($forums, $topics, $parents, $tid, $sortby, $forum_p
}
}
drupal_set_title($title);
drupal_set_title(check_plain($title));
$breadcrumb[] = array('path' => $_GET['q']);
menu_set_location($breadcrumb);
......
......@@ -411,6 +411,26 @@ function locale_admin_string_edit($lid) {
* Delete a string.
*/
function locale_admin_string_delete($lid) {
include_once './includes/locale.inc';
_locale_string_delete($lid);
$form = array();
$string = db_result(db_query("SELECT source FROM {locales_source} WHERE lid = %d", $lid));
if ($string) {
$form['lid'] = array('#type' => 'value', '#value' => $lid);
$form['string'] = array('#type' => 'item', '#value'=> check_plain($string, 150, FALSE, TRUE));
return confirm_form('locale_string_delete_confirm',
$form,
t('Are you sure you want to delete the following string?'),
'admin/locale/string/search',
'',
t('Delete'),
t('Cancel'));
}
else {
drupal_not_found();
}
}
function locale_string_delete_confirm_submit($form_id, $form_values) {
include_once './includes/locale.inc';
_locale_string_delete($form_values['lid']);
}
\ No newline at end of file
......@@ -483,14 +483,22 @@ function menu_reset_item_form_submit($form_id, $form_values) {
/**
* Menu callback; hide a menu item.
*/
function menu_disable_item($mid) {
function menu_disable_item($mid, $token = NULL) {
global $user;
$item = menu_get_item($mid);
$type = $item['type'];
$form = array();
$form['mid'] = array('#type' => 'value', '#value' => $mid);
$form['item'] = array('#type' => 'value', '#value' => $item);
return confirm_form('menu_disable_confirm', $form, t('Are you sure you want to disable the menu item %menu-item?', array('%menu-item' => theme('placeholder', $item['title']))), 'admin/menu', ' ', t('Disable'), t('Cancel'));
}
function menu_disable_confirm_submit($form_id, $form_values) {
$type = $form_values['item']['type'];
$type &= ~MENU_VISIBLE_IN_TREE;
$type &= ~MENU_VISIBLE_IN_BREADCRUMB;
$type |= MENU_MODIFIED_BY_ADMIN;
db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $mid);
drupal_set_message(t('The menu item has been disabled.'));
db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $form_values['mid']);
drupal_set_message(t('The menu item has been disabled.'));
drupal_goto('admin/menu');
}
......
......@@ -43,7 +43,7 @@ function node_help($section) {
return t('<p>Enter a simple pattern to search for a post. This can include the wildcard character *.<br />For example, a search for "br*" might return "bread bakers", "our daily bread" and "brenda".</p>');
}
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == 'revisions') {
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == 'revisions' && !arg(3)) {
return t('The revisions let you track differences between multiple versions of a post.');
}
......@@ -881,6 +881,18 @@ function node_menu($may_cache) {
'access' => $revisions_access,
'weight' => 2,
'type' => MENU_LOCAL_TASK);
$items[] = array('path' => 'node/'. arg(1) .'/revisions/' . arg(3) . '/delete',
'title' => t('revisions'),
'callback' => 'node_revisions',
'access' => $revisions_access,
'weight' => 2,
'type' => MENU_CALLBACK);
$items[] = array('path' => 'node/'. arg(1) .'/revisions/' . arg(3) . '/revert',
'title' => t('revisions'),
'callback' => 'node_revisions',
'access' => $revisions_access,
'weight' => 2,
'type' => MENU_CALLBACK);
}
}
else if (arg(0) == 'admin' && arg(1) == 'settings' && arg(2) == 'content-types' && is_string(arg(3))) {
......@@ -1305,16 +1317,12 @@ function node_revision_revert($nid, $revision) {
$node = node_load($nid, $revision);
if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
if ($node->vid) {
$node->revision = 1;
$node->log = t('Copy of the revision from %date.', array('%date' => theme('placeholder', format_date($node->revision_timestamp))));
if (module_exist('taxonomy')) {
$node->taxonomy = array_keys($node->taxonomy);
}
node_save($node);
drupal_set_message(t('%title has been reverted back to the revision from %revision-date', array('%revision-date' => theme('placeholder', format_date($node->revision_timestamp)), '%title' => theme('placeholder', check_plain($node->title)))));
watchdog('content', t('%type: reverted %title revision %revision.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
$form = array();
$form['nid'] = array('#type' => 'value', '#value' => $node->nid);
$form['vid'] = array('#type' => 'value', '#value' => $node->vid);
return confirm_form('node_revision_revert_confirm', $form,
t('Are you sure you want to revert %title to the revision from %revision-date?', array('%title' => theme('placeholder', $node->title), '%revision-date' => theme('placeholder', format_date($node->revision_timestamp)))),
"node/$nid/revisions", ' ', t('Revert'), t('Cancel'));
}
else {
drupal_set_message(t('You tried to revert to an invalid revision.'), 'error');
......@@ -1324,6 +1332,22 @@ function node_revision_revert($nid, $revision) {
drupal_access_denied();
}
function node_revision_revert_confirm_submit($form_id, $form_values) {
$nid = $form_values['nid'];
$revision = $form_values['vid'];
$node = node_load($nid, $revision);
$node->revision = 1;
$node->log = t('Copy of the revision from %date.', array('%date' => theme('placeholder', format_date($node->revision_timestamp))));
if (module_exist('taxonomy')) {
$node->taxonomy = array_keys($node->taxonomy);
}
node_save($node);
drupal_set_message(t('%title has been reverted back to the revision from %revision-date', array('%revision-date' => theme('placeholder', format_date($node->revision_timestamp)), '%title' => theme('placeholder', check_plain($node->title)))));
watchdog('content', t('%type: reverted %title revision %revision.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
return 'node/'. $nid .'/revisions';
}
/**
* Delete the revision with specified revision number. A "delete revision" nodeapi event is invoked when a
* revision is deleted.
......@@ -1335,13 +1359,13 @@ function node_revision_delete($nid, $revision) {
// Don't delete the current revision
if ($revision != $node->vid) {
$node = node_load($nid, $revision);
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision);
node_invoke_nodeapi($node, 'delete revision');
drupal_set_message(t('Deleted %title revision %revision.', array('%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
watchdog('content', t('%type: deleted %title revision %revision.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))));
$form = array();
$form['nid'] = array('#type' => 'value', '#value' => $nid);
$form['vid'] = array('#type' => 'value', '#value' => $revision);
return confirm_form('node_revision_delete_confirm', $form,
t('Are you sure you want to delete %title revision %revision?', array('%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $revision))),
"node/$nid/revisions", '', t('Delete'), t('Cancel'));
}
else {
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
}
......@@ -1353,10 +1377,22 @@ function node_revision_delete($nid, $revision) {
}
}
}
drupal_access_denied();
}
function node_revision_delete_confirm_submit($form_id, $form_values) {
$node = node_load($form_values['nid'], $form_values['vid']);
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node->nid, $node->vid);
node_invoke_nodeapi($node, 'delete revision');
drupal_set_message(t('Deleted %title revision %revision.', array('%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $node->vid))));
watchdog('content', t('%type: deleted %title revision %revision.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title), '%revision' => theme('placeholder', $node->revision))));
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node->nid)) > 1) {
return "node/$node->nid/revisions";
}
return "node/$node->nid";
}
/**
* Return a list of all the existing revision numbers.
*/
......@@ -1948,10 +1984,10 @@ function node_revisions() {
}
break;
case 'revert':
node_revision_revert(arg(1), arg(3));
return node_revision_revert(arg(1), arg(3));
break;
case 'delete':
node_revision_delete(arg(1), arg(3));
return node_revision_delete(arg(1), arg(3));
break;
}
}
......
......@@ -85,7 +85,7 @@ function path_admin() {
function path_admin_edit($pid = 0) {
if ($pid) {
$alias = path_load($pid);
drupal_set_title($alias['dst']);
drupal_set_title(check_plain($alias['dst']));
$output = path_form(path_load($pid));
}
else {
......
......@@ -292,7 +292,8 @@ function poll_teaser($node) {
* Generates the voting form for a poll.
*/
function poll_view_voting(&$node, $teaser, $page, $block) {
if ($_POST['op'] == t('Vote')) {
// Check for a valid form token to protect against cross site request forgeries.
if ($_POST['op'] == t('Vote') && drupal_valid_token($_POST['edit']['form_token'], 'poll_view_voting', TRUE)) {
poll_vote($node);
}
......
......@@ -137,7 +137,7 @@ function profile_block($op = 'list', $delta = 0, $edit = array()) {
}
if ($output) {
$block['subject'] = t('About %name', array('%name' => $account->name));
$block['subject'] = t('About %name', array('%name' => check_plain($account->name)));
$block['content'] = $output;
return $block;
}
......@@ -184,7 +184,7 @@ function profile_field_form($arg = NULL) {
drupal_not_found();
return;
}
drupal_set_title(t('edit %title', array('%title' => $edit['title'])));
drupal_set_title(t('edit %title', array('%title' => check_plain($edit['title']))));
$form['fid'] = array('#type' => 'value',
'#value' => $fid,
);
......@@ -460,7 +460,7 @@ function profile_browse() {
}
$output .= '</div>';
drupal_set_title($title);
drupal_set_title(check_plain($title));
return $output;
}
else if ($name && !$field->fid) {
......
......@@ -216,7 +216,7 @@ function statistics_user_tracker() {
l(t('details'), "admin/logs/access/$log->aid"));
}
drupal_set_title($account->name);
drupal_set_title(check_plain($account->name));
$output = theme('table', $header, $rows);
$output .= theme('pager', NULL, 30, 0);
return $output;
......
......@@ -6,7 +6,7 @@
* Configuration system that lets administrators modify the workings of the site.
*/
define('VERSION', '4.7.4 dev');
define('VERSION', '4.7.4');
/**
* Implementation of hook_help().
......@@ -84,6 +84,7 @@ function system_elements() {
$type['value'] = array('#input' => TRUE);
$type['markup'] = array('#prefix' => '', '#suffix' => '');
$type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE);
$type['token'] = array('#input'=> TRUE);
return $type;
}
......
......@@ -66,7 +66,7 @@ function tracker_menu($may_cache) {
function tracker_track_user() {
if ($account = user_load(array('uid' => arg(1)))) {
if ($account->status || user_access('administer users')) {
drupal_set_title($account->name);
drupal_set_title(check_plain($account->name));
return tracker_page($account->uid);
}
else {
......
This diff is collapsed.
......@@ -681,7 +681,14 @@ function update_convert_table_utf8($table) {
$op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
switch ($op) {
case 'Update':
$output = update_update_page();
// Check for a valid form token to protect against cross site request forgeries.
if (drupal_valid_token($_REQUEST['edit']['form_token'], 'update_script_selection_form', TRUE)) {
$output = update_update_page();
}
else {
form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.'));
$output = update_selection_page();
}
break;
case 'finished':
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment