diff options
Diffstat (limited to 'includes/database')
-rw-r--r-- | includes/database/database.inc | 60 | ||||
-rw-r--r-- | includes/database/log.inc | 1 | ||||
-rw-r--r-- | includes/database/mysql/database.inc | 1 | ||||
-rw-r--r-- | includes/database/mysql/install.inc | 1 | ||||
-rw-r--r-- | includes/database/mysql/query.inc | 9 | ||||
-rw-r--r-- | includes/database/mysql/schema.inc | 1 | ||||
-rw-r--r-- | includes/database/pgsql/database.inc | 10 | ||||
-rw-r--r-- | includes/database/pgsql/install.inc | 1 | ||||
-rw-r--r-- | includes/database/pgsql/query.inc | 5 | ||||
-rw-r--r-- | includes/database/pgsql/schema.inc | 9 | ||||
-rw-r--r-- | includes/database/pgsql/select.inc | 1 | ||||
-rw-r--r-- | includes/database/prefetch.inc | 1 | ||||
-rw-r--r-- | includes/database/query.inc | 23 | ||||
-rw-r--r-- | includes/database/schema.inc | 1 | ||||
-rw-r--r-- | includes/database/select.inc | 6 | ||||
-rw-r--r-- | includes/database/sqlite/database.inc | 1 | ||||
-rw-r--r-- | includes/database/sqlite/install.inc | 1 | ||||
-rw-r--r-- | includes/database/sqlite/query.inc | 11 | ||||
-rw-r--r-- | includes/database/sqlite/schema.inc | 1 | ||||
-rw-r--r-- | includes/database/sqlite/select.inc | 1 |
20 files changed, 99 insertions, 46 deletions
diff --git a/includes/database/database.inc b/includes/database/database.inc index b384afe3a..4cc1a33d7 100644 --- a/includes/database/database.inc +++ b/includes/database/database.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file @@ -321,7 +320,7 @@ abstract class DatabaseConnection extends PDO { * PDO::FETCH_OBJ, PDO::FETCH_NUM, or a string representing the name of a * class. If a string is specified, each record will be fetched into a new * object of that class. The behavior of all other values is defined by PDO. - * See http://www.php.net/PDOStatement-fetch + * See http://php.net/manual/pdostatement.fetch.php * - return: Depending on the type of query, different return values may be * meaningful. This directive instructs the system which type of return * value is desired. The system will generally set the correct value @@ -542,6 +541,63 @@ abstract class DatabaseConnection extends PDO { } /** + * Flatten an array of query comments into a single comment string. + * + * The comment string will be sanitized to avoid SQL injection attacks. + * + * @param $comments + * An array of query comment strings. + * + * @return + * A sanitized comment string. + */ + public function makeComment($comments) { + if (empty($comments)) + return ''; + + // Flatten the array of comments. + $comment = implode('; ', $comments); + + // Sanitize the comment string so as to avoid SQL injection attacks. + return '/* ' . $this->filterComment($comment) . ' */ '; + } + + /** + * Sanitize a query comment string. + * + * Ensure a query comment does not include strings such as "* /" that might + * terminate the comment early. This avoids SQL injection attacks via the + * query comment. The comment strings in this example are separated by a + * space to avoid PHP parse errors. + * + * For example, the comment: + * @code + * db_update('example') + * ->condition('id', $id) + * ->fields(array('field2' => 10)) + * ->comment('Exploit * / DROP TABLE node; --') + * ->execute() + * @endcode + * + * Would result in the following SQL statement being generated: + * @code + * "/ * Exploit * / DROP TABLE node; -- * / UPDATE example SET field2=..." + * @endcode + * + * Unless the comment is sanitised first, the SQL server would drop the + * node table and ignore the rest of the SQL statement. + * + * @param $comment + * A query comment string. + * + * @return + * A sanitized version of the query comment string. + */ + protected function filterComment($comment = '') { + return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment); + } + + /** * Executes a query string against the database. * * This method provides a central handler for the actual execution of every diff --git a/includes/database/log.inc b/includes/database/log.inc index f28aadb2c..ec27ef8e6 100644 --- a/includes/database/log.inc +++ b/includes/database/log.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc index a3d711840..262cc6051 100644 --- a/includes/database/mysql/database.inc +++ b/includes/database/mysql/database.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/mysql/install.inc b/includes/database/mysql/install.inc index 2f83b2664..75f2ae390 100644 --- a/includes/database/mysql/install.inc +++ b/includes/database/mysql/install.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/mysql/query.inc b/includes/database/mysql/query.inc index 584a4a473..888b6a5a4 100644 --- a/includes/database/mysql/query.inc +++ b/includes/database/mysql/query.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @ingroup database @@ -43,8 +42,8 @@ class InsertQuery_mysql extends InsertQuery { } public function __toString() { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); // Default fields are always placed first for consistency. $insert_fields = array_merge($this->defaultFields, $this->insertFields); @@ -93,8 +92,8 @@ class TruncateQuery_mysql extends TruncateQuery { // not transactional, and result in an implicit COMMIT. When we are in a // transaction, fallback to the slower, but transactional, DELETE. if ($this->connection->inTransaction()) { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}'; } else { diff --git a/includes/database/mysql/schema.inc b/includes/database/mysql/schema.inc index 01933da09..4e88fa169 100644 --- a/includes/database/mysql/schema.inc +++ b/includes/database/mysql/schema.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc index d38b64afe..98b954ffd 100644 --- a/includes/database/pgsql/database.inc +++ b/includes/database/pgsql/database.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file @@ -35,6 +34,15 @@ class DatabaseConnection_pgsql extends DatabaseConnection { if (empty($connection_options['password'])) { $connection_options['password'] = NULL; } + // If the password contains a backslash it is treated as an escape character + // http://bugs.php.net/bug.php?id=53217 + // so backslashes in the password need to be doubled up. + // The bug was reported against pdo_pgsql 1.0.2, backslashes in passwords + // will break on this doubling up when the bug is fixed, so check the version + //elseif (phpversion('pdo_pgsql') < 'version_this_was_fixed_in') { + else { + $connection_options['password'] = str_replace('\\', '\\\\', $connection_options['password']); + } $this->connectionOptions = $connection_options; diff --git a/includes/database/pgsql/install.inc b/includes/database/pgsql/install.inc index 0d446af58..c77f4ea78 100644 --- a/includes/database/pgsql/install.inc +++ b/includes/database/pgsql/install.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc index c475a0011..f3783a9ca 100644 --- a/includes/database/pgsql/query.inc +++ b/includes/database/pgsql/query.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @ingroup database @@ -104,8 +103,8 @@ class InsertQuery_pgsql extends InsertQuery { } public function __toString() { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); // Default fields are always placed first for consistency. $insert_fields = array_merge($this->defaultFields, $this->insertFields); diff --git a/includes/database/pgsql/schema.inc b/includes/database/pgsql/schema.inc index 30f12ef78..9ed8a2620 100644 --- a/includes/database/pgsql/schema.inc +++ b/includes/database/pgsql/schema.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file @@ -528,6 +527,9 @@ class DatabaseSchema_pgsql extends DatabaseSchema { $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $check . '"'); } + // Remove old default. + $this->fieldSetNoDefault($table, $field); + $this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast); if (isset($spec['not null'])) { @@ -562,6 +564,11 @@ class DatabaseSchema_pgsql extends DatabaseSchema { $this->connection->query('ALTER TABLE {' . $table . '} ADD CHECK ("' . $field_new . '" >= 0)'); } + // Add default if necessary. + if (isset($spec['default'])) { + $this->fieldSetDefault($table, $field_new, $spec['default']); + } + // Change description if necessary. if (!empty($spec['description'])) { $this->connection->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description'])); diff --git a/includes/database/pgsql/select.inc b/includes/database/pgsql/select.inc index 98061c90a..d1d838281 100644 --- a/includes/database/pgsql/select.inc +++ b/includes/database/pgsql/select.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/prefetch.inc b/includes/database/prefetch.inc index a81ea10f1..f378d3555 100644 --- a/includes/database/prefetch.inc +++ b/includes/database/prefetch.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/query.inc b/includes/database/query.inc index de421b30c..23b652f9b 100644 --- a/includes/database/query.inc +++ b/includes/database/query.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @ingroup database @@ -362,6 +361,9 @@ abstract class Query implements QueryPlaceholderInterface { * for easier debugging and allows you to more easily find where a query * with a performance problem is being generated. * + * The comment string will be sanitized to remove * / and other characters + * that may terminate the string early so as to avoid SQL injection attacks. + * * @param $comment * The comment string to be inserted into the query. * @@ -624,9 +626,8 @@ class InsertQuery extends Query { * The prepared statement. */ public function __toString() { - - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); // Default fields are always placed first for consistency. $insert_fields = array_merge($this->defaultFields, $this->insertFields); @@ -816,9 +817,8 @@ class DeleteQuery extends Query implements QueryConditionInterface { * The prepared statement. */ public function __toString() { - - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); $query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} '; @@ -885,8 +885,8 @@ class TruncateQuery extends Query { * The prepared statement. */ public function __toString() { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} '; } @@ -1112,9 +1112,8 @@ class UpdateQuery extends Query implements QueryConditionInterface { * The prepared statement. */ public function __toString() { - - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); // Expressions take priority over literal fields, so we process those first // and remove any literal fields that conflict. diff --git a/includes/database/schema.inc b/includes/database/schema.inc index e57c94bfb..de1b2f5b9 100644 --- a/includes/database/schema.inc +++ b/includes/database/schema.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/select.inc b/includes/database/select.inc index 43f92671e..716c2fc3d 100644 --- a/includes/database/select.inc +++ b/includes/database/select.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @ingroup database @@ -1440,9 +1439,8 @@ class SelectQuery extends Query implements SelectQueryInterface { } public function __toString() { - - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); // SELECT $query = $comments . 'SELECT '; diff --git a/includes/database/sqlite/database.inc b/includes/database/sqlite/database.inc index 651efa26f..cf3b9551f 100644 --- a/includes/database/sqlite/database.inc +++ b/includes/database/sqlite/database.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/sqlite/install.inc b/includes/database/sqlite/install.inc index a8a12410d..62cbac381 100644 --- a/includes/database/sqlite/install.inc +++ b/includes/database/sqlite/install.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc index 7b1af8114..6b8a72f2a 100644 --- a/includes/database/sqlite/query.inc +++ b/includes/database/sqlite/query.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file @@ -33,8 +32,8 @@ class InsertQuery_sqlite extends InsertQuery { } public function __toString() { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); // Produce as many generic placeholders as necessary. $placeholders = array_fill(0, count($this->insertFields), '?'); @@ -102,7 +101,7 @@ class UpdateQuery_sqlite extends UpdateQuery { } elseif (!isset($data)) { // The field will be set to NULL. - $condition->isNull($field); + $condition->isNotNull($field); } else { $condition->condition($field, $data, '<>'); @@ -149,8 +148,8 @@ class DeleteQuery_sqlite extends DeleteQuery { */ class TruncateQuery_sqlite extends TruncateQuery { public function __toString() { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + // Create a sanitized comment string to prepend to the query. + $comments = $this->connection->makeComment($this->comments); return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} '; } diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc index 11ecd881a..840ba6b5d 100644 --- a/includes/database/sqlite/schema.inc +++ b/includes/database/sqlite/schema.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file diff --git a/includes/database/sqlite/select.inc b/includes/database/sqlite/select.inc index ee3d84dff..fb926ef04 100644 --- a/includes/database/sqlite/select.inc +++ b/includes/database/sqlite/select.inc @@ -1,5 +1,4 @@ <?php -// $Id$ /** * @file |