Skip to content

Commit

Permalink
MDL-66222 antivirus: Added antivirus failure reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Nguyen authored and Peterburnett committed Aug 21, 2020
1 parent a0fc902 commit adbe92c
Show file tree
Hide file tree
Showing 22 changed files with 1,326 additions and 8 deletions.
23 changes: 23 additions & 0 deletions admin/settings/plugins.php
Expand Up @@ -167,6 +167,29 @@
$ADMIN->add('modules', new admin_category('antivirussettings', new lang_string('antiviruses', 'antivirus')));
$temp = new admin_settingpage('manageantiviruses', new lang_string('antivirussettings', 'antivirus'));
$temp->add(new admin_setting_manageantiviruses());

// Common settings.
$temp->add(new admin_setting_heading('antiviruscommonsettings', new lang_string('antiviruscommonsettings', 'antivirus'), ''));

// Alert email.
$temp->add(new admin_setting_configtext('antivirus/notifyemail',
new lang_string('notifyemail', 'antivirus'),
new lang_string('notifyemail_help', 'antivirus'), '', PARAM_EMAIL)
);

// Enable quarantine.
$temp->add(new admin_setting_configcheckbox('antivirus/enablequarantine',
new lang_string('enablequarantine', 'antivirus'),
new lang_string('enablequarantine_help', 'antivirus',
\core\antivirus\quarantine::DEFAULT_QUARANTINE_FOLDER), 0));

// Quarantine time.
$temp->add(new admin_setting_configduration('antivirus/quarantinetime',
new lang_string('quarantinetime', 'antivirus'),
new lang_string('quarantinetime_desc', 'antivirus'),
\core\antivirus\quarantine::DEFAULT_QUARANTINE_TIME)
);

$ADMIN->add('antivirussettings', $temp);
$plugins = core_plugin_manager::instance()->get_plugins_of_type('antivirus');
core_collator::asort_objects_by_property($plugins, 'displayname');
Expand Down
29 changes: 29 additions & 0 deletions lang/en/antivirus.php
Expand Up @@ -24,9 +24,38 @@

$string['actantivirushdr'] = 'Available antivirus plugins';
$string['antiviruses'] = 'Antivirus plugins';
$string['antiviruscommonsettings'] = 'Common antivirus settings';
$string['antivirussettings'] = 'Manage antivirus plugins';
$string['configantivirusplugins'] = 'Please choose the antivirus plugins you wish to use and arrange them in order of being applied.';
$string['confirmdelete'] = 'Do you really want to delete this file';
$string['confirmdeleteall'] = 'Do you really want to delete all files';
$string['datastream'] = 'Data';
$string['datainfecteddesc'] = 'There is a virus infected data';
$string['datainfectedname'] = 'Data infected';
$string['emailsubject'] = '{$a} :: Antivirus notification';
$string['enablequarantine'] = 'Enable quarantine';
$string['enablequarantine_help'] = 'When quarantine is enabled, any files which are detected as viruses will be kept in a quarantine folder for later inspection ([dataroot]/{$a}).
The upload into Moodle will still fail.
If you have any file system level virus scanning in place, the quarantine folder should be excluded from the antivirus check to avoid detecting the quarantined files.';
$string['fileinfectedname'] = 'File infected';
$string['incidencedetails'] = 'Infected file detected:
Report: {$a->report}
File name: {$a->filename}
File size: {$a->filesize}
File content hash: {$a->contenthash}
File content type: {$a->contenttype}
Uploaded by: {$a->author}
IP: {$a->ipaddress}
REFERER: {$a->referer}
Date: {$a->date}
{$a->notice}';
$string['notifyemail'] = 'Antivirus alert email';
$string['notifyemail_help'] = 'If set, then only the specified email will be notified when a virus is detected.
If blank, then all site admins will be notified by email when a virus is detected.';
$string['privacy:metadata'] = 'The Antivirus system does not store any personal data.';
$string['quarantinedfiles'] = 'Antivirus quarantined files';
$string['quarantinetime'] = 'Maximum quarantine time';
$string['quarantinetime_desc'] = 'Quarantined files older than specified period will be removed.';
$string['taskcleanup'] = 'Clean up quarantined files.';
$string['unknown'] = 'Unknown';
$string['virusfound'] = '{$a->item} has been scanned by a virus checker and found to be infected!';
5 changes: 5 additions & 0 deletions lib/antivirus/clamav/classes/scanner.php
Expand Up @@ -228,6 +228,9 @@ public function scan_file_execute_commandline($file) {
$notice .= "\n\n". implode("\n", $output);
$this->set_scanning_notice($notice);
return self::SCAN_RESULT_ERROR;
} else {
$notice = "\n\n". implode("\n", $output);
$this->set_scanning_notice($notice);
}

