Index: modules/blogapi/blogapi.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/blogapi/blogapi.module,v
retrieving revision 1.115.2.3
diff -u -p -r1.115.2.3 blogapi.module
--- modules/blogapi/blogapi.module	13 Aug 2008 23:59:13 -0000	1.115.2.3
+++ modules/blogapi/blogapi.module	8 Oct 2008 19:42:01 -0000
@@ -222,6 +222,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));
@@ -259,7 +264,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
@@ -275,6 +281,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));
@@ -308,6 +319,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) {
@@ -509,11 +547,59 @@ 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);
+      $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() {
@@ -544,11 +630,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/upload/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v
retrieving revision 1.197.2.2
diff -u -p -r1.197.2.2 upload.module
--- modules/upload/upload.module	13 Aug 2008 23:59:14 -0000	1.197.2.2
+++ modules/upload/upload.module	8 Oct 2008 19:42:01 -0000
@@ -178,7 +178,7 @@ function upload_node_form_submit(&$form,
   );
 
   // 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;
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.892.2.6
diff -u -p -r1.892.2.6 user.module
--- modules/user/user.module	12 Aug 2008 05:11:22 -0000	1.892.2.6
+++ modules/user/user.module	8 Oct 2008 19:42:01 -0000
@@ -1334,9 +1334,18 @@ function user_login_final_validate($form
 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;
Index: modules/user/user.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.pages.inc,v
retrieving revision 1.11
diff -u -p -r1.11 user.pages.inc
--- modules/user/user.pages.inc	8 Jan 2008 10:35:43 -0000	1.11
+++ modules/user/user.pages.inc	8 Oct 2008 19:42:01 -0000
@@ -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, $
     $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.'));
