/** * 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.'); } } }