Example #1
0
/**
 * Process the requests sent by the form submissions originated in the settings
 * page, all forms must have a nonce field that will be checked against the one
 * generated in the template render function.
 *
 * @param  boolean $page_nonce True if the nonce is valid, False otherwise.
 * @return void
 */
function sucuriscan_settings_form_submissions($page_nonce = null)
{
    global $sucuriscan_schedule_allowed, $sucuriscan_interface_allowed, $sucuriscan_notify_options, $sucuriscan_emails_per_hour, $sucuriscan_maximum_failed_logins, $sucuriscan_email_subjects;
    // Use this conditional to avoid double checking.
    if (is_null($page_nonce)) {
        $page_nonce = SucuriScanInterface::check_nonce();
    }
    if ($page_nonce) {
        // Save API key after it was recovered by the administrator.
        if ($api_key = SucuriScanRequest::post(':manual_api_key')) {
            SucuriScanAPI::set_plugin_key($api_key, true);
            SucuriScanEvent::schedule_task();
            SucuriScanEvent::report_info_event('Sucuri API key was added manually.');
        }
        // Remove API key from the local storage.
        if (SucuriScanRequest::post(':remove_api_key') !== false) {
            SucuriScanAPI::set_plugin_key('');
            wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
            SucuriScanEvent::report_critical_event('Sucuri API key was deleted.');
            SucuriScanEvent::notify_event('plugin_change', 'Sucuri API key removed');
        }
        // Enable or disable the filesystem scanner.
        if ($fs_scanner = SucuriScanRequest::post(':fs_scanner', '(en|dis)able')) {
            $action_d = $fs_scanner . 'd';
            $message = 'Main file system scanner was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':fs_scanner', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Enable or disable the filesystem scanner for modified files.
        if ($scan_modfiles = SucuriScanRequest::post(':scan_modfiles', '(en|dis)able')) {
            $action_d = $scan_modfiles . 'd';
            $message = 'File system scanner for modified files was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':scan_modfiles', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Enable or disable the filesystem scanner for file integrity.
        if ($scan_checksums = SucuriScanRequest::post(':scan_checksums', '(en|dis)able')) {
            $action_d = $scan_checksums . 'd';
            $message = 'File system scanner for file integrity was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':scan_checksums', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Enable or disable the filesystem scanner for error logs.
        if ($ignore_scanning = SucuriScanRequest::post(':ignore_scanning', '(en|dis)able')) {
            $action_d = $ignore_scanning . 'd';
            $message = 'File system scanner rules to ignore directories was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':ignore_scanning', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Enable or disable the filesystem scanner for error logs.
        if ($scan_errorlogs = SucuriScanRequest::post(':scan_errorlogs', '(en|dis)able')) {
            $action_d = $scan_errorlogs . 'd';
            $message = 'File system scanner for error logs was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':scan_errorlogs', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Enable or disable the error logs parsing.
        if ($parse_errorlogs = SucuriScanRequest::post(':parse_errorlogs', '(en|dis)able')) {
            $action_d = $parse_errorlogs . 'd';
            $message = 'Analysis of main error log file was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':parse_errorlogs', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Enable or disable the SiteCheck scanner and the malware scan page.
        if ($sitecheck_scanner = SucuriScanRequest::post(':sitecheck_scanner', '(en|dis)able')) {
            $action_d = $sitecheck_scanner . 'd';
            $message = 'SiteCheck malware and blacklist scanner was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':sitecheck_scanner', $action_d);
            SucuriScanEvent::report_auto_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Modify the schedule of the filesystem scanner.
        if ($frequency = SucuriScanRequest::post(':scan_frequency')) {
            if (array_key_exists($frequency, $sucuriscan_schedule_allowed)) {
                SucuriScanOption::update_option(':scan_frequency', $frequency);
                wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
                if ($frequency != '_oneoff') {
                    wp_schedule_event(time() + 10, $frequency, 'sucuriscan_scheduled_scan');
                }
                $frequency_title = strtolower($sucuriscan_schedule_allowed[$frequency]);
                $message = 'File system scanning frequency set to <code>' . $frequency_title . '</code>';
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            }
        }
        // Set the method (aka. interface) that will be used to scan the site.
        if ($interface = SucuriScanRequest::post(':scan_interface')) {
            $allowed_values = array_keys($sucuriscan_interface_allowed);
            if (in_array($interface, $allowed_values)) {
                $message = 'File system scanning interface set to <code>' . $interface . '</code>';
                SucuriScanOption::update_option(':scan_interface', $interface);
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            }
        }
        // Update the limit of error log lines to parse.
        if ($errorlogs_limit = SucuriScanRequest::post(':errorlogs_limit', '[0-9]+')) {
            if ($errorlogs_limit > 1000) {
                SucuriScanInterface::error('Analyze more than 1,000 lines will take too much time.');
            } else {
                SucuriScanOption::update_option(':errorlogs_limit', $errorlogs_limit);
                SucuriScanInterface::info('Analyze last <code>' . $errorlogs_limit . '</code> entries encountered in the error logs.');
                if ($errorlogs_limit == 0) {
                    SucuriScanOption::update_option(':parse_errorlogs', 'disabled');
                }
            }
        }
        // Reset the plugin security logs.
        $allowed_log_files = '(integrity|lastlogins|failedlogins|sitecheck)';
        if ($reset_logfile = SucuriScanRequest::post(':reset_logfile', $allowed_log_files)) {
            $files_to_delete = array('sucuri-' . $reset_logfile . '.php', 'sucuri-old' . $reset_logfile . '.php');
            foreach ($files_to_delete as $log_filename) {
                $log_filepath = SucuriScan::datastore_folder_path($log_filename);
                if (@unlink($log_filepath)) {
                    $log_filename_simple = str_replace('.php', '', $log_filename);
                    $message = 'Deleted security log <code>' . $log_filename_simple . '</code>';
                    SucuriScanEvent::report_debug_event($message);
                    SucuriScanInterface::info($message);
                }
            }
        }
        // Update the value for the maximum emails per hour.
        if ($per_hour = SucuriScanRequest::post(':emails_per_hour')) {
            if (array_key_exists($per_hour, $sucuriscan_emails_per_hour)) {
                $per_hour_label = strtolower($sucuriscan_emails_per_hour[$per_hour]);
                $message = 'Maximum email alerts per hour set to <code>' . $per_hour_label . '</code>';
                SucuriScanOption::update_option(':emails_per_hour', $per_hour);
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            } else {
                SucuriScanInterface::error('Invalid value for the maximum emails per hour.');
            }
        }
        // Update the email where the event notifications will be sent.
        if ($new_email = SucuriScanRequest::post(':notify_to')) {
            $valid_email = SucuriScan::get_valid_email($new_email);
            if ($valid_email) {
                $message = 'Sucuri alerts will be sent to this email: <code>' . $valid_email . '</code>';
                SucuriScanOption::update_option(':notify_to', $valid_email);
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            } else {
                SucuriScanInterface::error('Email format not supported.');
            }
        }
        // Update the maximum failed logins per hour before consider it a brute-force attack.
        if ($failed_logins = SucuriScanRequest::post(':maximum_failed_logins')) {
            if (array_key_exists($failed_logins, $sucuriscan_maximum_failed_logins)) {
                $message = 'Consider brute-force attack after <code>' . $failed_logins . '</code> failed logins per hour';
                SucuriScanOption::update_option(':maximum_failed_logins', $failed_logins);
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            } else {
                SucuriScanInterface::error('Invalid value for the maximum failed logins per hour before consider it a brute-force attack.');
            }
        }
        // Enable or disable the audit logs report.
        if ($audit_report = SucuriScanRequest::post(':audit_report', '(en|dis)able')) {
            $action_d = $audit_report . 'd';
            $message = 'Audit logs report was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':audit_report', $action_d);
            SucuriScanEvent::report_info_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Update the limit for audit logs report.
        if ($logs4report = SucuriScanRequest::post(':logs4report', '[0-9]{1,4}')) {
            $message = 'Limit for audit logs report set to <code>' . $logs4report . '</code>';
            SucuriScanOption::update_option(':logs4report', $logs4report);
            SucuriScanEvent::report_info_event($message);
            SucuriScanEvent::notify_event('plugin_change', $message);
            SucuriScanInterface::info($message);
        }
        // Update the notification settings.
        if (SucuriScanRequest::post(':save_notification_settings') !== false) {
            $options_updated_counter = 0;
            if (SucuriScanRequest::post(':notify_scan_checksums', '1')) {
                $_POST['sucuriscan_prettify_mails'] = '1';
            }
            foreach ($sucuriscan_notify_options as $alert_type => $alert_label) {
                $option_value = SucuriScanRequest::post($alert_type, '(1|0)');
                if ($option_value !== false) {
                    $current_value = SucuriScanOption::get_option($alert_type);
                    $option_value = $option_value == '1' ? 'enabled' : 'disabled';
                    // Check that the option value was actually changed.
                    if ($current_value !== $option_value) {
                        SucuriScanOption::update_option($alert_type, $option_value);
                        $options_updated_counter += 1;
                    }
                }
            }
            if ($options_updated_counter > 0) {
                $message = 'Alert settings were changed <code>' . $options_updated_counter . ' options</code>';
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            }
        }
        // Update the subject format for the email alerts.
        if ($email_subject = SucuriScanRequest::post(':email_subject')) {
            $new_email_subject = false;
            $current_value = SucuriScanOption::get_option(':email_subject');
            /**
             * Validate the format of the email subject format.
             *
             * If the user chooses the option to build the subject of the email alerts
             * manually we will need to validate the characters. Otherwise we will need to
             * check if the pseudo-tags selected by the user are allowed and supported.
             */
            if ($email_subject == 'custom') {
                $format_pattern = '/^[0-9a-zA-Z:,\\s]+$/';
                $custom_email_subject = SucuriScanRequest::post(':custom_email_subject');
                if ($custom_email_subject !== false && !empty($custom_email_subject) && preg_match($format_pattern, $custom_email_subject)) {
                    $new_email_subject = trim($custom_email_subject);
                } else {
                    SucuriScanInterface::error('Invalid characters found in the email alert subject format.');
                }
            } elseif (is_array($sucuriscan_email_subjects) && in_array($email_subject, $sucuriscan_email_subjects)) {
                $new_email_subject = trim($email_subject);
            }
            // Proceed with the operation saving the new subject.
            if ($new_email_subject !== false && $current_value !== $new_email_subject) {
                $message = 'Alert subject format set to <code>' . $new_email_subject . '</code>';
                SucuriScanOption::update_option(':email_subject', $new_email_subject);
                SucuriScanEvent::report_info_event($message);
                SucuriScanEvent::notify_event('plugin_change', $message);
                SucuriScanInterface::info($message);
            }
        }
        // Ignore a new event for email notifications.
        if ($action = SucuriScanRequest::post(':ignorerule_action', '(add|remove)')) {
            $ignore_rule = SucuriScanRequest::post(':ignorerule');
            if ($action == 'add') {
                if (SucuriScanOption::add_ignored_event($ignore_rule)) {
                    SucuriScanInterface::info('Post-type ignored successfully.');
                    SucuriScanEvent::report_warning_event('Changes in <code>' . $ignore_rule . '</code> post-type will be ignored');
                } else {
                    SucuriScanInterface::error('The post-type is invalid or it may be already ignored.');
                }
            } elseif ($action == 'remove') {
                SucuriScanOption::remove_ignored_event($ignore_rule);
                SucuriScanInterface::info('Post-type removed from the list successfully.');
                SucuriScanEvent::report_notice_event('Changes in <code>' . $ignore_rule . '</code> post-type will not be ignored');
            }
        }
        // Ignore a new directory path for the file system scans.
        if ($action = SucuriScanRequest::post(':ignorescanning_action', '(ignore|unignore)')) {
            $ignore_directories = SucuriScanRequest::post(':ignorescanning_dirs', '_array');
            $ignore_file = SucuriScanRequest::post(':ignorescanning_file');
            if ($action == 'ignore') {
                // Target a single file path to be ignored.
                if ($ignore_file !== false) {
                    $ignore_directories = array($ignore_file);
                }
                // Target a list of directories to be ignored.
                if (!empty($ignore_directories)) {
                    $were_ignored = array();
                    foreach ($ignore_directories as $resource_path) {
                        if (file_exists($resource_path) && SucuriScanFSScanner::ignore_directory($resource_path)) {
                            $were_ignored[] = $resource_path;
                        }
                    }
                    if (!empty($were_ignored)) {
                        SucuriScanInterface::info('Items selected will be ignored in future scans.');
                        SucuriScanEvent::report_warning_event(sprintf('Resources will not be scanned: (multiple entries): %s', @implode(',', $ignore_directories)));
                    }
                }
            } elseif ($action == 'unignore') {
                foreach ($ignore_directories as $directory_path) {
                    SucuriScanFSScanner::unignore_directory($directory_path);
                }
                SucuriScanInterface::info('Items selected will not be ignored anymore.');
                SucuriScanEvent::report_notice_event(sprintf('Resources will be scanned: (multiple entries): %s', @implode(',', $ignore_directories)));
            }
        }
        // Trust and IP address to ignore notifications for a subnet.
        if ($trust_ip = SucuriScanRequest::post(':trust_ip')) {
            if (SucuriScan::is_valid_ip($trust_ip) || SucuriScan::is_valid_cidr($trust_ip)) {
                $cache = new SucuriScanCache('trustip');
                $ip_info = SucuriScan::get_ip_info($trust_ip);
                $ip_info['added_at'] = SucuriScan::local_time();
                $cache_key = md5($ip_info['remote_addr']);
                if ($cache->exists($cache_key)) {
                    SucuriScanInterface::error('The IP address specified was already trusted.');
                } elseif ($cache->add($cache_key, $ip_info)) {
                    $message = 'Changes from <code>' . $trust_ip . '</code> will be ignored';
                    SucuriScanEvent::report_warning_event($message);
                    SucuriScanInterface::info($message);
                } else {
                    SucuriScanInterface::error('The new entry was not saved in the datastore file.');
                }
            }
        }
        // Trust and IP address to ignore notifications for a subnet.
        if ($del_trust_ip = SucuriScanRequest::post(':del_trust_ip', '_array')) {
            $cache = new SucuriScanCache('trustip');
            foreach ($del_trust_ip as $cache_key) {
                $cache->delete($cache_key);
            }
            SucuriScanInterface::info('The IP addresses selected were deleted successfully.');
        }
        // Update the settings for the heartbeat API.
        if ($heartbeat_status = SucuriScanRequest::post(':heartbeat_status')) {
            $statuses_allowed = SucuriScanHeartbeat::statuses_allowed();
            if (array_key_exists($heartbeat_status, $statuses_allowed)) {
                $message = 'Heartbeat status set to <code>' . $heartbeat_status . '</code>';
                SucuriScanOption::update_option(':heartbeat', $heartbeat_status);
                SucuriScanEvent::report_info_event($message);
                SucuriScanInterface::info($message);
            } else {
                SucuriScanInterface::error('Heartbeat status not allowed.');
            }
        }
        // Update the value of the heartbeat pulse.
        if ($heartbeat_pulse = SucuriScanRequest::post(':heartbeat_pulse')) {
            $pulses_allowed = SucuriScanHeartbeat::pulses_allowed();
            if (array_key_exists($heartbeat_pulse, $pulses_allowed)) {
                $message = 'Heartbeat pulse set to <code>' . $heartbeat_pulse . '</code> seconds.';
                SucuriScanOption::update_option(':heartbeat_pulse', $heartbeat_pulse);
                SucuriScanEvent::report_info_event($message);
                SucuriScanInterface::info($message);
            } else {
                SucuriScanInterface::error('Heartbeat pulse not allowed.');
            }
        }
        // Update the value of the heartbeat interval.
        if ($heartbeat_interval = SucuriScanRequest::post(':heartbeat_interval')) {
            $intervals_allowed = SucuriScanHeartbeat::intervals_allowed();
            if (array_key_exists($heartbeat_interval, $intervals_allowed)) {
                $message = 'Heartbeat interval set to <code>' . $heartbeat_interval . '</code>';
                SucuriScanOption::update_option(':heartbeat_interval', $heartbeat_interval);
                SucuriScanEvent::report_info_event($message);
                SucuriScanInterface::info($message);
            } else {
                SucuriScanInterface::error('Heartbeat interval not allowed.');
            }
        }
        // Enable or disable the auto-start execution of heartbeat.
        if ($heartbeat_autostart = SucuriScanRequest::post(':heartbeat_autostart', '(en|dis)able')) {
            $action_d = $heartbeat_autostart . 'd';
            $message = 'Heartbeat auto-start was <code>' . $action_d . '</code>';
            SucuriScanOption::update_option(':heartbeat_autostart', $action_d);
            SucuriScanEvent::report_info_event($message);
            SucuriScanInterface::info($message);
        }
        // Debug ability of the plugin to send email alerts correctly.
        if (SucuriScanRequest::post(':debug_email')) {
            $recipient = SucuriScanOption::get_option(':notify_to');
            $mail_sent = SucuriScanMail::send_mail($recipient, 'Test email alert', sprintf('Test email alert sent at %s', date('r')), array('Force' => true));
            SucuriScanInterface::info('Test email alert sent, check your inbox.');
        }
    }
}