From 74def328c8d6ebaa6c46011b8dc9692be4900e7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20Hojtsy?= <gabor@hojtsy.hu>
Date: Thu, 27 Sep 2007 16:52:00 +0000
Subject: [PATCH] #167284 by Heine and pwolanin: proper field type placeholders
 in IN() queries, setting a best practice to avoid vulnerabilities

---
 includes/database.inc               | 31 ++++++++++++++++++++++-------
 modules/block/block.module          |  6 ++++--
 modules/node/node.admin.inc         | 12 +++++------
 modules/taxonomy/taxonomy.pages.inc |  2 +-
 modules/user/user.module            |  2 +-
 5 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/includes/database.inc b/includes/database.inc
index e5cefded61a4..d82f94d00eb8 100644
--- a/includes/database.inc
+++ b/includes/database.inc
@@ -187,6 +187,22 @@ function _db_query_callback($match, $init = FALSE) {
   }
 }
 
+/**
+ * Generate placeholders for an array of query arguments of a single type.
+ *
+ * Given a Schema API field type, return correct %-placeholders to
+ * embed in a query
+ *
+ * @param $arguments
+ *  An array with at least one element.
+ * @param $type
+ *   The Schema API type of a field (e.g. 'int', 'text', or 'varchar').
+ */
+function db_placeholders($arguments, $type = 'int') {
+  $placeholder = _db_type_placeholder($type);
+  return implode(',', array_fill(0, count($arguments), $placeholder));
+}
+
 /**
  * Indicates the place holders that should be replaced in _db_query_callback().
  */
