Version Description
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 2.1.3 |
Comparing to | |
See all releases |
Code changes from version 2.1.2 to 2.1.3
- lib/wfConfig.php +96 -22
- lib/wfDB.php +6 -2
- lib/wfScanEngine.php +1 -1
- lib/wfSchema.php +1 -1
- lib/wordfenceClass.php +1 -0
- readme.txt +4 -0
- tmp/.htaccess +2 -0
- wfscan.php +3 -3
- wordfence.php +2 -2
lib/wfConfig.php
CHANGED
@@ -3,6 +3,7 @@ class wfConfig {
|
|
3 |
private static $table = false;
|
4 |
private static $cache = array();
|
5 |
private static $DB = false;
|
|
|
6 |
public static $securityLevels = array(
|
7 |
array( //level 0
|
8 |
"checkboxes" => array(
|
@@ -366,24 +367,8 @@ class wfConfig {
|
|
366 |
public static function clearCache(){
|
367 |
self::$cache = array();
|
368 |
}
|
369 |
-
public static function
|
370 |
-
|
371 |
-
// because we would have to concatenate $val twice into the query which could also exceed max packet for the mysql server
|
372 |
-
$dbh = self::getDB()->getDBH();
|
373 |
-
$exists = self::getDB()->querySingle("select name from " . self::table() . " where name='%s'", $key);
|
374 |
-
if($exists){
|
375 |
-
$res = mysql_query("update " . self::table() . " set val='" . mysql_real_escape_string(serialize($val)) . "' where name='" . mysql_real_escape_string($key) . "'", $dbh);
|
376 |
-
} else {
|
377 |
-
$res = mysql_query("insert IGNORE into " . self::table() . " (name, val) values ('" . mysql_real_escape_string($key) . "', '" . mysql_real_escape_string(serialize($val)) . "')", $dbh);
|
378 |
-
}
|
379 |
-
$err = mysql_error();
|
380 |
-
if($err){
|
381 |
-
$trace=debug_backtrace();
|
382 |
-
$caller=array_shift($trace);
|
383 |
-
wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
384 |
-
return false;
|
385 |
-
}
|
386 |
-
return true;
|
387 |
}
|
388 |
public static function set($key, $val){
|
389 |
if(is_array($val)){
|
@@ -393,9 +378,6 @@ class wfConfig {
|
|
393 |
self::getDB()->query("insert into " . self::table() . " (name, val) values ('%s', '%s') ON DUPLICATE KEY UPDATE val='%s'", $key, $val, $val);
|
394 |
self::$cache[$key] = $val;
|
395 |
}
|
396 |
-
public static function getHTML($key){
|
397 |
-
return htmlspecialchars(self::get($key));
|
398 |
-
}
|
399 |
public static function get($key, $default = false){
|
400 |
if(! isset(self::$cache[$key])){
|
401 |
$val = self::getDB()->querySingle("select val from " . self::table() . " where name='%s'", $key);
|
@@ -407,7 +389,35 @@ class wfConfig {
|
|
407 |
}
|
408 |
return self::$cache[$key];
|
409 |
}
|
410 |
-
public static function get_ser($key, $default){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
$dbh = self::getDB()->getDBH();
|
412 |
$res = mysql_query("select val from " . self::table() . " where name='" . mysql_real_escape_string($key) . "'", $dbh);
|
413 |
$err = mysql_error();
|
@@ -424,6 +434,70 @@ class wfConfig {
|
|
424 |
}
|
425 |
return $default;
|
426 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
public static function f($key){
|
428 |
echo esc_attr(self::get($key));
|
429 |
}
|
3 |
private static $table = false;
|
4 |
private static $cache = array();
|
5 |
private static $DB = false;
|
6 |
+
private static $tmpFileHeader = "<?php\n/* Wordfence temporary file security header */\necho \"Nothing to see here!\\n\"; exit(0);\n?>";
|
7 |
public static $securityLevels = array(
|
8 |
array( //level 0
|
9 |
"checkboxes" => array(
|
367 |
public static function clearCache(){
|
368 |
self::$cache = array();
|
369 |
}
|
370 |
+
public static function getHTML($key){
|
371 |
+
return htmlspecialchars(self::get($key));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
}
|
373 |
public static function set($key, $val){
|
374 |
if(is_array($val)){
|
378 |
self::getDB()->query("insert into " . self::table() . " (name, val) values ('%s', '%s') ON DUPLICATE KEY UPDATE val='%s'", $key, $val, $val);
|
379 |
self::$cache[$key] = $val;
|
380 |
}
|
|
|
|
|
|
|
381 |
public static function get($key, $default = false){
|
382 |
if(! isset(self::$cache[$key])){
|
383 |
$val = self::getDB()->querySingle("select val from " . self::table() . " where name='%s'", $key);
|
389 |
}
|
390 |
return self::$cache[$key];
|
391 |
}
|
392 |
+
public static function get_ser($key, $default, $canUseDisk = false){ //When using disk, reading a value deletes it.
|
393 |
+
//If we can use disk, check if there are any values stored on disk first and read them instead of the DB if there are values
|
394 |
+
if($canUseDisk){
|
395 |
+
$filename = 'wordfence_tmpfile_' . $key . '.php';
|
396 |
+
$dirs = self::getTempDirs();
|
397 |
+
$obj = false;
|
398 |
+
$foundFiles = false;
|
399 |
+
foreach($dirs as $dir){
|
400 |
+
$dir = rtrim($dir, '/') . '/';
|
401 |
+
$fullFile = $dir . $filename;
|
402 |
+
if(file_exists($fullFile)){
|
403 |
+
$foundFiles = true;
|
404 |
+
wordfence::status(4, 'info', "Loading serialized data from file $fullFile");
|
405 |
+
$obj = unserialize(substr(file_get_contents($fullFile), strlen(self::$tmpFileHeader))); //Strip off security header and unserialize
|
406 |
+
if($obj){
|
407 |
+
break;
|
408 |
+
} else {
|
409 |
+
wordfence::status(2, 'error', "Could not unserialize file $fullFile");
|
410 |
+
}
|
411 |
+
}
|
412 |
+
}
|
413 |
+
if($foundFiles){
|
414 |
+
self::deleteOldTempFiles($filename);
|
415 |
+
}
|
416 |
+
if($obj){ //If we managed to deserialize something, clean ALL tmp dirs of this file and return obj
|
417 |
+
return $obj;
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
$dbh = self::getDB()->getDBH();
|
422 |
$res = mysql_query("select val from " . self::table() . " where name='" . mysql_real_escape_string($key) . "'", $dbh);
|
423 |
$err = mysql_error();
|
434 |
}
|
435 |
return $default;
|
436 |
}
|
437 |
+
public static function set_ser($key, $val, $canUseDisk = false){
|
438 |
+
//We serialize some very big values so this is ultra-memory efficient. We don't make any copies of $val and don't use ON DUPLICATE KEY UPDATE
|
439 |
+
// because we would have to concatenate $val twice into the query which could also exceed max packet for the mysql server
|
440 |
+
$dbh = self::getDB()->getDBH();
|
441 |
+
$serialized = serialize($val);
|
442 |
+
$tempFilename = 'wordfence_tmpfile_' . $key . '.php';
|
443 |
+
if((strlen($serialized) * 1.1) > self::getDB()->getMaxAllowedPacketBytes()){ //If it's greater than max_allowed_packet + 10% for escaping and SQL
|
444 |
+
if($canUseDisk){
|
445 |
+
self::deleteOldTempFiles($tempFilename);
|
446 |
+
$dirs = self::getTempDirs();
|
447 |
+
$fh = false;
|
448 |
+
foreach($dirs as $dir){
|
449 |
+
$dir = rtrim($dir, '/') . '/';
|
450 |
+
$fullFile = $dir . $tempFilename;
|
451 |
+
$fh = fopen($fullFile, 'w');
|
452 |
+
if($fh){
|
453 |
+
wordfence::status(4, 'info', "Serialized data for $key is " . strlen($serialized) . " bytes and is greater than max_allowed packet so writing it to disk file: " . $fullFile);
|
454 |
+
break;
|
455 |
+
}
|
456 |
+
}
|
457 |
+
if(! $fh){
|
458 |
+
wordfence::status(1, 'error', "Your database doesn't allow big packets so we have to use files to store temporary data and Wordfence can't find a place to write them. Either ask your admin to increase max_allowed_packet on your MySQL database, or make one of the following directories writable by your web server: " . implode(', ', $dirs));
|
459 |
+
exit();
|
460 |
+
}
|
461 |
+
fwrite($fh, self::$tmpFileHeader);
|
462 |
+
fwrite($fh, $serialized);
|
463 |
+
fclose($fh);
|
464 |
+
return true;
|
465 |
+
} else {
|
466 |
+
wordfence::status(1, 'error', "Wordfence tried to save a variable with name '$key' and your database max_allowed_packet is set to be too small. This particular variable can't be saved to disk. Please ask your administrator to increase max_allowed_packet and also report this in the Wordfence forums because it may be a bug. Thanks.");
|
467 |
+
exit(0);
|
468 |
+
}
|
469 |
+
} else {
|
470 |
+
//Delete temp files on disk or else the DB will be written to but get_ser will see files on disk and read them instead
|
471 |
+
self::deleteOldTempFiles($tempFilename);
|
472 |
+
$exists = self::getDB()->querySingle("select name from " . self::table() . " where name='%s'", $key);
|
473 |
+
if($exists){
|
474 |
+
$res = mysql_query("update " . self::table() . " set val='" . mysql_real_escape_string($serialized) . "' where name='" . mysql_real_escape_string($key) . "'", $dbh);
|
475 |
+
} else {
|
476 |
+
$res = mysql_query("insert IGNORE into " . self::table() . " (name, val) values ('" . mysql_real_escape_string($key) . "', '" . mysql_real_escape_string($serialized) . "')", $dbh);
|
477 |
+
}
|
478 |
+
$err = mysql_error();
|
479 |
+
if($err){
|
480 |
+
$trace=debug_backtrace();
|
481 |
+
$caller=array_shift($trace);
|
482 |
+
wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
483 |
+
return false;
|
484 |
+
}
|
485 |
+
}
|
486 |
+
return true;
|
487 |
+
}
|
488 |
+
private static function deleteOldTempFiles($filename){
|
489 |
+
$dirs = self::getTempDirs();
|
490 |
+
foreach($dirs as &$dir){ //clean out old files in all dirs
|
491 |
+
$dir = rtrim($dir, '/') . '/';
|
492 |
+
$fullFile = $dir . $filename;
|
493 |
+
if(file_exists($fullFile)){
|
494 |
+
unlink($fullFile);
|
495 |
+
}
|
496 |
+
}
|
497 |
+
}
|
498 |
+
private static function getTempDirs(){
|
499 |
+
return array(sys_get_temp_dir(), wfUtils::getPluginBaseDir() . 'wordfence/tmp/');
|
500 |
+
}
|
501 |
public static function f($key){
|
502 |
echo esc_attr(self::get($key));
|
503 |
}
|
lib/wfDB.php
CHANGED
@@ -36,7 +36,7 @@ class wfDB {
|
|
36 |
$this->dbh = $dbh;
|
37 |
$this->query("SET NAMES 'utf8'");
|
38 |
//Set big packets for set_ser when it serializes a scan in between forks
|
39 |
-
|
40 |
} else {
|
41 |
$handleKey = md5($dbhost . $dbuser . $dbpassword . $dbname);
|
42 |
if(isset(self::$dbhCache[$handleKey])){
|
@@ -52,7 +52,7 @@ class wfDB {
|
|
52 |
$this->dbh = self::$dbhCache[$handleKey];
|
53 |
$this->query("SET NAMES 'utf8'");
|
54 |
//Set big packets for set_ser when it serializes a scan in between forks
|
55 |
-
|
56 |
}
|
57 |
}
|
58 |
}
|
@@ -167,6 +167,10 @@ class wfDB {
|
|
167 |
}
|
168 |
}
|
169 |
public function getDBH(){ return $this->dbh; }
|
|
|
|
|
|
|
|
|
170 |
}
|
171 |
|
172 |
?>
|
36 |
$this->dbh = $dbh;
|
37 |
$this->query("SET NAMES 'utf8'");
|
38 |
//Set big packets for set_ser when it serializes a scan in between forks
|
39 |
+
//$this->queryIgnoreError("SET GLOBAL max_allowed_packet=256*1024*1024");
|
40 |
} else {
|
41 |
$handleKey = md5($dbhost . $dbuser . $dbpassword . $dbname);
|
42 |
if(isset(self::$dbhCache[$handleKey])){
|
52 |
$this->dbh = self::$dbhCache[$handleKey];
|
53 |
$this->query("SET NAMES 'utf8'");
|
54 |
//Set big packets for set_ser when it serializes a scan in between forks
|
55 |
+
//$this->queryIgnoreError("SET GLOBAL max_allowed_packet=256*1024*1024");
|
56 |
}
|
57 |
}
|
58 |
}
|
167 |
}
|
168 |
}
|
169 |
public function getDBH(){ return $this->dbh; }
|
170 |
+
public function getMaxAllowedPacketBytes(){
|
171 |
+
$rec = $this->querySingleRec("show variables like 'max_allowed_packet'");
|
172 |
+
return $rec['Value'];
|
173 |
+
}
|
174 |
}
|
175 |
|
176 |
?>
|
lib/wfScanEngine.php
CHANGED
@@ -89,7 +89,7 @@ class wfScanEngine {
|
|
89 |
}
|
90 |
}
|
91 |
public function fork(){
|
92 |
-
wfConfig::set_ser('wfsd_engine', $this);
|
93 |
wfUtils::clearScanLock();
|
94 |
self::startScan(true);
|
95 |
exit(0);
|
89 |
}
|
90 |
}
|
91 |
public function fork(){
|
92 |
+
wfConfig::set_ser('wfsd_engine', $this, true);
|
93 |
wfUtils::clearScanLock();
|
94 |
self::startScan(true);
|
95 |
exit(0);
|
lib/wfSchema.php
CHANGED
@@ -126,7 +126,7 @@ class wfSchema {
|
|
126 |
ctime DOUBLE(17,6) UNSIGNED NOT NULL,
|
127 |
level tinyint UNSIGNED NOT NULL,
|
128 |
type char(5) NOT NULL,
|
129 |
-
msg varchar(
|
130 |
KEY k1(ctime),
|
131 |
KEY k2(type)
|
132 |
) default charset=utf8",
|
126 |
ctime DOUBLE(17,6) UNSIGNED NOT NULL,
|
127 |
level tinyint UNSIGNED NOT NULL,
|
128 |
type char(5) NOT NULL,
|
129 |
+
msg varchar(1000) NOT NULL,
|
130 |
KEY k1(ctime),
|
131 |
KEY k2(type)
|
132 |
) default charset=utf8",
|
lib/wordfenceClass.php
CHANGED
@@ -186,6 +186,7 @@ class wordfence {
|
|
186 |
$prefix = $wpdb->base_prefix;
|
187 |
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
188 |
$db->queryIgnoreError("alter table $prefix"."wfBlocks add column permanent tinyint UNSIGNED default 0");
|
|
|
189 |
|
190 |
//Must be the final line
|
191 |
update_option('wordfence_version', WORDFENCE_VERSION);
|
186 |
$prefix = $wpdb->base_prefix;
|
187 |
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
188 |
$db->queryIgnoreError("alter table $prefix"."wfBlocks add column permanent tinyint UNSIGNED default 0");
|
189 |
+
$db->queryIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
|
190 |
|
191 |
//Must be the final line
|
192 |
update_option('wordfence_version', WORDFENCE_VERSION);
|
readme.txt
CHANGED
@@ -152,6 +152,10 @@ or a theme, because often these have been updated to fix a security hole.
|
|
152 |
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
|
153 |
|
154 |
== Changelog ==
|
|
|
|
|
|
|
|
|
155 |
= 2.1.2 =
|
156 |
* Fixed issue with scan scheduling that caused a loop
|
157 |
* Fixed issue that caused version constant to not be included in scans
|
152 |
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
|
153 |
|
154 |
== Changelog ==
|
155 |
+
= 2.1.3: June 5, 2012 dev release =
|
156 |
+
* Added fix for hosts that have max_allowed_packet set too small. We will write a temp file to disk instead if possible.
|
157 |
+
* Increased size of status column to 1000 chars
|
158 |
+
|
159 |
= 2.1.2 =
|
160 |
* Fixed issue with scan scheduling that caused a loop
|
161 |
* Fixed issue that caused version constant to not be included in scans
|
tmp/.htaccess
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
deny from all
|
2 |
+
|
wfscan.php
CHANGED
@@ -85,15 +85,15 @@ class wfScan {
|
|
85 |
@ini_set('display_errors','On');
|
86 |
wordfence::status(4, 'info', "Setting up scanRunning and starting scan");
|
87 |
$isFork = ($_GET['isFork'] == '1' ? true : false);
|
88 |
-
$scan = wfConfig::get_ser('wfsd_engine', false);
|
89 |
if($scan){
|
90 |
//Set false so that we don't get stuck in a loop where we're repeating scan stages.
|
91 |
wordfence::status(4, 'info', "Got a true deserialized value back from 'wfsd_engine' with type: " . gettype($scan));
|
92 |
-
wfConfig::set('wfsd_engine', '');
|
93 |
} else {
|
94 |
if($isFork){ //We encountered an error so blank scan and exit
|
95 |
wordfence::status(2, 'error', "Scan can't continue - stored data not found after a fork. Got type: " . gettype($scan));
|
96 |
-
wfConfig::set('wfsd_engine', '');
|
97 |
exit();
|
98 |
} else {
|
99 |
wordfence::statusPrep(); //Re-initializes all status counters
|
85 |
@ini_set('display_errors','On');
|
86 |
wordfence::status(4, 'info', "Setting up scanRunning and starting scan");
|
87 |
$isFork = ($_GET['isFork'] == '1' ? true : false);
|
88 |
+
$scan = wfConfig::get_ser('wfsd_engine', false, true);
|
89 |
if($scan){
|
90 |
//Set false so that we don't get stuck in a loop where we're repeating scan stages.
|
91 |
wordfence::status(4, 'info', "Got a true deserialized value back from 'wfsd_engine' with type: " . gettype($scan));
|
92 |
+
wfConfig::set('wfsd_engine', '', true);
|
93 |
} else {
|
94 |
if($isFork){ //We encountered an error so blank scan and exit
|
95 |
wordfence::status(2, 'error', "Scan can't continue - stored data not found after a fork. Got type: " . gettype($scan));
|
96 |
+
wfConfig::set('wfsd_engine', '', true);
|
97 |
exit();
|
98 |
} else {
|
99 |
wordfence::statusPrep(); //Re-initializes all status counters
|
wordfence.php
CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
-
Version: 2.1.
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '2.1.
|
11 |
|
12 |
if(! defined('WORDFENCE_SCAN_MODE')){
|
13 |
require_once('lib/wordfenceConstants.php');
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 2.1.3
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '2.1.3');
|
11 |
|
12 |
if(! defined('WORDFENCE_SCAN_MODE')){
|
13 |
require_once('lib/wordfenceConstants.php');
|