Commit 4dfa29ee authored by drumm's avatar drumm

Drupal 5.11.

parent cfdf854e
// $Id$
Drupal 5.11-dev, xxxx-xx-xx (development release)
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
-----------------------
......
......@@ -217,6 +217,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));
......@@ -254,7 +259,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
......@@ -270,6 +276,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));
......@@ -302,6 +313,33 @@ function blogapi_blogger_get_post($appkey, $postid, $username, $password) {
return _blogapi_get_post($node, TRUE);
}
/**
* 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.
*/
......@@ -492,10 +530,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);
$placeholders = implode(', ', array_fill(0, count($term_list), '%d'));
$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 (". $placeholders .") 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.
*/
......@@ -527,11 +614,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;
......
......@@ -2165,6 +2165,14 @@ function node_form($node, $form_values = NULL) {
$form['delete'] = array('#type' => 'button', '#value' => t('Delete'), '#weight' => 50);
}
$form['#after_build'] = array('node_form_add_preview');
// Ensure that node_validate() will always get called.
$form['#validate']['node_form_validate'] = array();
// Also, if the module defines its own _validate() routine based on the
// form_id, include that in the #validate array, as well.
$node_validate = $node->type .'_node_form_validate';
if (function_exists($node_validate)) {
$form['#validate'][$node_validate] = array();
}
$form['#base'] = 'node_form';
return $form;
}
......
......@@ -6,7 +6,7 @@
* Configuration system that lets administrators modify the workings of the site.
*/
define('VERSION', '5.11-dev');
define('VERSION', '5.11');
/**
* Implementation of hook_help().
......
......@@ -878,8 +878,21 @@ function _upload_image($file) {
* Menu-callback for JavaScript-based uploads.
*/
function upload_js() {
// We only do the upload.module part of the node validation process.
$node = (object)$_POST;
if (isset($_POST['vid']) && is_numeric($_POST['vid'])) {
// Load the node and check the user is allowed to post attachments to it.
$node = node_load(array('vid' => $_POST['vid']));
if (!$node || !node_access('update', $node) || !variable_get('upload_'. $node->type, TRUE)) {
// 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.'));
$output = theme('status_messages');
print drupal_to_js(array('status' => TRUE, 'data' => $output));
exit();
}
}
else {
// This is a new node.
$node = new stdClass();
}
// Load existing node files.
$node->files = upload_load($node);
......
......@@ -979,8 +979,17 @@ function user_authenticate($name, $pass) {
// Try to log in the user locally. Don't set $user unless successful.
if ($account = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1))) {
$user = $account;
return $user;
// Check if the e-mail is denied by an access rule.
// Doing this check here saves us a user_load() in user_login_validate()
// and introduces less code change for a security fix.
if (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)));
return;
}
else {
$user = $account;
return $user;
}
}
// Strip name and server from ID:
......@@ -1060,6 +1069,13 @@ function user_pass() {
function user_pass_validate($form_id, $form_values) {
$name = $form_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)));
}
$account = user_load(array('mail' => $name, 'status' => 1));
if (!$account) {
$account = user_load(array('name' => $name, 'status' => 1));
......@@ -1112,6 +1128,11 @@ function user_pass_reset($uid, $timestamp, $hashed_pass, $action = NULL) {
$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.'));
......
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