1
+ − 1
<?php
+ − 2
+ − 3
/*
+ − 4
* Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
142
ca9118d9c0f2
Rebrand as 1.0.2 (Coblynau); internal links are now parsed by RenderMan::parse_internal_links()
Dan
diff
changeset
+ − 5
* Version 1.0.2 (Coblynau)
1
+ − 6
* Copyright (C) 2006-2007 Dan Fuhry
+ − 7
*
+ − 8
* This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
+ − 9
* as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+ − 10
*
+ − 11
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ − 12
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ − 13
*/
+ − 14
+ − 15
function db_error_handler($errno, $errstr, $errfile = false, $errline = false, $errcontext = Array() )
+ − 16
{
+ − 17
if ( !defined('ENANO_DEBUG') )
+ − 18
return;
+ − 19
$e = error_reporting(0);
+ − 20
error_reporting($e);
+ − 21
if ( $e < $errno )
+ − 22
return;
+ − 23
$errtype = 'Notice';
+ − 24
switch ( $errno )
+ − 25
{
+ − 26
case E_ERROR: case E_USER_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: $errtype = 'Error'; break;
+ − 27
case E_WARNING: case E_USER_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: $errtype = 'Warning'; break;
+ − 28
}
+ − 29
$debug = debug_backtrace();
+ − 30
$debug = $debug[2]['file'] . ', line ' . $debug[2]['line'];
+ − 31
echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
+ − 32
}
+ − 33
+ − 34
class mysql {
+ − 35
var $num_queries, $query_backtrace, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values;
+ − 36
var $row = array();
+ − 37
var $rowset = array();
+ − 38
var $errhandler;
+ − 39
+ − 40
function enable_errorhandler()
+ − 41
{
+ − 42
if ( function_exists('debug_backtrace') )
+ − 43
{
+ − 44
$this->errhandler = set_error_handler('db_error_handler');
+ − 45
}
+ − 46
}
+ − 47
+ − 48
function disable_errorhandler()
+ − 49
{
+ − 50
if ( $this->errhandler )
+ − 51
{
+ − 52
set_error_handler($this->errhandler);
+ − 53
}
+ − 54
else
+ − 55
{
+ − 56
restore_error_handler();
+ − 57
}
+ − 58
}
+ − 59
+ − 60
function sql_backtrace() {
+ − 61
$qb = explode("\n", $this->query_backtrace);
+ − 62
$bt = '';
+ − 63
//for($i=sizeof($qb)-1;$i>=0;$i--) {
+ − 64
for($i=0;$i<sizeof($qb);$i++) {
+ − 65
$bt .= $qb[$i]."\n";
+ − 66
}
+ − 67
return $bt;
+ − 68
}
+ − 69
+ − 70
function ensure_connection()
+ − 71
{
+ − 72
if(!$this->_conn)
+ − 73
{
+ − 74
$this->connect();
+ − 75
}
+ − 76
}
+ − 77
+ − 78
function _die($t = '') {
+ − 79
if(defined('ENANO_HEADERS_SENT')) {
+ − 80
ob_clean();
+ − 81
}
+ − 82
header('HTTP/1.1 500 Internal Server Error');
15
ad5986a53197
Fixed complicated SQL injection vulnerability in URL handler, updated license info for Tigra Tree Menu, and killed one XSS vulnerability
Dan
diff
changeset
+ − 83
$bt = $this->latest_query; // $this->sql_backtrace();
1
+ − 84
$e = htmlspecialchars(mysql_error());
+ − 85
if($e=='') $e='<none>';
91
+ − 86
$t = ( !empty($t) ) ? $t : '<No error description provided>';
+ − 87
global $email;
+ − 88
$email_info = ( defined('ENANO_CONFIG_FETCHED') && is_object($email) ) ? ', at <' . $email->jscode() . $email->encryptEmail(getConfig('contact_email')) . '>' : '';
+ − 89
$internal_text = '<h3>The site was unable to finish serving your request.</h3>
+ − 90
<p>We apologize for the inconveience, but an error occurred in the Enano database layer. Please report the full text of this page to the administrator of this site' . $email_info . '.</p>
+ − 91
<p>Description or location of error: '.$t.'<br />
+ − 92
Error returned by MySQL extension: ' . $e . '<br />
+ − 93
Most recent SQL query:</p>
+ − 94
<pre>'.$bt.'</pre>';
+ − 95
if(defined('ENANO_CONFIG_FETCHED')) die_semicritical('Database error', $internal_text);
+ − 96
else grinding_halt('Database error', $internal_text);
1
+ − 97
exit;
+ − 98
}
+ − 99
+ − 100
function die_json()
+ − 101
{
+ − 102
$e = addslashes(htmlspecialchars(mysql_error()));
+ − 103
$q = addslashes($this->latest_query);
+ − 104
$t = "{'mode':'error','error':'An error occurred during database query.\nQuery was:\n $q\n\nError returned by MySQL: $e'}";
+ − 105
die($t);
+ − 106
}
+ − 107
+ − 108
function get_error($t = '') {
+ − 109
header('HTTP/1.1 500 Internal Server Error');
+ − 110
$bt = $this->sql_backtrace();
+ − 111
$e = htmlspecialchars(mysql_error());
+ − 112
if($e=='') $e='<none>';
91
+ − 113
global $email;
+ − 114
$email_info = ( defined('ENANO_CONFIG_FETCHED') && is_object($email) ) ? ', at <' . $email->jscode() . $email->encryptEmail(getConfig('contact_email')) . '>' : '';
+ − 115
$internal_text = '<h3>The site was unable to finish serving your request.</h3>
+ − 116
<p>We apologize for the inconveience, but an error occurred in the Enano database layer. Please report the full text of this page to the administrator of this site' . $email_info . '.</p>
+ − 117
<p>Description or location of error: '.$t.'<br />
+ − 118
Error returned by MySQL extension: ' . $e . '<br />
+ − 119
Most recent SQL query:</p>
+ − 120
<pre>'.$bt.'</pre>';
+ − 121
return $internal_text;
1
+ − 122
}
+ − 123
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 124
function connect()
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 125
{
1
+ − 126
$this->enable_errorhandler();
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 127
1
+ − 128
dc_here('dbal: trying to connect....');
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 129
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 130
if ( defined('IN_ENANO_INSTALL') )
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 131
{
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 132
@include(ENANO_ROOT.'/config.new.php');
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 133
}
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 134
else
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 135
{
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 136
@include(ENANO_ROOT.'/config.php');
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 137
}
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 138
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 139
if ( isset($crypto_key) )
1
+ − 140
unset($crypto_key); // Get this sucker out of memory fast
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 141
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 142
if ( !defined('ENANO_INSTALLED') && !defined('MIDGET_INSTALLED') && !defined('IN_ENANO_INSTALL') )
1
+ − 143
{
+ − 144
dc_here('dbal: oops, looks like Enano isn\'t set up. Constants ENANO_INSTALLED, MIDGET_INSTALLED, and IN_ENANO_INSTALL are all undefined.');
218
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 145
// scriptPath isn't set yet - we need to autodetect it to avoid infinite redirects
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 146
if ( !defined('scriptPath') )
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 147
{
222
acfdccf7a2bf
Re-sync Oxygen and Mint and Oxygen simple with Oxygen main; a couple improvements to the redirect-on-no-config code
Dan
diff
changeset
+ − 148
if ( isset($_SERVER['PATH_INFO']) && !preg_match('/index\.php$/', $_SERVER['PATH_INFO']) )
218
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 149
{
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 150
$_SERVER['REQUEST_URI'] = preg_replace(';' . preg_quote($_SERVER['PATH_INFO']) . '$;', '', $_SERVER['REQUEST_URI']);
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 151
}
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 152
$sp = dirname($_SERVER['REQUEST_URI']);
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 153
if($sp == '/' || $sp == '\\') $sp = '';
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 154
define('scriptPath', $sp);
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 155
define('contentPath', "$sp/index.php?title=");
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 156
}
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 157
$loc = scriptPath . '/install.php';
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 158
// header("Location: $loc");
e0ec986c0af3
Searching sucks, and Enano's search algorithm was complete bullcrap. So I rewrote it. No, it does not use Google search technology. Like they have a patent for using the Arial font on search result pages anyway.
Dan
diff
changeset
+ − 159
redirect($loc, 'Enano not installed', 'We can\'t seem to find an Enano installation (valid config file). You will be transferred to the installation wizard momentarily...', 3);
1
+ − 160
exit;
+ − 161
}
+ − 162
$this->_conn = @mysql_connect($dbhost, $dbuser, $dbpasswd);
+ − 163
unset($dbuser);
+ − 164
unset($dbpasswd); // Security
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 165
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 166
if ( !$this->_conn )
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 167
{
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 168
dc_here('dbal: uhoh!<br />'.mysql_error());
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 169
grinding_halt('Enano is having a problem', '<p>Error: couldn\'t connect to MySQL.<br />'.mysql_error().'</p>');
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 170
}
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 171
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 172
// Reset some variables
1
+ − 173
$this->query_backtrace = '';
+ − 174
$this->num_queries = 0;
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 175
1
+ − 176
dc_here('dbal: we\'re in, selecting database...');
203
acb9d021b860
Database name can now contain dashes (as per requested at http://forum.enanocms.org/viewtopic.php?f=5&t=14); corrected some installer behavior issues with connecting as root and setting up permissions resulting in logs not being flushed, configs not being inserted, and what have you.
Dan
diff
changeset
+ − 177
$q = $this->sql_query('USE `'.$dbname.'`;');
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 178
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 179
if ( !$q )
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 180
$this->_die('The database could not be selected.');
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 181
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 182
// We're in!
1
+ − 183
dc_here('dbal: connected to MySQL');
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 184
1
+ − 185
$this->disable_errorhandler();
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 186
return true;
1
+ − 187
}
+ − 188
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 189
function sql_query($q)
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 190
{
1
+ − 191
$this->enable_errorhandler();
+ − 192
$this->num_queries++;
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 193
$this->query_backtrace .= $q . "\n";
1
+ − 194
$this->latest_query = $q;
+ − 195
dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 196
// First make sure we have a connection
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 197
if ( !$this->_conn )
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 198
{
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 199
$this->_die('A database connection has not yet been established.');
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 200
}
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 201
// Does this query look malicious?
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 202
if ( !$this->check_query($q) )
1
+ − 203
{
+ − 204
$this->report_query($q);
+ − 205
grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
+ − 206
}
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 207
1
+ − 208
$r = mysql_query($q, $this->_conn);
+ − 209
$this->latest_result = $r;
+ − 210
$this->disable_errorhandler();
+ − 211
return $r;
+ − 212
}
+ − 213
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 214
function sql_unbuffered_query($q)
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 215
{
1
+ − 216
$this->enable_errorhandler();
+ − 217
$this->num_queries++;
+ − 218
$this->query_backtrace .= '(UNBUFFERED) ' . $q."\n";
+ − 219
$this->latest_query = $q;
+ − 220
dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 221
// First make sure we have a connection
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 222
if ( !$this->_conn )
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 223
{
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 224
$this->_die('A database connection has not yet been established.');
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 225
}
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 226
// Does this query look malicious?
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 227
if ( !$this->check_query($q) )
1
+ − 228
{
+ − 229
$this->report_query($q);
+ − 230
grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
+ − 231
}
215
58477ab3937f
Hopefully managed to put enough hacks in there to make renaming the config file the last step, so if it fails, it can be done manually
Dan
diff
changeset
+ − 232
1
+ − 233
$r = mysql_unbuffered_query($q, $this->_conn);
+ − 234
$this->latest_result = $r;
+ − 235
$this->disable_errorhandler();
+ − 236
return $r;
+ − 237
}
+ − 238
+ − 239
/**
+ − 240
* Checks a SQL query for possible signs of injection attempts
+ − 241
* @param string $q the query to check
+ − 242
* @return bool true if query passed check, otherwise false
+ − 243
*/
+ − 244
+ − 245
function check_query($q, $debug = false)
+ − 246
{
+ − 247
if($debug) echo "\$db->check_query(): checking query: ".htmlspecialchars($q).'<br />'."\n";
+ − 248
$sz = strlen($q);
+ − 249
$quotechar = false;
+ − 250
$quotepos = 0;
+ − 251
$prev_is_quote = false;
+ − 252
$just_started = false;
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 253
for ( $i = 0; $i < strlen($q); $i++, $c = substr($q, $i, 1) )
1
+ − 254
{
+ − 255
$next = substr($q, $i+1, 1);
+ − 256
$next2 = substr($q, $i+2, 1);
+ − 257
$prev = substr($q, $i-1, 1);
+ − 258
$prev2 = substr($q, $i-2, 1);
+ − 259
if(isset($c) && in_array($c, Array('"', "'", '`')))
+ − 260
{
+ − 261
if($quotechar)
+ − 262
{
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 263
if (
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 264
( $quotechar == $c && $quotechar != $next && ( $quotechar != $prev || $just_started ) && $prev != '\\') ||
1
+ − 265
( $prev2 == '\\' && $prev == $quotechar && $quotechar == $c )
+ − 266
)
+ − 267
{
+ − 268
$quotechar = false;
+ − 269
if($debug) echo('$db->check_query(): just finishing a quote section, quoted string: '.htmlspecialchars(substr($q, $quotepos, $i - $quotepos + 1)) . '<br />');
+ − 270
$q = substr($q, 0, $quotepos) . 'SAFE_QUOTE' . substr($q, $i + 1, strlen($q));
+ − 271
if($debug) echo('$db->check_query(): Filtered query: '.$q.'<br />');
+ − 272
$i = $quotepos;
+ − 273
}
+ − 274
}
+ − 275
else
+ − 276
{
+ − 277
$quotechar = $c;
+ − 278
$quotepos = $i;
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 279
$just_started = true;
1
+ − 280
}
+ − 281
if($debug) echo '$db->check_query(): found quote char as pos: '.$i.'<br />';
+ − 282
continue;
+ − 283
}
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 284
$just_started = false;
1
+ − 285
}
+ − 286
if(substr(trim($q), strlen(trim($q))-1, 1) == ';') $q = substr(trim($q), 0, strlen(trim($q))-1);
+ − 287
for($i=0;$i<strlen($q);$i++,$c=substr($q, $i, 1))
+ − 288
{
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 289
if (
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 290
( ( $c == ';' && $i != $sz-1 ) || $c . substr($q, $i+1, 1) == '--' )
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 291
|| ( in_array($c, Array('"', "'", '`')) )
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 292
) // Don't permit semicolons in mid-query, and never allow comments
1
+ − 293
{
+ − 294
// Injection attempt!
+ − 295
if($debug)
+ − 296
{
+ − 297
$e = '';
+ − 298
for($j=$i-5;$j<$i+5;$j++)
+ − 299
{
+ − 300
if($j == $i) $e .= '<span style="color: red; text-decoration: underline;">' . $c . '</span>';
+ − 301
else $e .= $c;
+ − 302
}
+ − 303
echo 'Injection attempt caught at pos: '.$i.'<br />';
+ − 304
}
+ − 305
return false;
+ − 306
}
+ − 307
}
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 308
if ( preg_match('/[\s]+(SAFE_QUOTE|[\S]+)=\\1($|[\s]+)/', $q, $match) )
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 309
{
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 310
if ( $debug ) echo 'Found always-true test in query, injection attempt caught, match:<br />' . '<pre>' . print_r($match, true) . '</pre>';
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 311
return false;
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 312
}
1
+ − 313
return true;
+ − 314
}
+ − 315
+ − 316
/**
+ − 317
* Set the internal result pointer to X
+ − 318
* @param int $pos The number of the row
+ − 319
* @param resource $result The MySQL result resource - if not given, the latest cached query is assumed
+ − 320
* @return true on success, false on failure
+ − 321
*/
+ − 322
+ − 323
function sql_data_seek($pos, $result = false)
+ − 324
{
+ − 325
$this->enable_errorhandler();
+ − 326
if(!$result)
+ − 327
$result = $this->latest_result;
+ − 328
if(!$result)
+ − 329
{
+ − 330
$this->disable_errorhandler();
+ − 331
return false;
+ − 332
}
+ − 333
if(mysql_data_seek($result, $pos))
+ − 334
{
+ − 335
$this->disable_errorhandler();
+ − 336
return true;
+ − 337
}
+ − 338
else
+ − 339
{
+ − 340
$this->disable_errorhandler();
+ − 341
return false;
+ − 342
}
+ − 343
}
+ − 344
+ − 345
/**
+ − 346
* Reports a bad query to the admin
+ − 347
* @param string $query the naughty query
+ − 348
* @access private
+ − 349
*/
+ − 350
+ − 351
function report_query($query)
+ − 352
{
+ − 353
global $session;
+ − 354
if(is_object($session) && defined('ENANO_MAINSTREAM'))
+ − 355
$username = $session->username;
+ − 356
else
+ − 357
$username = 'Unavailable';
+ − 358
$query = $this->escape($query);
+ − 359
$q = $this->sql_query('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, page_text, author, edit_summary)
+ − 360
VALUES(\'security\', \'sql_inject\', '.time().', \'\', \''.$query.'\', \''.$username.'\', \''.$_SERVER['REMOTE_ADDR'].'\');');
+ − 361
}
+ − 362
73
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 363
/**
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 364
* Returns the ID of the row last inserted.
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 365
* @return int
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 366
*/
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 367
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 368
function insert_id()
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 369
{
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 370
return @mysql_insert_id();
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 371
}
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 372
1
+ − 373
function fetchrow($r = false) {
+ − 374
$this->enable_errorhandler();
+ − 375
if(!$this->_conn) return false;
+ − 376
if(!$r) $r = $this->latest_result;
+ − 377
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 378
$row = mysql_fetch_assoc($r);
+ − 379
$this->disable_errorhandler();
+ − 380
return $row;
+ − 381
}
+ − 382
+ − 383
function fetchrow_num($r = false) {
+ − 384
$this->enable_errorhandler();
+ − 385
if(!$r) $r = $this->latest_result;
+ − 386
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 387
$row = mysql_fetch_row($r);
+ − 388
$this->disable_errorhandler();
+ − 389
return $row;
+ − 390
}
+ − 391
+ − 392
function numrows($r = false) {
+ − 393
$this->enable_errorhandler();
+ − 394
if(!$r) $r = $this->latest_result;
+ − 395
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 396
$n = mysql_num_rows($r);
+ − 397
$this->disable_errorhandler();
+ − 398
return $n;
+ − 399
}
+ − 400
+ − 401
function escape($str)
+ − 402
{
+ − 403
$this->enable_errorhandler();
+ − 404
$str = mysql_real_escape_string($str);
+ − 405
$this->disable_errorhandler();
+ − 406
return $str;
+ − 407
}
+ − 408
+ − 409
function free_result($result = false)
+ − 410
{
+ − 411
$this->enable_errorhandler();
+ − 412
if(!$result)
+ − 413
$result = $this->latest_result;
+ − 414
if(!$result)
+ − 415
{
+ − 416
$this->disable_errorhandler();
+ − 417
return null;
+ − 418
}
+ − 419
mysql_free_result($result);
+ − 420
$this->disable_errorhandler();
+ − 421
return null;
+ − 422
}
+ − 423
+ − 424
function close() {
+ − 425
dc_here('dbal: closing MySQL connection');
+ − 426
mysql_close($this->_conn);
+ − 427
unset($this->_conn);
+ − 428
}
+ − 429
+ − 430
// phpBB DBAL compatibility
+ − 431
function sql_fetchrow($r = false)
+ − 432
{
+ − 433
return $this->fetchrow($r);
+ − 434
}
+ − 435
function sql_freeresult($r = false)
+ − 436
{
+ − 437
if(!$this->_conn) return false;
+ − 438
if(!$r) $r = $this->latest_result;
+ − 439
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 440
mysql_free_result($r);
+ − 441
}
+ − 442
function sql_numrows($r = false)
+ − 443
{
+ − 444
if(!$this->_conn) return false;
+ − 445
if(!$r) $r = $this->latest_result;
+ − 446
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 447
return mysql_num_rows($r);
+ − 448
}
+ − 449
function sql_affectedrows($r = false, $f, $n)
+ − 450
{
+ − 451
if(!$this->_conn) return false;
+ − 452
if(!$r) $r = $this->latest_result;
+ − 453
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 454
return mysql_affected_rows();
+ − 455
}
+ − 456
+ − 457
function sql_type_cast(&$value)
+ − 458
{
+ − 459
if ( is_float($value) )
+ − 460
{
+ − 461
return doubleval($value);
+ − 462
}
+ − 463
if ( is_integer($value) || is_bool($value) )
+ − 464
{
+ − 465
return intval($value);
+ − 466
}
+ − 467
if ( is_string($value) || empty($value) )
+ − 468
{
+ − 469
return '\'' . $this->sql_escape_string($value) . '\'';
+ − 470
}
+ − 471
// uncastable var : let's do a basic protection on it to prevent sql injection attempt
+ − 472
return '\'' . $this->sql_escape_string(htmlspecialchars($value)) . '\'';
+ − 473
}
+ − 474
+ − 475
function sql_statement(&$fields, $fields_inc='')
+ − 476
{
+ − 477
// init result
+ − 478
$this->sql_fields = $this->sql_values = $this->sql_update = '';
+ − 479
if ( empty($fields) && empty($fields_inc) )
+ − 480
{
+ − 481
return;
+ − 482
}
+ − 483
+ − 484
// process
+ − 485
if ( !empty($fields) )
+ − 486
{
+ − 487
$first = true;
+ − 488
foreach ( $fields as $field => $value )
+ − 489
{
+ − 490
// field must contain a field name
+ − 491
if ( !empty($field) && is_string($field) )
+ − 492
{
+ − 493
$value = $this->sql_type_cast($value);
+ − 494
$this->sql_fields .= ( $first ? '' : ', ' ) . $field;
+ − 495
$this->sql_values .= ( $first ? '' : ', ' ) . $value;
+ − 496
$this->sql_update .= ( $first ? '' : ', ' ) . $field . ' = ' . $value;
+ − 497
$first = false;
+ − 498
}
+ − 499
}
+ − 500
}
+ − 501
if ( !empty($fields_inc) )
+ − 502
{
+ − 503
foreach ( $fields_inc as $field => $indent )
+ − 504
{
+ − 505
if ( $indent != 0 )
+ − 506
{
+ − 507
$this->sql_update .= (empty($this->sql_update) ? '' : ', ') . $field . ' = ' . $field . ($indent < 0 ? ' - ' : ' + ') . abs($indent);
+ − 508
}
+ − 509
}
+ − 510
}
+ − 511
}
+ − 512
+ − 513
function sql_stack_reset($id='')
+ − 514
{
+ − 515
if ( empty($id) )
+ − 516
{
+ − 517
$this->sql_stack_fields = array();
+ − 518
$this->sql_stack_values = array();
+ − 519
}
+ − 520
else
+ − 521
{
+ − 522
$this->sql_stack_fields[$id] = array();
+ − 523
$this->sql_stack_values[$id] = array();
+ − 524
}
+ − 525
}
+ − 526
+ − 527
function sql_stack_statement(&$fields, $id='')
+ − 528
{
+ − 529
$this->sql_statement($fields);
+ − 530
if ( empty($id) )
+ − 531
{
+ − 532
$this->sql_stack_fields = $this->sql_fields;
+ − 533
$this->sql_stack_values[] = '(' . $this->sql_values . ')';
+ − 534
}
+ − 535
else
+ − 536
{
+ − 537
$this->sql_stack_fields[$id] = $this->sql_fields;
+ − 538
$this->sql_stack_values[$id][] = '(' . $this->sql_values . ')';
+ − 539
}
+ − 540
}
+ − 541
+ − 542
function sql_stack_insert($table, $transaction=false, $line='', $file='', $break_on_error=true, $id='')
+ − 543
{
+ − 544
if ( (empty($id) && empty($this->sql_stack_values)) || (!empty($id) && empty($this->sql_stack_values[$id])) )
+ − 545
{
+ − 546
return false;
+ − 547
}
+ − 548
switch( SQL_LAYER )
+ − 549
{
+ − 550
case 'mysql':
+ − 551
case 'mysql4':
+ − 552
if ( empty($id) )
+ − 553
{
+ − 554
$sql = 'INSERT INTO ' . $table . '
+ − 555
(' . $this->sql_stack_fields . ') VALUES ' . implode(",\n", $this->sql_stack_values);
+ − 556
}
+ − 557
else
+ − 558
{
+ − 559
$sql = 'INSERT INTO ' . $table . '
+ − 560
(' . $this->sql_stack_fields[$id] . ') VALUES ' . implode(",\n", $this->sql_stack_values[$id]);
+ − 561
}
+ − 562
$this->sql_stack_reset($id);
+ − 563
return $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
+ − 564
break;
+ − 565
default:
+ − 566
$count_sql_stack_values = empty($id) ? count($this->sql_stack_values) : count($this->sql_stack_values[$id]);
+ − 567
$result = !empty($count_sql_stack_values);
+ − 568
for ( $i = 0; $i < $count_sql_stack_values; $i++ )
+ − 569
{
+ − 570
if ( empty($id) )
+ − 571
{
+ − 572
$sql = 'INSERT INTO ' . $table . '
+ − 573
(' . $this->sql_stack_fields . ') VALUES ' . $this->sql_stack_values[$i];
+ − 574
}
+ − 575
else
+ − 576
{
+ − 577
$sql = 'INSERT INTO ' . $table . '
+ − 578
(' . $this->sql_stack_fields[$id] . ') VALUES ' . $this->sql_stack_values[$id][$i];
+ − 579
}
+ − 580
$result &= $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
+ − 581
}
+ − 582
$this->sql_stack_reset($id);
+ − 583
return $result;
+ − 584
break;
+ − 585
}
+ − 586
}
+ − 587
+ − 588
function sql_subquery($field, $sql, $line='', $file='', $break_on_error=true, $type=TYPE_INT)
+ − 589
{
+ − 590
// sub-queries doable
+ − 591
$this->sql_get_version();
+ − 592
if ( !in_array(SQL_LAYER, array('mysql', 'mysql4')) || (($this->sql_version[0] + ($this->sql_version[1] / 100)) >= 4.01) )
+ − 593
{
+ − 594
return $sql;
+ − 595
}
+ − 596
+ − 597
// no sub-queries
+ − 598
$ids = array();
+ − 599
$result = $this->sql_query(trim($sql), false, $line, $file, $break_on_error);
+ − 600
while ( $row = $this->sql_fetchrow($result) )
+ − 601
{
+ − 602
$ids[] = $type == TYPE_INT ? intval($row[$field]) : '\'' . $this->sql_escape_string($row[$field]) . '\'';
+ − 603
}
+ − 604
$this->sql_freeresult($result);
+ − 605
return empty($ids) ? 'NULL' : implode(', ', $ids);
+ − 606
}
+ − 607
+ − 608
function sql_col_id($expr, $alias)
+ − 609
{
+ − 610
$this->sql_get_version();
+ − 611
return in_array(SQL_LAYER, array('mysql', 'mysql4')) && (($this->sql_version[0] + ($this->sql_version[1] / 100)) <= 4.01) ? $alias : $expr;
+ − 612
}
+ − 613
+ − 614
function sql_get_version()
+ − 615
{
+ − 616
if ( empty($this->sql_version) )
+ − 617
{
+ − 618
$this->sql_version = array(0, 0, 0);
+ − 619
switch ( SQL_LAYER )
+ − 620
{
+ − 621
case 'mysql':
+ − 622
case 'mysql4':
+ − 623
if ( function_exists('mysql_get_server_info') )
+ − 624
{
+ − 625
$lo_version = explode('-', mysql_get_server_info());
+ − 626
$this->sql_version = explode('.', $lo_version[0]);
+ − 627
$this->sql_version = array(intval($this->sql_version[0]), intval($this->sql_version[1]), intval($this->sql_version[2]), $lo_version[1]);
+ − 628
}
+ − 629
break;
+ − 630
+ − 631
case 'postgresql':
+ − 632
case 'mssql':
+ − 633
case 'mssql-odbc':
+ − 634
default:
+ − 635
break;
+ − 636
}
+ − 637
}
+ − 638
return $this->sql_version;
+ − 639
}
+ − 640
+ − 641
function sql_error()
+ − 642
{
+ − 643
if ( $this->_conn )
+ − 644
{
+ − 645
return mysql_error();
+ − 646
}
+ − 647
else
+ − 648
{
+ − 649
return array();
+ − 650
}
+ − 651
}
+ − 652
function sql_escape_string($t)
+ − 653
{
+ − 654
return mysql_real_escape_string($t);
+ − 655
}
+ − 656
function sql_close()
+ − 657
{
+ − 658
$this->close();
+ − 659
}
+ − 660
function sql_fetchrowset($query_id = 0)
+ − 661
{
+ − 662
if( !$query_id )
+ − 663
{
+ − 664
$query_id = $this->query_result;
+ − 665
}
+ − 666
+ − 667
if( $query_id )
+ − 668
{
+ − 669
unset($this->rowset[$query_id]);
+ − 670
unset($this->row[$query_id]);
+ − 671
+ − 672
while($this->rowset[$query_id] = mysql_fetch_array($query_id, MYSQL_ASSOC))
+ − 673
{
+ − 674
$result[] = $this->rowset[$query_id];
+ − 675
}
+ − 676
+ − 677
return $result;
+ − 678
}
+ − 679
else
+ − 680
{
+ − 681
return false;
+ − 682
}
+ − 683
}
+ − 684
}
+ − 685
+ − 686
?>