ax_logwriter_set_defaults_option();
// Get current options
$this->options = $this->ax_logwriter_get_options();
// Listen for the activate event
register_activation_hook(AX_LOGWRITER_FILE, array($this, 'ax_logwriter_activate'));
// Listen for the uninstall event
register_uninstall_hook(AX_LOGWRITER_FILE, array('axLogWriter', 'ax_logwriter_uninstall'));
add_action( 'wp_login_failed', array( $this, 'ax_logwriter_login_failed_hook' ) );
add_filter( 'xmlrpc_pingback_error', array( $this, 'ax_logwriter_pingback_error_hook' ), 1 );
add_filter( 'plugin_action_links_' . AX_LOGWRITER_BASENAME, array( $this, 'ax_logwriter_settings_link' ) );
add_filter( 'plugin_row_meta', array( $this, 'ax_logwriter_row_meta' ), 10, 2 );
add_action( 'plugins_loaded', array( $this, 'ax_logwriter_load_plugin_textdomain' ) );
// Add a pingback log if option enabled
if( isset( $this->options[ 'security_log_each_pingback' ] ) &&
!empty( $this->options[ 'security_log_each_pingback' ] ) )
{
// Need to log each pingback request
add_action( 'xmlrpc_call', array( $this, 'ax_logwriter_pingback_request_hook' ) );
}
// Add a user enumeration log and stop it if option enabled
if( isset( $this->options[ 'security_stop_user_enumeration' ] ) &&
!empty( $this->options[ 'security_stop_user_enumeration' ] ) )
{
// Need to log and stop user enumeration
$this->ax_logwriter_security_stop_user_enumeration_hook();
}
// Add a remove wp version and generator meta feature if option enabled
if( isset( $this->options[ 'security_remove_generator' ] ) &&
!empty( $this->options[ 'security_remove_generator' ] ) )
{
// Need to remove wp version and generator meta
remove_action( 'wp_head', 'wp_generator' ); // Remove version number
add_filter('the_generator', create_function('', 'return "";'));
}
// Add a disable xmlrpc authenticated methods feature if option enabled
if( isset( $this->options[ 'security_disable_xmlrpc_authenticated_methods' ] ) &&
!empty( $this->options[ 'security_disable_xmlrpc_authenticated_methods' ] ) )
{
// Need to disable xmlrpc authenticated methods
add_filter( 'xmlrpc_enabled', '__return_false' );
}
// Add a kill multiple requests in a single xmlrpc call feature if option enabled
if( isset( $this->options[ 'security_kill_xmlrpc_on_login_error' ] ) &&
!empty( $this->options[ 'security_kill_xmlrpc_on_login_error' ] ) )
{
// Need to kill multiple requests in a single xmlrpc call
add_filter( 'xmlrpc_login_error', array( $this, 'ax_logwriter_xmlrpc_login_failed_hook' ), 10, 2 ) ;
}
}
/**
* HOOK functions
*/
public function ax_logwriter_load_plugin_textdomain()
{
load_plugin_textdomain( 'authentication-and-xmlrpc-log-writer', FALSE, basename( dirname( AX_LOGWRITER_FILE ) ) . '/languages/' );
}
public function ax_logwriter_login_failed_hook($username)
{
$site_name = "unknown" ;
if( function_exists( "get_bloginfo" ) ) {
$tmp_site_name = get_bloginfo('name') ;
if( !empty( $tmp_site_name ) ) {
$site_name = $tmp_site_name;
}
}
$real_ip = $this->ax_logwriter_get_real_ip() ;
$this->ax_logwriter_log_writer("Authentication failure on [".$site_name."] for ".$username." from ".$real_ip."");
}
public function ax_logwriter_pingback_error_hook($ixr_error)
{
$site_name = "unknown" ;
if( function_exists( "get_bloginfo" ) ) {
$tmp_site_name = get_bloginfo('name') ;
if( !empty( $tmp_site_name ) ) {
$site_name = $tmp_site_name;
}
}
if ( $ixr_error->code === 48 ) return $ixr_error; // don't punish duplication
$real_ip = $this->ax_logwriter_get_real_ip() ;
$this->ax_logwriter_log_writer("Pingback error ".$ixr_error->code." generated on [".$site_name."] from ".$real_ip."");
return $ixr_error;
}
public function ax_logwriter_pingback_request_hook($call)
{
$site_name = "unknown" ;
if( function_exists( "get_bloginfo" ) ) {
$tmp_site_name = get_bloginfo('name') ;
if( !empty( $tmp_site_name ) ) {
$site_name = $tmp_site_name;
}
}
if ('pingback.ping' == $call) {
global $wp_xmlrpc_server;
$args = array();
if ( is_object( $wp_xmlrpc_server ) ) {
$args = $wp_xmlrpc_server->message->params;
}
$to = 'unknown';
if ( ! empty( $args[1] ) ) {
$to = esc_url_raw( $args[1] );
}
$real_ip = $this->ax_logwriter_get_real_ip() ;
$this->ax_logwriter_log_writer("Pingback requested for '".$to."' on [".$site_name."] from ".$real_ip."");
}
}
public function ax_logwriter_security_stop_user_enumeration_hook()
{
if ( !is_admin() && isset($_SERVER['REQUEST_URI'])){
if( !preg_match('/(wp-comments-post)/', $_SERVER['REQUEST_URI']) && !empty($_REQUEST['author']) && (int) $_REQUEST['author'] ) {
$site_name = "unknown" ;
if( function_exists( "get_bloginfo" ) ) {
$tmp_site_name = get_bloginfo('name') ;
if( !empty( $tmp_site_name ) ) {
$site_name = $tmp_site_name;
}
}
$real_ip = $this->ax_logwriter_get_real_ip() ;
$this->ax_logwriter_log_writer("User enumeration attempt generated on [".$site_name."] from ".$real_ip."");
// Make a redirection to the home with 301 code
header ('HTTP/1.1 301 Moved Permanently');
header ('Location: ' . home_url() );
exit();
}
}
}
public function ax_logwriter_xmlrpc_login_failed_hook($error, $user)
{
wp_die( $error->message, "Authentication request fail", array( 'response' => 401 ) ) ;
}
public function ax_logwriter_settings_link( $links )
{
// Add settings link on plugin page
$action_links = array( 'settings' => '' . __('Settings', 'General') . '', );
return array_merge( $action_links, $links );
}
/**
* Show row meta on the plugin screen.
*
* @access public
* @param mixed $links Plugin Row Meta
* @param mixed $file Plugin Base file
* @return array
*/
public function ax_logwriter_row_meta( $links, $file )
{
if ( $file == AX_LOGWRITER_BASENAME )
{
$row_meta = array(
'home' => ''.__( 'Home','authentication-and-xmlrpc-log-writer' ).'',
'faq' => ''.__( 'FAQ','authentication-and-xmlrpc-log-writer' ).'',
'support' => ''.__( 'Support','authentication-and-xmlrpc-log-writer' ).'',
'rate' => ''.__( 'Rate','authentication-and-xmlrpc-log-writer' ).'',
'donate' => ''.__( 'Donate','authentication-and-xmlrpc-log-writer' ).'',
);
return array_merge( $links, $row_meta );
}
return (array) $links;
}
public function ax_logwriter_activate()
{
// Add option to WP option table
update_option($this->option_name, $this->defaults);
}
static function ax_logwriter_uninstall()
{
// Remove option from WP option table
delete_option('ax_logwriter');
}
/**
* Operational functions
*/
public function ax_logwriter_log_writer( $data_to_write = "Unkown error for authentication or xmlrpc" )
{
/**
* Function used for writing the final log
*/
// Get current and defaults options
$options = $this->options;
$defaults = $this->defaults;
$error_type = ( isset( $options[ 'error_type' ] ) ? $options[ 'error_type' ] : $defaults[ 'error_type' ] );
$error_log_path = ( isset( $options[ 'error_log_path' ] ) ? $options[ 'error_log_path' ] : $defaults[ 'error_log_path' ] );
$error_log_name = ( isset( $options[ 'error_log_name' ] ) ? $options[ 'error_log_name' ] : $defaults[ 'error_log_name' ] );
$error_log_timezone = ( isset( $options[ 'error_log_timezone' ] ) ? $options[ 'error_log_timezone' ] : $defaults[ 'error_log_timezone' ] );
// Manage php timestamp with microseconds
date_default_timezone_set($error_log_timezone);
$time = $this->ax_logwriter_date_with_micro("D M d H:i:s.u Y");
switch( $error_type )
{
case "SYSTEM" :
// Error by SYSLOG
openlog('wordpress('.$_SERVER['HTTP_HOST'].')', LOG_NDELAY|LOG_PID, LOG_AUTHPRIV);
syslog(LOG_NOTICE,$data_to_write);
break;
case "APACHE" :
// Error by APACHE ERROR LOG
error_log('wordpress('.$_SERVER['HTTP_HOST'].') '.$data_to_write, 0);
break;
case "CUSTOM" :
// Error by custom log
if( is_dir( $error_log_path ) && is_writable( $error_log_path ) && !empty( $error_log_name ) ) error_log('['.$time.'] wordpress('.$_SERVER['HTTP_HOST'].') '.$data_to_write.PHP_EOL, 3, $error_log_path.$error_log_name );
else error_log('wordpress('.$_SERVER['HTTP_HOST'].') '.$data_to_write, 0);
break;
default :
// Error by APACHE ERROR LOG
error_log('wordpress('.$_SERVER['HTTP_HOST'].') '.$data_to_write, 0);
}
}
public function ax_logwriter_get_real_ip()
{
/**
* Function used to analyze the user's IP address
*/
$ip = getenv("REMOTE_ADDR"); // default
if (getenv("HTTP_CLIENT_IP")) $ip = getenv("HTTP_CLIENT_IP");
else if(getenv("HTTP_X_FORWARDED_FOR")) $ip = getenv("HTTP_X_FORWARDED_FOR");
return $ip ;
}
private function ax_logwriter_date_with_micro($format, $timestamp = null)
{
/**
* Function used to calculate the date with microseconds
*/
if (is_null($timestamp) || $timestamp === false)
{
$timestamp = microtime(true);
}
$timestamp_int = (int) floor($timestamp);
$microseconds = (int) round(($timestamp - floor($timestamp)) * 1000000.0, 0);
$format_with_micro = str_replace("u", $microseconds, $format);
return date($format_with_micro, $timestamp_int);
}
private function ax_logwriter_set_defaults_option()
{
/**
* Function used to sets the defaults options
*/
$error_type = 'CUSTOM' ;
$error_log_path = '/storage/www/logs/' ;
$error_log_name = 'sites_auth_errors.log' ;
$error_log_timezone = 'Europe/Rome' ;
$wp_time_zone_string = get_option('timezone_string') ;
if( $wp_time_zone_string &&
!empty( $wp_time_zone_string ) )
{
$error_log_timezone = $wp_time_zone_string;
}
$security_log_each_pingback = '0' ;
$security_stop_user_enumeration = '0' ;
$security_remove_generator = '0' ;
$security_kill_xmlrpc_on_login_error = '0' ;
$security_disable_xmlrpc_authenticated_methods = '0' ;
$this->defaults = array(
'error_type' => $error_type,
'error_log_path' => $error_log_path,
'error_log_name' => $error_log_name,
'error_log_timezone' => $error_log_timezone,
'security_log_each_pingback' => $security_log_each_pingback,
'security_stop_user_enumeration' => $security_stop_user_enumeration,
'security_remove_generator' => $security_remove_generator,
'security_kill_xmlrpc_on_login_error' => $security_kill_xmlrpc_on_login_error,
'security_disable_xmlrpc_authenticated_methods' => $security_disable_xmlrpc_authenticated_methods
) ;
}
public function ax_logwriter_get_defaults_option()
{
$this->ax_logwriter_set_defaults_option();
return $this->defaults ;
}
public function ax_logwriter_get_options()
{
return get_option( $this->option_name );
}
}