public static function get_instance()
 {
     if (!self::$instance) {
         self::$instance = new self();
     }
     return self::$instance;
 }
 /**
  * Loads core functionality across both admin and frontend.
  *
  * Creates all plugin globals, registers activation and related hooks,
  * loads the text domain and loads all plugin modules
  *
  * @since 4.0
  *
  * @access private
  *
  * @param string $plugin_file The main plugin file
  * @param string $plugin_name The plugin name
  *
  */
 public function init($plugin_file, $plugin_name)
 {
     global $itsec_globals, $itsec_logger, $itsec_lockout;
     $this->plugin_build = 4044;
     // used to trigger updates
     $this->plugin_file = $plugin_file;
     $this->plugin_dir = dirname($plugin_file) . '/';
     $this->current_time = current_time('timestamp');
     $this->current_time_gmt = current_time('timestamp', true);
     $this->notices_loaded = false;
     $this->doing_data_upgrade = false;
     $this->interactive = false;
     // Used to distinguish between a user modifying settings and the API modifying
     // settings (such as from Sync requests).
     $itsec_globals = array('plugin_name' => sanitize_text_field($plugin_name), 'plugin_dir' => $this->plugin_dir, 'current_time' => $this->current_time, 'current_time_gmt' => $this->current_time_gmt);
     require $this->plugin_dir . 'core/class-itsec-modules.php';
     add_action('itsec-register-modules', array($this, 'register_modules'));
     ITSEC_Modules::init_modules();
     require $this->plugin_dir . 'core/class-itsec-lib.php';
     require $this->plugin_dir . 'core/class-itsec-logger.php';
     require $this->plugin_dir . 'core/class-itsec-lockout.php';
     require $this->plugin_dir . 'core/class-itsec-files.php';
     require $this->plugin_dir . 'core/class-itsec-notify.php';
     require $this->plugin_dir . 'core/class-itsec-response.php';
     require $this->plugin_dir . 'core/lib/class-itsec-lib-user-activity.php';
     $this->itsec_files = ITSEC_Files::get_instance();
     $this->itsec_notify = new ITSEC_Notify();
     $itsec_logger = new ITSEC_Logger();
     $itsec_lockout = new ITSEC_Lockout($this);
     //Determine if we need to run upgrade scripts
     $plugin_data = get_site_option('itsec_data');
     if (false === $plugin_data) {
         $plugin_data = $this->save_plugin_data();
     }
     $itsec_globals['data'] = $plugin_data;
     if (isset($plugin_data['build']) && $plugin_data['build'] !== $this->plugin_build) {
         // We need to upgrade the data. Delay init of the rest of the plugin until the upgrade is complete.
         $this->doing_data_upgrade = true;
         // Run the actions early so that the rest of the code can still use the plugins_loaded hook.
         add_action('plugins_loaded', array($this, 'execute_upgrade'), -100);
         add_action('plugins_loaded', array($this, 'continue_init'), -90);
     } else {
         $this->continue_init();
     }
 }
 /**
  * Inserts an IP address into the htaccess ban list.
  *
  * @since 4.0
  *
  * @param      $ip
  * @param null $ban_list
  * @param null $white_list
  *
  * @return void
  */
 public static function insert_ip($ip, $ban_list = null, $white_list = null)
 {
     $settings = get_site_option('itsec_ban_users');
     $host = sanitize_text_field($ip);
     if ($ban_list === null) {
         $ban_list = isset($settings['host_list']) ? $settings['host_list'] : array();
     }
     if ($white_list === null) {
         $global_settings = get_site_option('itsec_global');
         $white_list = isset($global_settings['lockout_white_list']) ? $global_settings['lockout_white_list'] : array();
     }
     if (!in_array($host, $ban_list) && !ITSEC_Ban_Users::is_ip_whitelisted($host, $white_list)) {
         $ban_list[] = $host;
         $settings['host_list'] = $ban_list;
         ITSEC_Files::quick_ban($host);
         update_site_option('itsec_ban_users', $settings);
         add_site_option('itsec_rewrites_changed', true);
     }
 }
 /**
  * Locks out given user or host
  *
  * @since 4.0
  *
  * @param  string $type     The type of lockout (for user reference)
  * @param  string $reason   Reason for lockout, for notifications
  * @param  string $host     Host to lock out
  * @param  int    $user     user id to lockout
  * @param string  $username username to lockout
  *
  * @return void
  */
 private function lockout($type, $reason, $host = null, $user = null, $username = null)
 {
     global $wpdb, $itsec_logger, $itsec_globals;
     $itsec_files = ITSEC_Core::get_itsec_files();
     $host_expiration = null;
     $user_expiration = null;
     $username = sanitize_text_field(trim($username));
     if ($itsec_files->get_file_lock('lockout_' . $host . $user . $username)) {
         //Do we have a good host to lock out or not
         if (!is_null($host) && ITSEC_Lib::is_ip_whitelisted(sanitize_text_field($host)) === false && ITSEC_Lib_IP_Tools::validate($host)) {
             $good_host = sanitize_text_field($host);
         } else {
             $good_host = false;
         }
         //Do we have a valid user to lockout or not
         if ($user !== null && ITSEC_Lib::user_id_exists(intval($user)) === true) {
             $good_user = intval($user);
         } else {
             $good_user = false;
         }
         //Do we have a valid username to lockout or not
         if ($username !== null && $username != '') {
             $good_username = $username;
         } else {
             $good_username = false;
         }
         $blacklist_host = false;
         //assume we're not permanently blcking the host
         //Sanitize the data for later
         $type = sanitize_text_field($type);
         $reason = sanitize_text_field($reason);
         //handle a permanent host ban (if needed)
         if (ITSEC_Modules::get_setting('global', 'blacklist') && $good_host !== false) {
             //permanent blacklist
             $blacklist_period = ITSEC_Modules::get_setting('global', 'blacklist_period', 7);
             $blacklist_seconds = $blacklist_period * DAY_IN_SECONDS;
             $host_count = 1 + $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM `" . $wpdb->base_prefix . "itsec_lockouts` WHERE `lockout_expire_gmt` > '%s' AND `lockout_host`='%s';", date('Y-m-d H:i:s', $itsec_globals['current_time_gmt'] - $blacklist_seconds), $host));
             if ($host_count >= ITSEC_Modules::get_setting('global', 'blacklist_count') && ITSEC_Files::can_write_to_files()) {
                 $host_expiration = false;
                 $this->blacklist_ip(sanitize_text_field($host));
                 $blacklist_host = true;
                 //flag it so we don't do a temp ban as well
             }
         }
         //We have temp bans to perform
         if ($good_host !== false || $good_user !== false || $good_username || $good_username !== false) {
             if (ITSEC_Lib::is_ip_whitelisted(sanitize_text_field($host))) {
                 $whitelisted = true;
                 $expiration = date('Y-m-d H:i:s', 1);
                 $expiration_gmt = date('Y-m-d H:i:s', 1);
             } else {
                 $whitelisted = false;
                 $exp_seconds = ITSEC_Modules::get_setting('global', 'lockout_period') * MINUTE_IN_SECONDS;
                 $expiration = date('Y-m-d H:i:s', $itsec_globals['current_time'] + $exp_seconds);
                 $expiration_gmt = date('Y-m-d H:i:s', $itsec_globals['current_time_gmt'] + $exp_seconds);
             }
             if ($good_host !== false && $blacklist_host === false) {
                 //temp lockout host
                 $host_expiration = $expiration;
                 $wpdb->insert($wpdb->base_prefix . 'itsec_lockouts', array('lockout_type' => $type, 'lockout_start' => date('Y-m-d H:i:s', $itsec_globals['current_time']), 'lockout_start_gmt' => date('Y-m-d H:i:s', $itsec_globals['current_time_gmt']), 'lockout_expire' => $expiration, 'lockout_expire_gmt' => $expiration_gmt, 'lockout_host' => sanitize_text_field($host)));
                 $itsec_logger->log_event('lockout', 10, array('expires' => $expiration, 'expires_gmt' => $expiration_gmt, 'type' => $type), sanitize_text_field($host));
             }
             if ($good_user !== false) {
                 //blacklist host and temp lockout user
                 $user_expiration = $expiration;
                 $wpdb->insert($wpdb->base_prefix . 'itsec_lockouts', array('lockout_type' => $type, 'lockout_start' => date('Y-m-d H:i:s', $itsec_globals['current_time']), 'lockout_start_gmt' => date('Y-m-d H:i:s', $itsec_globals['current_time_gmt']), 'lockout_expire' => $expiration, 'lockout_expire_gmt' => $expiration_gmt, 'lockout_host' => '', 'lockout_user' => intval($user)));
                 if ($whitelisted === false) {
                     $itsec_logger->log_event('lockout', 10, array('expires' => $expiration, 'expires_gmt' => $expiration_gmt, 'type' => $type), '', '', intval($user));
                 } else {
                     $itsec_logger->log_event('lockout', 10, array(__('White Listed', 'better-wp-security'), 'type' => $type), '', '', intval($user));
                 }
             }
             if ($good_username !== false) {
                 //blacklist host and temp lockout username
                 $user_expiration = $expiration;
                 $wpdb->insert($wpdb->base_prefix . 'itsec_lockouts', array('lockout_type' => $type, 'lockout_start' => date('Y-m-d H:i:s', $itsec_globals['current_time']), 'lockout_start_gmt' => date('Y-m-d H:i:s', $itsec_globals['current_time_gmt']), 'lockout_expire' => $expiration, 'lockout_expire_gmt' => $expiration_gmt, 'lockout_host' => '', 'lockout_username' => $username));
                 if ($whitelisted === false) {
                     $itsec_logger->log_event('lockout', 10, array('expires' => $expiration, 'expires_gmt' => $expiration_gmt, 'type' => $type), '', '', $username);
                 } else {
                     $itsec_logger->log_event('lockout', 10, array(__('White Listed', 'better-wp-security'), 'type' => $type), '', '', $username);
                 }
             }
             if ($whitelisted === false) {
                 if (ITSEC_Modules::get_setting('global', 'email_notifications')) {
                     //send email notifications
                     $this->send_lockout_email($good_host, $good_user, $good_username, $host_expiration, $user_expiration, $reason);
                 }
                 if ($good_host !== false) {
                     $itsec_files->release_file_lock('lockout_' . $host . $user . $username);
                     $this->execute_lock();
                 } else {
                     $itsec_files->release_file_lock('lockout_' . $host . $user . $username);
                     $this->execute_lock(true);
                 }
             }
         }
         $itsec_files->release_file_lock('lockout_' . $host . $user . $username);
     }
 }
 /**
  * Update modifications in the supplied configuration file.
  *
  * If a blank $contents argument is supplied, all modifications will be removed.
  *
  * @since 1.15.0
  * @access protected
  *
  * @param string $file                         Config file to update.
  * @param string $type                         The type of config file. Valid options are apache, nginx, and
  *                                             wp-config.
  * @param string $modification                 The contents to add or update the file with. If an empty string is
  *                                             supplied, all iThemes Security modifications will be removed.
  * @param bool   $clear_existing_modifications Optional. Whether or not existing modifications should be removed
  *                                             first. Defaults to true.
  * @return bool|WP_Error Boolean true on success or a WP_Error object otherwise.
  */
 protected static function update($file, $type, $modification, $clear_existing_modifications = true)
 {
     // Check to make sure that the settings give permission to write files.
     if (!ITSEC_Files::can_write_to_files()) {
         $display_file = str_replace('\\', '/', $file);
         $abspath = str_replace('\\', '/', ABSPATH);
         $display_file = preg_replace('/^' . preg_quote($abspath, '/') . '/', '', $display_file);
         $display_file = ltrim($display_file, '/');
         return new WP_Error('itsec-config-file-update-writes-files-disabled', sprintf(__('The "Write to Files" setting is disabled. Manual configuration for the <code>%s</code> file can be found on the Security > Settings page in the Advanced section.', 'better-wp-security'), $display_file));
     }
     if ($clear_existing_modifications) {
         $contents = self::get_file_contents_without_modification($file, $type);
     } else {
         $contents = self::get_file_contents($file);
     }
     if (is_wp_error($contents)) {
         return $contents;
     }
     $modification = ltrim($modification, "\v\r\n");
     $modification = rtrim($modification, " \t\v\r\n");
     if (empty($modification)) {
         // If there isn't a new modification, write the content without any modification and return the result.
         if (empty($contents)) {
             $contents = PHP_EOL;
         }
         return ITSEC_Lib_File::write($file, $contents);
     }
     $placeholder = self::get_placeholder();
     // Ensure that the generated placeholder can be uniquely identified in the contents.
     while (false !== strpos($contents, $placeholder)) {
         $placeholder = self::get_placeholder();
     }
     if ('wp-config' === $type) {
         // Put the placeholder at the beginning of the file, after the <?php tag.
         $contents = preg_replace('/^(.*?<\\?(?:php)?)\\s*(?:\\r\\r\\n|\\r\\n|\\r|\\n)/', "\${1}{$placeholder}", $contents, 1);
         if (false === strpos($contents, $placeholder)) {
             $contents = preg_replace('/^(.*?<\\?(?:php)?)\\s*(.+(?:\\r\\r\\n|\\r\\n|\\r|\\n))/', "\${1}{$placeholder}\$2", $contents, 1);
         }
         if (false === strpos($contents, $placeholder)) {
             $contents = "<?php{$placeholder}?" . ">{$contents}";
         }
     } else {
         // Apache and nginx server config files.
         $contents = "{$placeholder}{$contents}";
     }
     // Pad away from existing sections when adding iThemes Security modifications.
     $line_ending = self::get_line_ending($contents);
     while (!preg_match("/(?:^|(?:(?<!\r)\n|\r(?!\n)|(?<!\r)\r\n|\r\r\n)(?:(?<!\r)\n|\r(?!\n)|(?<!\r)\r\n|\r\r\n)){$placeholder}/", $contents)) {
         $contents = preg_replace("/{$placeholder}/", "{$line_ending}{$placeholder}", $contents);
     }
     while (!preg_match("/{$placeholder}(?:\$|(?:(?<!\r)\n|\r(?!\n)|(?<!\r)\r\n|\r\r\n)(?:(?<!\r)\n|\r(?!\n)|(?<!\r)\r\n|\r\r\n))/", $contents)) {
         $contents = preg_replace("/{$placeholder}/", "{$placeholder}{$line_ending}", $contents);
     }
     // Ensure that the file ends in a newline if the placeholder is at the end.
     $contents = preg_replace("/{$placeholder}\$/", "{$placeholder}{$line_ending}", $contents);
     if (!empty($modification)) {
         // Normalize line endings of the modification to match the file's line endings.
         $modification = ITSEC_Lib_Utility::normalize_line_endings($modification, $line_ending);
         // Exchange the placeholder with the modification.
         $contents = preg_replace("/{$placeholder}/", $modification, $contents);
     }
     // Write the new contents to the file and return the results.
     return ITSEC_Lib_File::write($file, $contents);
 }
Example #6
0
 public static function maybe_regenerate_server_config()
 {
     $self = self::get_instance();
     if ($self->regenerate_server_config) {
         ITSEC_Files::regenerate_server_config();
         $self->regenerate_server_config = false;
     }
 }