Index: modules/blogapi/blogapi.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blogapi/blogapi.module,v retrieving revision 1.100.2.5 diff -u -F^f -r1.100.2.5 blogapi.module --- modules/blogapi/blogapi.module 13 Aug 2008 23:59:09 -0000 1.100.2.5 +++ modules/blogapi/blogapi.module 8 Oct 2008 18:35:47 -0000 @@ -217,6 +217,11 @@ function blogapi_blogger_new_post($appke 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($appk 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($appk 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)); @@ -303,6 +314,33 @@ function blogapi_blogger_get_post($appke } /** + * 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) { @@ -492,11 +530,60 @@ function blogapi_mt_set_post_categories( 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. */ function blogapi_mt_supported_text_filters() { @@ -527,11 +614,16 @@ function blogapi_mt_publish_post($postid 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; Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.776.2.30 diff -u -F^f -r1.776.2.30 node.module --- modules/node/node.module 16 Jul 2008 19:04:21 -0000 1.776.2.30 +++ modules/node/node.module 8 Oct 2008 18:35:47 -0000 @@ -2165,6 +2165,14 @@ function node_form($node, $form_values = $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; } Index: modules/upload/upload.module =================================================================== RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v retrieving revision 1.148.2.4 diff -u -F^f -r1.148.2.4 upload.module --- modules/upload/upload.module 26 May 2008 05:03:47 -0000 1.148.2.4 +++ modules/upload/upload.module 8 Oct 2008 18:35:47 -0000 @@ -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); Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.745.2.32 diff -u -F^f -r1.745.2.32 user.module --- modules/user/user.module 13 Aug 2008 23:59:09 -0000 1.745.2.32 +++ modules/user/user.module 8 Oct 2008 18:35:48 -0000 @@ -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: @@ -1064,6 +1073,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)); @@ -1116,6 +1132,11 @@ function user_pass_reset($uid, $timestam $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.'));