summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGábor Hojtsy2008-10-08 20:12:18 +0000
committerGábor Hojtsy2008-10-08 20:12:18 +0000
commit85c9ed0b6a001b4196b24826841e2cf2d18d2612 (patch)
treec00a58ab34fdd2e75f72deee79ef74b024d12121
parentfd7eac94a648d6c977fb6454dfb5f7b1180f1c4c (diff)
Drupal 6.56.5
-rw-r--r--CHANGELOG.txt12
-rw-r--r--includes/common.inc2
-rw-r--r--modules/blogapi/blogapi.module97
-rw-r--r--modules/system/system.module2
-rw-r--r--modules/upload/upload.module2
-rw-r--r--modules/user/user.module13
-rw-r--r--modules/user/user.pages.inc13
7 files changed, 131 insertions, 10 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 0f40a18..5ee6379 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,8 +1,10 @@
// $Id$
-Drupal 6.5-dev, xxxx-xx-xx (development release)
+Drupal 6.5, 2008-10-08
----------------------
-
+- Fixed security issues, (File upload access bypass, Access rules bypass,
+ BlogAPI access bypass), see SA-2008-060.
+- Fixed a variety of small bugs.
Drupal 6.4, 2008-08-13
----------------------
@@ -135,6 +137,12 @@ Drupal 6.0, 2008-02-13
- Removed old system updates. Updates from Drupal versions prior to 5.x will
require upgrading to 5.x before upgrading to 6.x.
+Drupal 5.11, 2008-10-08
+-----------------------
+- fixed a variety of small bugs.
+- fixed security issues, (File upload access bypass, Access rules bypass,
+ BlogAPI access bypass, Node validation bypass), see SA-2008-060
+
Drupal 5.10, 2008-08-13
-----------------------
- fixed a variety of small bugs.
diff --git a/includes/common.inc b/includes/common.inc
index 445261f..9488bb9 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -587,7 +587,7 @@ function drupal_error_handler($errno, $message, $filename, $line, $context) {
return;
}
- if ($errno & (E_ALL)) {
+ if ($errno & (E_ALL ^ E_NOTICE)) {
$types = array(1 => 'error', 2 => 'warning', 4 => 'parse error', 8 => 'notice', 16 => 'core error', 32 => 'core warning', 64 => 'compile error', 128 => 'compile warning', 256 => 'user error', 512 => 'user warning', 1024 => 'user notice', 2048 => 'strict warning', 4096 => 'recoverable fatal error');
// For database errors, we want the line number/file name of the place that
diff --git a/modules/blogapi/blogapi.module b/modules/blogapi/blogapi.module
index 730e7fb..d5101d5 100644
--- a/modules/blogapi/blogapi.module
+++ b/modules/blogapi/blogapi.module
@@ -222,6 +222,11 @@ function blogapi_blogger_new_post($appkey, $blogid, $username, $password, $conte
node_invoke_nodeapi($edit, 'blogapi new');
+ $valid = blogapi_status_error_check($edit, $publish);
+ if ($valid !== TRUE) {
+ return $valid;
+ }
+
node_validate($edit);
if ($errors = form_get_errors()) {
return blogapi_error(implode("\n", $errors));
@@ -259,7 +264,8 @@ function blogapi_blogger_edit_post($appkey, $postid, $username, $password, $cont
if (!node_access('update', $node)) {
return blogapi_error(t('You do not have permission to update this post.'));
}
-
+ // Save the original status for validation of permissions.
+ $original_status = $node->status;
$node->status = $publish;
// check for bloggerAPI vs. metaWeblogAPI
@@ -275,6 +281,11 @@ function blogapi_blogger_edit_post($appkey, $postid, $username, $password, $cont
node_invoke_nodeapi($node, 'blogapi edit');
+ $valid = blogapi_status_error_check($node, $original_status);
+ if ($valid !== TRUE) {
+ return $valid;
+ }
+
node_validate($node);
if ($errors = form_get_errors()) {
return blogapi_error(implode("\n", $errors));
@@ -308,6 +319,33 @@ function blogapi_blogger_get_post($appkey, $postid, $username, $password) {
}
/**
+ * Check that the user has permission to save the node with the chosen status.
+ *
+ * @return
+ * TRUE if no error, or the blogapi_error().
+ */
+function blogapi_status_error_check($node, $original_status) {
+
+ $node = (object) $node;
+
+ $node_type_default = variable_get('node_options_'. $node->type, array('status', 'promote'));
+
+ // If we don't have the 'administer nodes' permission and the status is
+ // changing or for a new node the status is not the content type's default,
+ // then return an error.
+ if (!user_access('administer nodes') && (($node->status != $original_status) || (empty($node->nid) && $node->status != in_array('status', $node_type_default)))) {
+ if ($node->status) {
+ return blogapi_error(t('You do not have permission to publish this type of post. Please save it as a draft instead.'));
+ }
+ else {
+ return blogapi_error(t('You do not have permission to save this post as a draft. Please publish it instead.'));
+ }
+ }
+ return TRUE;
+}
+
+
+/**
* Blogging API callback. Removes the specified blog node.
*/
function blogapi_blogger_delete_post($appkey, $postid, $username, $password, $publish) {
@@ -514,11 +552,59 @@ function blogapi_mt_set_post_categories($postid, $username, $password, $categori
foreach ($categories as $category) {
$node->taxonomy[] = $category['categoryId'];
}
+ $validated = blogapi_mt_validate_terms($node);
+ if ($validated !== TRUE) {
+ return $validated;
+ }
node_save($node);
return TRUE;
}
/**
+ * Blogging API helper - find allowed taxonomy terms for a node type.
+ */
+function blogapi_mt_validate_terms($node) {
+ // We do a lot of heavy lifting here since taxonomy module doesn't have a
+ // stand-alone validation function.
+ if (module_exists('taxonomy')) {
+ $found_terms = array();
+ if (!empty($node->taxonomy)) {
+ $term_list = array_unique($node->taxonomy);
+ $params = $term_list;
+ $params[] = $node->type;
+ $result = db_query(db_rewrite_sql("SELECT t.tid, t.vid FROM {term_data} t INNER JOIN {vocabulary_node_types} n ON t.vid = n.vid WHERE t.tid IN (". db_placeholders($term_list) .") AND n.type = '%s'", 't', 'tid'), $params);
+ $found_terms = array();
+ $found_count = 0;
+ while ($term = db_fetch_object($result)) {
+ $found_terms[$term->vid][$term->tid] = $term->tid;
+ $found_count++;
+ }
+ // If the counts don't match, some terms are invalid or not accessible to this user.
+ if (count($term_list) != $found_count) {
+ return blogapi_error(t('Invalid categories submitted.'));
+ }
+ }
+ // Look up all the vocabularies for this node type.
+ $result2 = db_query(db_rewrite_sql("SELECT v.vid, v.name, v.required, v.multiple FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s'", 'v', 'vid'), $node->type);
+ // Check each vocabulary associated with this node type.
+ while ($vocabulary = db_fetch_object($result2)) {
+ // Required vocabularies must have at least one term.
+ if ($vocabulary->required && empty($found_terms[$vocabulary->vid])) {
+ return blogapi_error(t('A category from the @vocabulary_name vocabulary is required.', array('@vocabulary_name' => $vocabulary->name)));
+ }
+ // Vocabularies that don't allow multiple terms may have at most one.
+ if (!($vocabulary->multiple) && (isset($found_terms[$vocabulary->vid]) && count($found_terms[$vocabulary->vid]) > 1)) {
+ return blogapi_error(t('You may only choose one category from the @vocabulary_name vocabulary.'), array('@vocabulary_name' => $vocabulary->name));
+ }
+ }
+ }
+ elseif (!empty($node->taxonomy)) {
+ return blogapi_error(t('Error saving categories. This feature is not available.'));
+ }
+ return TRUE;
+}
+
+/**
* Blogging API callback. Sends a list of available input formats.
*/
function blogapi_mt_supported_text_filters() {
@@ -549,11 +635,16 @@ function blogapi_mt_publish_post($postid, $username, $password) {
return blogapi_error(t('Invalid post.'));
}
- $node->status = 1;
- if (!node_access('update', $node)) {
+ // Nothing needs to be done if already published.
+ if ($node->status) {
+ return;
+ }
+
+ if (!node_access('update', $node) || !user_access('administer nodes')) {
return blogapi_error(t('You do not have permission to update this post.'));
}
+ $node->status = 1;
node_save($node);
return TRUE;
diff --git a/modules/system/system.module b/modules/system/system.module
index 94e34ae..cfb857a 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -9,7 +9,7 @@
/**
* The current system version.
*/
-define('VERSION', '6.5-dev');
+define('VERSION', '6.5');
/**
* Core API compatibility.
diff --git a/modules/upload/upload.module b/modules/upload/upload.module
index cf04200..2c5ab44 100644
--- a/modules/upload/upload.module
+++ b/modules/upload/upload.module
@@ -178,7 +178,7 @@ function upload_node_form_submit(&$form, &$form_state) {
);
// Save new file uploads.
- if (($user->uid != 1 || user_access('upload files')) && ($file = file_save_upload('upload', $validators, file_directory_path()))) {
+ if (user_access('upload files') && ($file = file_save_upload('upload', $validators, file_directory_path()))) {
$file->list = variable_get('upload_list_default', 1);
$file->description = $file->filename;
$file->weight = 0;
diff --git a/modules/user/user.module b/modules/user/user.module
index b2abaed..33c81f6 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -1334,9 +1334,18 @@ function user_login_final_validate($form, &$form_state) {
function user_authenticate($form_values = array()) {
global $user;
+ // Load the account to check if the e-mail is denied by an access rule.
+ // Doing this check here saves us a user_load() in user_login_name_validate()
+ // and introduces less code change for a security fix.
+ $account = user_load(array('name' => $form_values['name'], 'pass' => trim($form_values['pass']), 'status' => 1));
+ if ($account && drupal_is_denied('mail', $account->mail)) {
+ form_set_error('name', t('The name %name is registered using a reserved e-mail address and therefore could not be logged in.', array('%name' => $account->name)));
+ }
+
// Name and pass keys are required.
- if (!empty($form_values['name']) && !empty($form_values['pass']) &&
- $account = user_load(array('name' => $form_values['name'], 'pass' => trim($form_values['pass']), 'status' => 1))) {
+ // The user is about to be logged in, so make sure no error was previously
+ // encountered in the validation process.
+ if (!form_get_errors() && !empty($form_values['name']) && !empty($form_values['pass']) && $account) {
$user = $account;
user_authenticate_finalize($form_values);
return $user;
diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc
index e2c1781..f74db1d 100644
--- a/modules/user/user.pages.inc
+++ b/modules/user/user.pages.inc
@@ -43,6 +43,13 @@ function user_pass() {
function user_pass_validate($form, &$form_state) {
$name = trim($form_state['values']['name']);
+
+ // Blocked accounts cannot request a new password,
+ // check provided username and email against access rules.
+ if (drupal_is_denied('user', $name) || drupal_is_denied('mail', $name)) {
+ form_set_error('name', t('%name is not allowed to request a new password.', array('%name' => $name)));
+ }
+
// Try to load by email.
$account = user_load(array('mail' => $name, 'status' => 1));
if (!$account) {
@@ -87,6 +94,12 @@ function user_pass_reset(&$form_state, $uid, $timestamp, $hashed_pass, $action =
$current = time();
// Some redundant checks for extra security ?
if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
+ // Deny one-time login to blocked accounts.
+ if (drupal_is_denied('user', $account->name) || drupal_is_denied('mail', $account->mail)) {
+ drupal_set_message(t('You have tried to use a one-time login for an account which has been blocked.'), 'error');
+ drupal_goto();
+ }
+
// No time out for first time login.
if ($account->login && $current - $timestamp > $timeout) {
drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));