MDL-19380 reimplement antivir scanning in repositories

This commit is contained in:
Petr Skoda 2011-08-07 11:26:03 +02:00
parent 4f3632441a
commit 23bfe0a448
4 changed files with 85 additions and 12 deletions

View File

@ -697,7 +697,8 @@ function clam_message_admins($notice) {
$admins = get_admins();
foreach ($admins as $admin) {
$eventdata = new stdClass();
$eventdata->modulename = 'moodle';
$eventdata->component = 'moodle';
$eventdata->name = 'errors';
$eventdata->userfrom = get_admin();
$eventdata->userto = $admin;
$eventdata->subject = $subject;

View File

@ -946,6 +946,76 @@ abstract class repository {
return call_user_func_array(array('repository_' . $plugin, $function), $args);
}
/**
* Scan file, throws exception in case of infected file.
*
* Please note that the scanning engine must be able to access the file,
* permissions of the file are not modified here!
*
* @static
* @param string $thefile
* @param string $filename name of the file
* @param bool $deleteinfected
* @return void
*/
public static function antivir_scan_file($thefile, $filename, $deleteinfected) {
global $CFG;
if (!is_readable($thefile)) {
// this should not happen
return;
}
if (empty($CFG->runclamonupload) or empty($CFG->pathtoclam)) {
// clam not enabled
return;
}
$CFG->pathtoclam = trim($CFG->pathtoclam);
if (!file_exists($CFG->pathtoclam) or !is_executable($CFG->pathtoclam)) {
// misconfigured clam - use the old notification for now
require("$CFG->libdir/uploadlib.php");
$notice = get_string('clamlost', 'moodle', $CFG->pathtoclam);
clam_message_admins($notice);
return;
}
// do NOT mess with permissions here, the calling party is responsible for making
// sure the scanner engine can access the files!
// execute test
$cmd = escapeshellcmd($CFG->pathtoclam).' --stdout '.escapeshellarg($thefile);
exec($cmd, $output, $return);
if ($return == 0) {
// perfect, no problem found
return;
} else if ($return == 1) {
// infection found
if ($deleteinfected) {
unlink($thefile);
}
throw new moodle_exception('virusfounduser', 'moodle', '', array('filename'=>$filename));
} else {
//unknown problem
require("$CFG->libdir/uploadlib.php");
$notice = get_string('clamfailed', 'moodle', get_clam_error_code($return));
$notice .= "\n\n". implode("\n", $output);
clam_message_admins($notice);
if ($CFG->clamfailureonupload === 'actlikevirus') {
if ($deleteinfected) {
unlink($thefile);
}
throw new moodle_exception('virusfounduser', 'moodle', '', array('filename'=>$filename));
} else {
return;
}
}
}
/**
* Move file from download folder to file pool using FILE API
* @global object $DB
@ -962,6 +1032,10 @@ abstract class repository {
*/
public static function move_to_filepool($thefile, $record) {
global $DB, $CFG, $USER, $OUTPUT;
// scan for viruses if possible, throws exception if problem found
self::antivir_scan_file($thefile, $record->filename, empty($CFG->repository_no_delete)); //TODO: MDL-28637 this repository_no_delete is a bloody hack!
if ($record->filepath !== '/') {
$record->filepath = trim($record->filepath, '/');
$record->filepath = '/'.$record->filepath.'/';

View File

@ -249,17 +249,8 @@ switch ($action) {
}
break;
case 'upload':
// handle exception here instead moodle default exception handler
// see MDL-23407
try {
// TODO: add file scanning MDL-19380 into each plugin
$result = $repo->upload($saveas_filename, $maxbytes);
echo json_encode($result);
} catch (Exception $e) {
$err->error = $e->getMessage();
echo json_encode($err);
die;
}
$result = $repo->upload($saveas_filename, $maxbytes);
echo json_encode($result);
break;
case 'overwrite':

View File

@ -102,6 +102,13 @@ class repository_upload extends repository {
}
}
// scan the files, throws exception and deletes if virus found
// this is tricky because clamdscan daemon might not be able to access the files
$permissions = fileperms($_FILES[$elname]['tmp_name']);
@chmod($_FILES[$elname]['tmp_name'], $CFG->filepermissions);
self::antivir_scan_file($_FILES[$elname]['tmp_name'], $_FILES[$elname]['name'], true);
@chmod($_FILES[$elname]['tmp_name'], $permissions);
if (empty($saveas_filename)) {
$record->filename = clean_param($_FILES[$elname]['name'], PARAM_FILE);
} else {