From 2d0df351d704ba34d191831f7d4b8cb385555be2 Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Tue, 29 Nov 2005 20:17:10 +0000 Subject: [PATCH] - Various fixes. Updated CHANGELOG.txt --- CHANGELOG.txt | 8 + includes/bootstrap.inc | 6 +- includes/common.inc | 67 +----- includes/database.mysql.inc | 2 +- includes/database.mysqli.inc | 2 +- includes/database.pgsql.inc | 2 +- includes/file.inc | 18 +- includes/unicode.inc | 4 + modules/filter.module | 421 +++++++++++++++++++++++++++-------- modules/filter/filter.module | 421 +++++++++++++++++++++++++++-------- modules/search.module | 2 +- modules/search/search.module | 2 +- modules/system.module | 2 +- modules/system/system.module | 2 +- modules/upload.module | 8 - modules/upload/upload.module | 8 - 16 files changed, 685 insertions(+), 290 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 1a68edc4f17..91521595de8 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -52,6 +52,10 @@ Drupal x.x.x, xxxx-xx-xx (development version) - PostgreSQL support: * removed dependency on PL/pgSQL procedural language +Drupal 4.6.4, 2005-11-29 +------------------------ +- fixed bugs, including 3 security vulnerabilities. + Drupal 4.6.3, 2005-08-15 ------------------------ - fixed bugs, including a critical "arbitrary PHP code execution" bug. @@ -108,6 +112,10 @@ Drupal 4.6.0, 2005-04-15 - documentation: * improved and extended PHPDoc/Doxygen comments. +Drupal 4.5.6, 2005-11-29 +------------------------ +- fixed bugs, including 3 security vulnerabilities. + Drupal 4.5.5, 2005-08-15 ------------------------ - fixed bugs, including a critical "arbitrary PHP code execution" bug. diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 6c87605ac91..9d3e44cd0c1 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -708,14 +708,12 @@ function arg($index) { } /** - * Prepare a URL for use in an HTML attribute. + * Prepare a URL for use in an HTML attribute. Strips harmful protocols. * - * We replace ( and ) with their url-encoded equivalents to prevent XSS attacks. */ function check_url($uri) { $uri = htmlspecialchars($uri, ENT_QUOTES); - - $uri = strtr($uri, array('(' => '%28', ')' => '%29')); + $uri = filter_xss_bad_protocol($uri, FALSE); return $uri; } diff --git a/includes/common.inc b/includes/common.inc index 84c955eed66..08545ce0e7c 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -615,13 +615,6 @@ function t($string, $args = 0) { } } -/** - * Encode special characters in a plain-text string for display as HTML. - */ -function check_plain($text) { - return htmlspecialchars($text, ENT_QUOTES); -} - /** * @defgroup validation Input validation * @{ @@ -667,54 +660,6 @@ function valid_url($url, $absolute = FALSE) { } } -/** - * Validate data input by a user. - * - * Ensures that user data cannot be used to perform attacks on the site. - * - * @param $data - * The input to check. - * @return - * TRUE if the input data is acceptable. - */ -function valid_input_data($data) { - if (is_array($data) || is_object($data)) { - // Form data can contain a number of nested arrays. - foreach ($data as $key => $value) { - if (!valid_input_data($key) || !valid_input_data($value)) { - return FALSE; - } - } - } - else if (isset($data)) { - // Detect dangerous input data. - - // Decode all normal character entities. - $data = decode_entities($data, array('<', '&', '"')); - - // Check strings: - $match = preg_match('/\Wjavascript\s*:/i', $data); - $match += preg_match('/\Wexpression\s*\(/i', $data); - $match += preg_match('/\Walert\s*\(/i', $data); - - // Check attributes: - $match += preg_match("/\W(dynsrc|datasrc|data|lowsrc|on[a-z]+)\s*=[^>]+?>/i", $data); - - // Check tags: - $match += preg_match("/<\s*(applet|script|object|style|embed|form|blink|meta|html|frame|iframe|layer|ilayer|head|frameset|xml)/i", $data); - - if ($match) { - watchdog('security', t('Terminated request because of suspicious input data: %data.', array('%data' => theme('placeholder', $data)))); - return FALSE; - } - } - - return TRUE; -} -/** - * @} End of "defgroup validation". - */ - /** * Register an event for the current visitor (hostname/IP) to the flood control mechanism. * @@ -1366,17 +1311,7 @@ function _drupal_bootstrap_full() { } // Initialize all enabled modules. module_init(); - if (!user_access('bypass input data check')) { - // We can't use $_REQUEST because it consists of the contents of $_POST, - // $_GET and $_COOKIE: if any of the input arrays share a key, only one - // value will be verified. - if (!valid_input_data($_GET) - || !valid_input_data($_POST) - || !valid_input_data($_COOKIE) - || !valid_input_data($_FILES)) { - die('Terminated request because of suspicious input data.'); - } - } + // Undo magic quotes fix_gpc_magic(); // Initialize the localization system. $locale = locale_initialize(); diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index ed02fa886c6..3fce79940cc 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -105,7 +105,7 @@ function _db_query($query, $debug = 0) { return $result; } else { - trigger_error(mysql_error() ."\nquery: ". htmlspecialchars($query), E_USER_ERROR); + trigger_error(check_plain(mysql_error() ."\nquery: ". $query), E_USER_ERROR); return FALSE; } } diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index f2583b214d9..3eaea585463 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -113,7 +113,7 @@ function _db_query($query, $debug = 0) { return $result; } else { - trigger_error(mysqli_error($active_db) ."\nquery: ". htmlspecialchars($query), E_USER_ERROR); + trigger_error(check_plain(mysqli_error($active_db) ."\nquery: ". $query), E_USER_ERROR); return FALSE; } } diff --git a/includes/database.pgsql.inc b/includes/database.pgsql.inc index 415565a477b..3c2f8f710d1 100644 --- a/includes/database.pgsql.inc +++ b/includes/database.pgsql.inc @@ -92,7 +92,7 @@ function _db_query($query, $debug = 0) { return $last_result; } else { - trigger_error(pg_last_error() ."\nquery: ". htmlspecialchars($query), E_USER_ERROR); + trigger_error(check_plain(pg_last_error() ."\nquery: ". $query), E_USER_ERROR); return FALSE; } } diff --git a/includes/file.inc b/includes/file.inc index 41f9a78f158..55f7825d5be 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -144,8 +144,24 @@ function file_check_upload($source) { elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) { $file = new StdClass(); $file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.'); - $file->filemime = $_FILES["edit"]["type"][$source]; $file->filepath = $_FILES["edit"]["tmp_name"][$source]; + + if (function_exists('mime_content_type')) { + $file->filemime = mime_content_type($file->filepath); + if ($file->filemime != $_FILES["edit"]["type"][$source]) { + watchdog('file', t('For %file the system thinks its MIME type is %detected while the user has given %given for MIME type', array('%file' => theme('placeholder', $file->filepath), '%detected' => theme('placeholder', $file>-filemime), '%given' => theme('placeholder', $_FILES['edit']['type'][$source])))); + } + } + else { + $file->filemime = $_FILES["edit"]["type"][$source]; + } + if (((substr($file->filemime, 0, 5) == 'text/' || strpos($file->filemime, 'javascript')) && (substr($file->filepath, -4) != '.txt')) || preg_match('/\.(php|pl|py|cgi|asp)$/i', $file->filename)) { + $file->filemime = 'text/plain'; + rename($file->filepath, $file->filepath .'.txt'); + $file->filepath .= '.txt'; + $file->filename .= '.txt'; + } + $file->error = $_FILES["edit"]["error"][$source]; $file->filesize = $_FILES["edit"]["size"][$source]; $file->source = $source; diff --git a/includes/unicode.inc b/includes/unicode.inc index 3508aad6485..0c562a8c1bb 100644 --- a/includes/unicode.inc +++ b/includes/unicode.inc @@ -303,6 +303,10 @@ function _decode_entities($prefix, $codepoint, $original, &$table, &$exclude) { if ($prefix == '#x') { $codepoint = base_convert($codepoint, 16, 10); } + // Decimal numerical entity (strip leading zeros to avoid PHP octal notation) + else { + $codepoint = preg_replace('/^0+/', '', $codepoint); + } // Encode codepoint as UTF-8 bytes if ($codepoint < 0x80) { $str = chr($codepoint); diff --git a/modules/filter.module b/modules/filter.module index 41e6ad39905..2ee9f17437c 100644 --- a/modules/filter.module +++ b/modules/filter.module @@ -14,9 +14,6 @@ define('FILTER_FORMAT_DEFAULT', 0); define('FILTER_HTML_STRIP', 1); define('FILTER_HTML_ESCAPE', 2); -define('FILTER_STYLE_ALLOW', 0); -define('FILTER_STYLE_STRIP', 1); - /** * Implementation of hook_help(). */ @@ -65,105 +62,100 @@ function filter_filter_tips($delta, $format, $long = false) { global $base_url; switch ($delta) { case 0: - switch (variable_get("filter_html_$format", FILTER_HTML_STRIP)) { + if (variable_get("filter_html_$format", FILTER_HTML_STRIP) == FILTER_HTML_STRIP) { + if ($allowed_html = variable_get("allowed_html_$format", '