return (int)$return;
Expand Down Expand Up @@ -384,6 +387,8 @@ private function parse_socket_response($output) {
$parts = explode(' ', $message);
$status = array_pop($parts);
if ($status === 'FOUND') {
$notice = "\n\n" . $output;
$this->set_scanning_notice($notice);
return self::SCAN_RESULT_FOUND;
} else {
$notice = get_string('clamfailed', 'antivirus_clamav', $this->get_clam_error_code(2));
Expand Down
40 changes: 38 additions & 2 deletions lib/classes/antivirus/manager.php
Expand Up @@ -67,11 +67,28 @@ private static function get_enabled() {
* @return void
*/
public static function scan_file($file, $filename, $deleteinfected) {
global $USER;
$antiviruses = self::get_enabled();
foreach ($antiviruses as $antivirus) {
$result = $antivirus->scan_file($file, $filename);
if ($result === $antivirus::SCAN_RESULT_FOUND) {
// Infection found.
// Infection found, send notification.
$notice = $antivirus->get_scanning_notice();
$incidencedetails = $antivirus->get_incidence_details($file, $filename, $notice);
$antivirus->message_admins($notice, FORMAT_MOODLE, 'infected');

// Move to quarantine folder.
$zipfile = \core\antivirus\quarantine::quarantine_file($file, $filename, $incidencedetails, $notice);

// Log file infected event.
$params = array(
'context' => \context_system::instance(),
'relateduserid' => $USER->id,
'other' => ['filename' => $filename, 'zipfile' => $zipfile, 'incidencedetails' => $incidencedetails],
);
$event = \core\event\antivirus_file_infected::create($params);
$event->trigger();

if ($deleteinfected) {
unlink($file);
}
Expand All @@ -83,15 +100,34 @@ public static function scan_file($file, $filename, $deleteinfected) {
/**
* Scan data steam using all enabled antiviruses, throws exception in case of infected data.
*
* @param string $data The varaible containing the data to scan.
* @param string $data The variable containing the data to scan.
* @throws \core\antivirus\scanner_exception If data is infected.
* @return void
*/
public static function scan_data($data) {
global $USER;
$antiviruses = self::get_enabled();
foreach ($antiviruses as $antivirus) {
$result = $antivirus->scan_data($data);
if ($result === $antivirus::SCAN_RESULT_FOUND) {
// Infection found, send notification.
$filename = get_string('datastream', 'antivirus');
$notice = $antivirus->get_scanning_notice();
$incidencedetails = $antivirus->get_incidence_details('', $filename, $notice);
$antivirus->message_admins($notice, FORMAT_MOODLE, 'infected');

// Copy data to quarantine folder.
$zipfile = \core\antivirus\quarantine::quarantine_data($data, $filename, $incidencedetails, $notice);

// Log file infected event.
$params = array(
'context' => \context_system::instance(),
'relateduserid' => $USER->id,
'other' => ['filename' => $filename, 'zipfile' => $zipfile, 'incidencedetails' => $incidencedetails],
);
$event = \core\event\antivirus_data_infected::create($params);
$event->trigger();

throw new \core\antivirus\scanner_exception('virusfound', '', array('item' => get_string('datastream', 'antivirus')));
}
}
Expand Down

0 comments on commit adbe92c

Please sign in to comment.