/** * 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 */ 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; } $clamparam = ' --stdout '; // If we are dealing with clamdscan, clamd is likely run as a different user // that might not have permissions to access your file. // To make clamdscan work, we use --fdpass parameter that passes the file // descriptor permissions to clamd, which allows it to scan given file // irrespective of directory and file permissions. if (basename($CFG->pathtoclam) == 'clamdscan') { $clamparam .= '--fdpass '; } // execute test $cmd = escapeshellcmd($CFG->pathtoclam) . $clamparam . 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; } } } }
/** * If $CFG->runclamonupload is set, we scan a given file. (called from {@link preprocess_files()}) * * This function will add on a uploadlog index in $file. * * @global object * @global object * @param mixed $file The file to scan from $files. or an absolute path to a file. * @param course $course {@link $COURSE} * @return int 1 if good, 0 if something goes wrong (opposite from actual error code from clam) */ function clam_scan_moodle_file(&$file, $course) { global $CFG, $USER; if (is_array($file) && is_uploaded_file($file['tmp_name'])) { // it's from $_FILES $appendlog = true; $fullpath = $file['tmp_name']; } else { if (file_exists($file)) { // it's a path to somewhere on the filesystem! $fullpath = $file; } else { return false; // erm, what is this supposed to be then, huh? } } $CFG->pathtoclam = trim($CFG->pathtoclam); if (!$CFG->pathtoclam || !file_exists($CFG->pathtoclam) || !is_executable($CFG->pathtoclam)) { $newreturn = 1; $notice = get_string('clamlost', 'moodle', $CFG->pathtoclam); if ($CFG->clamfailureonupload == 'actlikevirus') { $notice .= "\n" . get_string('clamlostandactinglikevirus'); $notice .= "\n" . clam_handle_infected_file($fullpath); $newreturn = false; } clam_message_admins($notice); if ($appendlog) { $file['uploadlog'] .= "\n" . get_string('clambroken'); $file['clam'] = 1; } return $newreturn; // return 1 if we're allowing clam failures } $cmd = $CFG->pathtoclam . ' ' . $fullpath . " 2>&1"; // before we do anything we need to change perms so that clamscan can read the file (clamdscan won't work otherwise) chmod($fullpath, $CFG->directorypermissions); exec($cmd, $output, $return); switch ($return) { case 0: // glee! we're ok. return 1; // translate clam return code into reasonable return code consistent with everything else. // translate clam return code into reasonable return code consistent with everything else. case 1: // bad wicked evil, we have a virus. $info = new stdClass(); if (!empty($course)) { $info->course = format_string($course->fullname, true, array('context' => context_course::instance($course->id))); } else { $info->course = 'No course'; } $info->user = fullname($USER); $notice = get_string('virusfound', 'moodle', $info); $notice .= "\n\n" . implode("\n", $output); $notice .= "\n\n" . clam_handle_infected_file($fullpath); clam_message_admins($notice); if ($appendlog) { $info->filename = $file['originalname']; $file['uploadlog'] .= "\n" . get_string('virusfounduser', 'moodle', $info); $file['virus'] = 1; } return false; // in this case, 0 means bad. // in this case, 0 means bad. default: // error - clam failed to run or something went wrong $notice .= get_string('clamfailed', 'moodle', get_clam_error_code($return)); $notice .= "\n\n" . implode("\n", $output); $newreturn = true; if ($CFG->clamfailureonupload == 'actlikevirus') { $notice .= "\n" . clam_handle_infected_file($fullpath); $newreturn = false; } clam_message_admins($notice); if ($appendlog) { $file['uploadlog'] .= "\n" . get_string('clambroken'); $file['clam'] = 1; } return $newreturn; // return 1 if we're allowing failures. } }
/** * 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 */ 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; } } } }