3 * Database connection library
5 * @author Roland Haeder <webmaster@shipsimu.org>
7 * @copyright Copyright (c) 2009 - 2011 Cracker Tracker Team
8 * @license GNU GPL 3.0 or any newer version
9 * @link http://www.shipsimu.org
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 // Function to aquire a database link
26 function aquireCrackerTrackerDatabaseLink () {
28 if ((!isCrackerTrackerDatabaseLinkUp()) && (!empty($GLOBALS['ctracker_host'])) && (!empty($GLOBALS['ctracker_dbname'])) && (!empty($GLOBALS['ctracker_user']))) {
29 // Then connect to the database
30 $GLOBALS['ctracker_link'] = mysqli_connect($GLOBALS['ctracker_host'], $GLOBALS['ctracker_user'], $GLOBALS['ctracker_password'], $GLOBALS['ctracker_dbname']) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
32 // Check on connection and config table
33 if (!isCrackerTrackerDatabaseLinkUp()) {
34 // Connect didn't work
35 crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
36 } elseif (isCrackerTrackerTableCreated('ctracker_config')) {
38 crackerTrackerLoadConfig();
42 crackerTrackerInitFakeConfig();
46 // Inits a fake configurtation
47 function crackerTrackerInitFakeConfig () {
49 $GLOBALS['ctracker_config'] = array(
50 'ctracker_alert_user' => 'Y',
54 // Checks if the link is up
55 function isCrackerTrackerDatabaseLinkUp () {
56 // Is the instance at least set?
57 if (isset($GLOBALS['ctracker_link'])) {
59 //* DEBUG: */ error_log('isset='.intval(isset($GLOBALS['ctracker_link'])) . ',is_object=' . intval(is_object($GLOBALS['ctracker_link'])) . ',mysqli_connect_errno=' . mysqli_connect_errno());
62 //* DEBUG: */ error_log('ctracker_link not set.');
65 return ((isset($GLOBALS['ctracker_link'])) && (is_object($GLOBALS['ctracker_link'])) && (mysqli_connect_errno() == 0));
68 // Database error detected
69 function crackerTrackerDatabaseError ($F, $L) {
71 if (isCrackerTrackerDebug()) {
73 print 'Function : ' . $F . '<br />';
74 print 'Line : ' . $L . '<br />';
75 if (isset($GLOBALS['ctracker_link'])) {
76 print 'MySQL error : ' . mysqli_error($GLOBALS['ctracker_link']) . '<br />';
78 print 'No MySQLi available.<br />';
80 print 'Last SQL : '. $GLOBALS['ctracker_last_sql'] . '<br />';
83 // Currently only die here
87 // Closes a maybe open database link
88 function crackerTrackerCloseDatabaseLink () {
90 if (isCrackerTrackerDatabaseLinkUp()) {
92 if (!mysqli_close($GLOBALS['ctracker_link'])) {
94 crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
99 // Inserts given array, if IP/check_worm combination was not found
100 function crackerTrackerInsertArray ($table, $rowData) {
101 // Is there a link up?
102 if (!isCrackerTrackerDatabaseLinkUp()) {
103 // Abort silently here
108 if (!isCrackerTrackerEntryFound($rowData)) {
110 $SQL = 'INSERT INTO `' . $table . '` (`' . implode('`,`', array_keys($rowData)) . '`) VALUES(' . implode_secure($rowData) . ')';
113 $GLOBALS['ctracker_last_insert_id'] = FALSE;
116 runCrackerTrackerSql($SQL, __FUNCTION__, __LINE__);
118 // Remember the last insert id
119 $GLOBALS['ctracker_last_insert_id'] = mysqli_insert_id($GLOBALS['ctracker_link']) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
121 // Only update the entry
122 updateCrackerTrackerEntry($rowData);
126 // Updates a given entry by just counting it up
127 function updateCrackerTrackerEntry ($rowData) {
128 // Construct the SELECT query
129 $SQL = 'UPDATE `ctracker_data` SET `count`=`count`+1 WHERE (`remote_addr`="' . crackerTrackerEscapeString($rowData['remote_addr']) . '" OR `proxy_addr`="' . crackerTrackerEscapeString($rowData['proxy_addr']) . '") AND `check_worm` = "' . crackerTrackerEscapeString($rowData['check_worm']) . '" LIMIT 1';
131 // Run the SQL and check if we have one line
132 runCrackerTrackerSql($SQL, __FUNCTION__, __LINE__);
135 // Checks if an entry with IP/check_worm/domain combination is there
136 function isCrackerTrackerEntryFound ($rowData) {
137 // Construct the SELECT query
138 $SQL = 'SELECT `id` FROM `ctracker_data` WHERE (`remote_addr`="' . crackerTrackerEscapeString($rowData['remote_addr']) . '" OR `proxy_addr`="' . crackerTrackerEscapeString($rowData['proxy_addr']) . '") AND `check_worm` = "' . crackerTrackerEscapeString($rowData['check_worm']) . '" AND `server_name`="' . crackerTrackerEscapeString($rowData['server_name']) . '" LIMIT 1';
140 // Run the SQL and check if we have one line
141 return ((isCrackerTrackerDatabaseLinkUp()) && (mysqli_num_rows(runCrackerTrackerSql($SQL, __FUNCTION__, __LINE__)) == 1));
144 // Escapes the string
145 function crackerTrackerEscapeString ($string) {
147 if (!isCrackerTrackerDatabaseLinkUp()) {
148 // Then we cant use mysqli_real_escape_string!
149 $string = addslashes($string);
150 } elseif (function_exists('mysqli_real_escape_string')) {
151 // Use mysqli_real_escape_string()
152 $string = mysqli_real_escape_string($GLOBALS['ctracker_link'], $string);
154 // Use fall-back (bad!)
155 $string = addslashes($string);
158 // Return the secured string
162 // Runs an SQL query and checks for errors
163 function runCrackerTrackerSql ($SQL, $F, $L) {
165 if (!isCrackerTrackerDatabaseLinkUp()) {
171 $GLOBALS['ctracker_last_sql'] = $SQL;
174 $GLOBALS['ctracker_last_result'] = mysqli_query($GLOBALS['ctracker_link'], $SQL) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
177 return $GLOBALS['ctracker_last_result'];
180 // Checks wether a table was found
181 function isCrackerTrackerTableCreated ($table) {
182 // Default is not found
186 $result = runCrackerTrackerSql('SHOW TABLES', __FUNCTION__, __LINE__);
188 // Is our table there?
189 while (list($tab) = mysqli_fetch_row($result)) {
191 //* NOISY-DEBUG: */ error_log('tab=' . $tab);
193 // Is the table there?
194 if ($tab == $table) {
195 // Okay, found. So abort
202 freeCrackerTrackerResult($result);
208 // Creates the given table with columns
209 function crackerTrackerCreateTable ($table, array $columns, array $keys) {
211 $SQL = 'CREATE TABLE IF NOT EXISTS `' . $table . '` (';
213 // Add table name as first column
214 $SQL .= '`' . $table . '` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT, ';
217 foreach ($columns as $column=>$type) {
219 $SQL .= '`' . $column . '` ' . $type . ', ';
222 // Add table name as primary key
223 $SQL .= 'PRIMARY KEY (`' . $table . '`), ';
226 foreach ($keys as $key=>$type) {
228 $SQL .= '' . $type . ' (`' . $key . '`), ';
232 $SQL = substr($SQL, 0, -2) . ') TYPE=InnoDB';
235 runCrackerTrackerSql($SQL);
238 // Inits a table by inserting
239 function crackerTrackerInitTable ($table) {
240 // Prepare SQL and run it
241 runCrackerTrackerSql('INSERT INTO `' . $table . '` (`' . $table . '`) VALUES (NULL)');
244 // Updates the database scheme automatically
245 function crackerTrackerUpdateDatabaseScheme () {
247 if (!isCrackerTrackerDatabaseLinkUp()) {
248 // Abort here silently
252 // Is the main config table there?
253 if (!isCrackerTrackerTableCreated('ctracker_config')) {
255 crackerTrackerCreateTable('ctracker_config', array(
256 'ctracker_db_version' => 'BIGINT ( 20 ) UNSIGNED NOT NULL DEFAULT 0',
257 'ctracker_min_sleep' => 'SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT 10',
258 'ctracker_max_sleep' => 'SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT 30',
259 'ctracker_alert_user' => "ENUM('Y','N') NOT NULL DEFAULT 'Y'",
260 'ctracker_language' => "CHAR ( 2) NOT NULL DEFAULT 'en'"
264 crackerTrackerInitTable('ctracker_config');
267 // Init update array here
268 crackerTrackerInitUpdates();
270 // Run any SQL updates recursively
271 while (isset($GLOBALS['ctracker_updates'][getCrackerTrackerConfig('ctracker_db_version')])) {
273 runCrackerTrackerUpdates(getCrackerTrackerConfig('ctracker_db_version'));
276 runCrackerTrackerSql('UPDATE `ctracker_config` SET `ctracker_db_version`=`ctracker_db_version`+1 WHERE `ctracker_config`=1 LIMIT 1', __FUNCTION__, __LINE__);
278 // And count it up in the config array
279 $GLOBALS['ctracker_config']['ctracker_db_version']++;
283 // Load the configuration
284 function crackerTrackerLoadConfig () {
285 // Construct SQL command and run it
286 $result = runCrackerTrackerSql('SELECT * FROM `ctracker_config` WHERE `ctracker_config`=1 LIMIT 1', __FUNCTION__, __LINE__);
289 $GLOBALS['ctracker_config'] = mysqli_fetch_array($result);
292 freeCrackerTrackerResult($result);
296 function getCrackerTrackerConfig ($entry) {
297 // Is the config entry there?
298 if (!isset($GLOBALS['ctracker_config'][$entry])) {
299 // Then better die here, else we may have an endless loop
300 if (isCrackerTrackerDebug()) {
301 // Nicer message in debug mode
302 die('Configuration entry ' . $entry . ' missing!');
304 // die() on production systems
310 return $GLOBALS['ctracker_config'][$entry];
313 // Did the current IP already generated blocked attempts?
314 function isCrackerTrackerIpSuspicious () {
315 // Skip this silently if we have not config
316 if (!isCrackerTrackerDatabaseLinkUp()) {
317 // Skip this step silently, all is not suspicious
321 // Check if an entry is there
322 $result = runCrackerTrackerSql("SELECT COUNT(`id`) AS `cnt` FROM `ctracker_data` USE INDEX (`remote_proxy_last`) WHERE `remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' OR `proxy_addr`='" . getenv('REMOTE_ADDR') . "' LIMIT 1", __FUNCTION__, __LINE__);
325 list($rows) = mysqli_fetch_row($result);
327 // Is there one entry?
328 $found = ($rows > 0);
331 if ($found === TRUE) {
332 // Yes, one is found, then load it
333 $result = runCrackerTrackerSql("SELECT SQL_SMALL_RESULT * FROM `ctracker_data` USE INDEX (`remote_proxy_last`) WHERE `remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' OR `proxy_addr`='" . getenv('REMOTE_ADDR') . "' ORDER BY `last_attempt` DESC LIMIT 1", __FUNCTION__, __LINE__);
336 $GLOBALS['ctracker_last_suspicious_entry'] = mysqli_fetch_array($result);
340 freeCrackerTrackerResult($result);
346 // Does the current IP have a ticket?
347 function ifCrackerTrackerIpHasTicket () {
348 // We only give one ticket per IP!
349 $result = runCrackerTrackerSql("SELECT * FROM `ctracker_ticket` WHERE `ctracker_ticket_remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' OR `ctracker_ticket_proxy_addr`='" . getenv('REMOTE_ADDR') . "' LIMIT 1", __FUNCTION__, __LINE__);
351 // Do we have a ticket?
352 $found = (mysqli_num_rows($result) == 1);
355 if ($found === TRUE) {
356 // Cache the ticket data
357 $GLOBALS['ctracker_last_ticket'] = mysqli_fetch_array($result);
361 freeCrackerTrackerResult($result);
367 // Adds a ticket based on given (mostly $_POST) data
368 function addCrackerTrackerTicket (array $data) {
370 $GLOBALS['ctracker_last_ticket'] = array(
371 'ctracker_ticket_remote_addr' => determineCrackerTrackerRealRemoteAddress(),
372 'ctracker_ticket_proxy_addr' => getenv('REMOTE_ADDR'),
373 'ctracker_ticket_user_agent' => crackerTrackerUserAgent(),
374 'ctracker_ticket_name' => crackerTrackerSecureString($data['name']),
375 'ctracker_ticket_email' => crackerTrackerSecureString($data['email']),
376 'ctracker_ticket_comment' => crackerTrackerSecureString($data['comment'])
380 crackerTrackerInsertArray('ctracker_ticket', $GLOBALS['ctracker_last_ticket']);
382 // Is there an entry?
383 if ((isset($GLOBALS['ctracker_last_insert_id'])) && ($GLOBALS['ctracker_last_insert_id'] > 0)) {
384 // All fine, so prepare the link between ticket<->data
386 'ctracker_ticket_id' => $GLOBALS['ctracker_last_insert_id'],
387 'ctracker_data_id' => $GLOBALS['ctracker_last_suspicious_entry']['id']
390 // And insert it as well
391 crackerTrackerInsertArray('ctracker_ticket_data', $data);
393 // Add ticket id again
394 $GLOBALS['ctracker_ticket'] = $data['ctracker_ticket_id'];
396 // Merge all data for emails
397 $GLOBALS['ctracker_last_ticket'] = array_merge($GLOBALS['ctracker_last_ticket'], $data);
399 // Is this also there?
400 if ((isset($GLOBALS['ctracker_last_insert_id'])) && ($GLOBALS['ctracker_last_insert_id'] > 0)) {
401 // All fine, so display "thank you page"
402 crackerTrackerLoadTemplate('add_ticket_thanks');
413 // Frees given result instance
414 function freeCrackerTrackerResult (mysqli_result $result) {