@@ -437,10 +453,10 @@ function db_create_table(&$ret, $name, $table) {
 }
 
 /**
- * Return an array of field names from an array of key/index column
- * specifiers.  This is usually an identity function but if a
- * key/index uses a column prefix specification, this function
- * extracts just the name.
+ * Return an array of field names from an array of key/index column specifiers.
+ *
+ * This is usually an identity function but if a key/index uses a column prefix
+ * specification, this function extracts just the name.
  *
  * @param $fields
  *   An array of key/index column specifiers.
@@ -461,9 +477,10 @@ function db_field_names($fields) {
 }
 
 /**
- * Given a Schema API field type, return the correct %-placeholder to
- * embed in a query to be passed to db_query along with a value from a
- * column of the specified type.
+ * Given a Schema API field type, return the correct %-placeholder.
+ *
+ * Embed the placeholder in a query to be passed to db_query and and pass as an
+ * argument to db_query a value of the specified type.
  *
  * @param $type
  *   The Schema API type of a field.
diff --git a/modules/block/block.module b/modules/block/block.module
index ca2a204f7b6c..af458a8d5253 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -332,7 +332,8 @@ function block_user($type, $edit, &$user, $category = NULL) {
   switch ($type) {
     case 'form':
       if ($category == 'account') {
-        $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom != 0 AND (r.rid IN (%s) OR r.rid IS NULL) ORDER BY b.weight, b.module", implode(',', array_keys($user->roles)));
+        $rids = array_keys($user->roles);
+        $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom != 0 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.weight, b.module", $rids);
         $form['block'] = array('#type' => 'fieldset', '#title' => t('Block configuration'), '#weight' => 3, '#collapsible' => TRUE, '#tree' => TRUE);
         while ($block = db_fetch_object($result)) {
           $data = module_invoke($block->module, 'block', 'list');
@@ -379,7 +380,8 @@ function block_list($region) {
   static $blocks = array();
 
   if (!count($blocks)) {
-    $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (%s) OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), $theme_key, implode(',', array_keys($user->roles)));
+    $rids = array_keys($user->roles);
+    $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), array_merge(array($theme_key), $rids));
     while ($block = db_fetch_object($result)) {
       if (!isset($blocks[$block->region])) {
         $blocks[$block->region] = array();
diff --git a/modules/node/node.admin.inc b/modules/node/node.admin.inc
index eeac16e5653e..115bb486e129 100644
--- a/modules/node/node.admin.inc
+++ b/modules/node/node.admin.inc
@@ -116,42 +116,42 @@ function node_node_operations() {
  * Callback function for admin mass publishing nodes.
  */
 function node_operations_publish($nodes) {
-  db_query('UPDATE {node} SET status = 1 WHERE nid IN(%s)', implode(',', $nodes));
+  db_query('UPDATE {node} SET status = 1 WHERE nid IN('. db_placeholders($nodes) .')', $nodes);
 }
 
 /**
  * Callback function for admin mass unpublishing nodes.
  */
 function node_operations_unpublish($nodes) {
-  db_query('UPDATE {node} SET status = 0 WHERE nid IN(%s)', implode(',', $nodes));
+  db_query('UPDATE {node} SET status = 0 WHERE nid IN('. db_placeholders($nodes) .')', $nodes);
 }
 
 /**
  * Callback function for admin mass promoting nodes.
  */
 function node_operations_promote($nodes) {
-  db_query('UPDATE {node} SET status = 1, promote = 1 WHERE nid IN(%s)', implode(',', $nodes));
+  db_query('UPDATE {node} SET status = 1, promote = 1 WHERE nid IN('. db_placeholders($nodes) .')', $nodes);
 }
 
 /**
  * Callback function for admin mass demoting nodes.
  */
 function node_operations_demote($nodes) {
-  db_query('UPDATE {node} SET promote = 0 WHERE nid IN(%s)', implode(',', $nodes));
+  db_query('UPDATE {node} SET promote = 0 WHERE nid IN('. db_placeholders($nodes) .')', $nodes);
 }
 
 /**
  * Callback function for admin mass editing nodes to be sticky.
  */
 function node_operations_sticky($nodes) {
-  db_query('UPDATE {node} SET status = 1, sticky = 1 WHERE nid IN(%s)', implode(',', $nodes));
+  db_query('UPDATE {node} SET status = 1, sticky = 1 WHERE nid IN('. db_placeholders($nodes) .')',  $nodes);
 }
 
 /**
  * Callback function for admin mass editing nodes to remove stickiness.
  */
 function node_operations_unsticky($nodes) {
-  db_query('UPDATE {node} SET sticky = 0 WHERE nid IN(%s)', implode(',', $nodes));
+  db_query('UPDATE {node} SET sticky = 0 WHERE nid IN('. db_placeholders($nodes) .')', $nodes);
 }
 
 /**
diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc
index ef4ceaed2234..5ff9cff481eb 100644
--- a/modules/taxonomy/taxonomy.pages.inc
+++ b/modules/taxonomy/taxonomy.pages.inc
@@ -16,7 +16,7 @@ function taxonomy_term_page($str_tids = '', $depth = 0, $op = 'page') {
   }
 
   if ($terms['tids']) {
-    $result = db_query(db_rewrite_sql('SELECT t.tid, t.name FROM {term_data} t WHERE t.tid IN (%s)', 't', 'tid'), implode(',', $terms['tids']));
+    $result = db_query(db_rewrite_sql('SELECT t.tid, t.name FROM {term_data} t WHERE t.tid IN ('. db_placeholders($terms['tids']) .')', 't', 'tid'), $terms['tids']);
     $tids = array(); // we rebuild the $tids-array so it only contains terms the user has access to.
     $names = array();
     while ($term = db_fetch_object($result)) {
diff --git a/modules/user/user.module b/modules/user/user.module
index f82cdde5e3be..b215c7efd49b 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -453,7 +453,7 @@ function user_access($string, $account = NULL) {
   // To reduce the number of SQL queries, we cache the user's permissions
   // in a static variable.
   if (!isset($perm[$account->uid])) {
-    $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles)));
+    $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (". db_placeholders($account->roles) .")", array_keys($account->roles));
 
     $perm[$account->uid] = '';
     while ($row = db_fetch_object($result)) {
-- 
GitLab