Move code into subdirectory
This commit is contained in:
Родитель
9596fa1161
Коммит
b89abd5cae
|
@ -0,0 +1,50 @@
|
|||
#Owncloud Antivirus App
|
||||
|
||||
files_antivirus is an antivirus app for [Owncloud](https://github.com/owncloud) based on [ClamAV](http://www.clamav.net).
|
||||
|
||||
v0.2
|
||||
|
||||
##Details
|
||||
|
||||
The idea is to check for virus at upload-time, notifying the user (on screen and/or email) and
|
||||
remove the file if it's infected.
|
||||
|
||||
##Status
|
||||
|
||||
The App is not complete yet...
|
||||
* It can be configured to work with the executable or the daemon mode of ClamAV
|
||||
* In daemon mode, it sends files to a remote/local server using INSTREAM command
|
||||
* When the user uploads a file, it's checked
|
||||
* If an uploaded file is infected, it's deleted and a notification is shown to the user on screen and an email is sent with details.
|
||||
* Tested in Linux only
|
||||
|
||||
##In progress
|
||||
|
||||
* Test uploading from clients
|
||||
|
||||
##ToDo
|
||||
|
||||
* Background Job to scan all files
|
||||
* File size limit
|
||||
* Configurations Tuneups
|
||||
* Other OS Testing
|
||||
* Look for ideas :P
|
||||
|
||||
## Requirements
|
||||
|
||||
* Owncloud 4
|
||||
* ClamAV (Binaries or a server running ClamAV in daemon mode)
|
||||
|
||||
## Install
|
||||
|
||||
* Download App tarball or clone repo
|
||||
* [master](https://github.com/valarauco/files_antivirus/tarball/master)
|
||||
* [v0.2](https://github.com/valarauco/files_antivirus/archive/v0.2.tar.gz)
|
||||
* `git clone git://github.com/valarauco/files_antivirus.git`
|
||||
* Unpack the tarball inside the apps directory of Owncloud
|
||||
* Activate the App
|
||||
* Go to Admin Panel and configure the App
|
||||
|
||||
|
||||
Author:
|
||||
[Manuel Delgado López](https://github.com/valarauco/) :: manuel.delgado at ucr.ac.cr
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - files_antivirus
|
||||
*
|
||||
* @author Manuel Deglado
|
||||
* @copyright 2012 Manuel Deglado manuel.delgado@ucr.ac.cr
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
OC::$CLASSPATH['OC_Files_Antivirus'] = OC_App::getAppPath('files_antivirus').'/lib/clamav.php';
|
||||
|
||||
OC_APP::registerAdmin('files_antivirus', 'settings');
|
||||
OC_Hook::connect('OC_Filesystem', 'post_write', 'OC_Files_Antivirus', 'av_scan');
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<info>
|
||||
<id>files_antivirus</id>
|
||||
<name>Antivirus App for files</name>
|
||||
<description>Verify files for virus using ClamAV</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Manuel Delgado</author>
|
||||
<require>4</require>
|
||||
<shipped>false</shipped>
|
||||
<types>
|
||||
<filesystem/>
|
||||
</types>
|
||||
</info>
|
|
@ -0,0 +1 @@
|
|||
0.2
|
|
@ -0,0 +1,20 @@
|
|||
function av_mode_show_options(str){
|
||||
if ( str == 'daemon'){
|
||||
$('p.av_host').show('slow');
|
||||
$('p.av_port').show('slow');
|
||||
$('p.av_chunk_size').show('slow');
|
||||
$('p.av_path').hide('slow');
|
||||
} else if (str == 'executable'){
|
||||
$('p.av_host').hide('slow');
|
||||
$('p.av_port').hide('slow');
|
||||
$('p.av_chunk_size').hide('slow');
|
||||
$('p.av_path').show('slow');
|
||||
}
|
||||
}
|
||||
$(document).ready(function() {
|
||||
$("#av_mode").change(function () {
|
||||
var str = $("#av_mode").val();
|
||||
av_mode_show_options(str);
|
||||
});
|
||||
$("#av_mode").change();
|
||||
});
|
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - files_antivirus
|
||||
*
|
||||
* @author Manuel Deglado
|
||||
* @copyright 2012 Manuel Deglado manuel.delgado@ucr.ac.cr
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// The file was not checked (e.g. because the AV daemon wasn't running).
|
||||
define('CLAMAV_SCANRESULT_UNCHECKED', -1);
|
||||
// The file was checked and found to be clean.
|
||||
define('CLAMAV_SCANRESULT_CLEAN', 0);
|
||||
// The file was checked and found to be infected.
|
||||
define('CLAMAV_SCANRESULT_INFECTED', 1);
|
||||
|
||||
class OC_Files_Antivirus {
|
||||
|
||||
public static function av_scan($path) {
|
||||
$path=$path[\OC_Filesystem::signal_param_path];
|
||||
if ($path != '') {
|
||||
$files_view = \OCP\Files::getStorage("files");
|
||||
if ($files_view->file_exists($path)) {
|
||||
$root=OC_User::getHome(OC_User::getUser()).'/files';
|
||||
$file = $root.$path;
|
||||
$result = self::clamav_scan($file);
|
||||
switch($result) {
|
||||
case CLAMAV_SCANRESULT_UNCHECKED:
|
||||
//TODO: Show warning to the user: The file can not be checked
|
||||
break;
|
||||
case CLAMAV_SCANRESULT_INFECTED:
|
||||
//remove file
|
||||
$files_view->unlink($path);
|
||||
OCP\JSON::error(array("data" => array( "message" => "Virus detected! Can't upload the file." )));
|
||||
$email = OC_Preferences::getValue(OC_User::getUser(), 'settings', 'email', '');
|
||||
\OCP\Util::writeLog('files_antivirus', 'Email: '.$email, \OCP\Util::DEBUG);
|
||||
if (!empty($email) ) {
|
||||
$tmpl = new OC_Template('files_antivirus', 'notification');
|
||||
$tmpl->assign('file', $path, false);
|
||||
$tmpl->assign('host', OCP\Util::getServerHost(), false);
|
||||
$tmpl->assign('user', OC_User::getUser(), false);
|
||||
$msg = $tmpl->fetchPage();
|
||||
$from = 'security-noreply@' . OCP\Util::getServerHost();
|
||||
\OC_MAIL::send($email, OC_User::getUser(), 'Malware detected', $msg, $from, 'ownCloud', 1);
|
||||
}
|
||||
exit();
|
||||
break;
|
||||
|
||||
case CLAMAV_SCANRESULT_CLEAN:
|
||||
//do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function clamav_scan($filepath) {
|
||||
$av_mode = \OCP\Config::getAppValue('files_antivirus', 'av_mode', 'executable');
|
||||
switch($av_mode) {
|
||||
case 'daemon':
|
||||
return self::_clamav_scan_via_daemon($filepath);
|
||||
case 'executable':
|
||||
return self::_clamav_scan_via_exec($filepath);
|
||||
}
|
||||
}
|
||||
|
||||
private static function _clamav_scan_via_daemon($filepath) {
|
||||
$av_host = \OCP\Config::getAppValue('files_antivirus', 'av_host', '');
|
||||
$av_port = \OCP\Config::getAppValue('files_antivirus', 'av_port', '');
|
||||
$av_chunk_size = \OCP\Config::getAppValue('files_antivirus', 'av_chunk_size', '1024');
|
||||
|
||||
// try to open a socket to clamav
|
||||
$shandler = ($av_host && $av_port) ? @fsockopen($av_host, $av_port) : false;
|
||||
if(!$shandler) {
|
||||
\OCP\Util::writeLog('files_antivirus', 'The clamav module is not configured for daemon mode.', \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$fhandler = fopen($filepath, "r");
|
||||
if(!$fhandler) {
|
||||
\OCP\Util::writeLog('files_antivirus', 'File could not be open.', \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// request scan from the daemon
|
||||
fwrite($shandler, "nINSTREAM\n");
|
||||
while (!feof($fhandler)) {
|
||||
$chunk = fread($fhandler, $av_chunk_size);
|
||||
$chunk_len = pack('N', strlen($chunk));
|
||||
fwrite($shandler, $chunk_len.$chunk);
|
||||
}
|
||||
fwrite($shandler, pack('N', 0));
|
||||
$response = fgets($shandler);
|
||||
\OCP\Util::writeLog('files_antivirus', 'Response :: '.$response, \OCP\Util::WARN);
|
||||
fclose($shandler);
|
||||
fclose($fhandler);
|
||||
|
||||
// clamd returns a string response in the format:
|
||||
// filename: OK
|
||||
// filename: <name of virus> FOUND
|
||||
// filename: <error string> ERROR
|
||||
|
||||
if (preg_match('/.*: OK$/', $response)) {
|
||||
return CLAMAV_SCANRESULT_CLEAN;
|
||||
}
|
||||
elseif (preg_match('/.*: (.*) FOUND$/', $response, $matches)) {
|
||||
$virus_name = $matches[1];
|
||||
\OCP\Util::writeLog('files_antivirus', 'Virus detected in file. Clamav reported the virus: '.$virus_name, \OCP\Util::WARN);
|
||||
return CLAMAV_SCANRESULT_INFECTED;
|
||||
}
|
||||
else {
|
||||
// try to extract the error message from the response.
|
||||
preg_match('/.*: (.*) ERROR$/', $response, $matches);
|
||||
$error_string = $matches[1]; // the error message given by the daemon
|
||||
\OCP\Util::writeLog('files_antivirus', 'File could not be scanned. Clamscan reported: '.$error_string, \OCP\Util::WARN);
|
||||
return CLAMAV_SCANRESULT_UNCHECKED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function _clamav_scan_via_exec($filepath) {
|
||||
\OCP\Util::writeLog('files_antivirus', 'Exec scan: '.$filepath, \OCP\Util::DEBUG);
|
||||
// get the path to the executable
|
||||
$av_path = \OCP\Config::getAppValue('files_antivirus', 'av_path', '/usr/bin/clamscan');
|
||||
|
||||
// check that the executable is available
|
||||
if (!file_exists($av_path)) {
|
||||
\OCP\Util::writeLog('files_antivirus', 'The clamscan executable could not be found at '.$av_path, \OCP\Util::ERROR);
|
||||
return CLAMAV_SCANRESULT_UNCHECKED;
|
||||
}
|
||||
|
||||
// using 2>&1 to grab the full command-line output.
|
||||
$cmd = escapeshellcmd($av_path) ." ". escapeshellarg($filepath) . " 2>&1";
|
||||
exec($cmd, $output, $result);
|
||||
|
||||
|
||||
/**
|
||||
* clamscan return values (documented from man clamscan)
|
||||
* 0 : No virus found.
|
||||
* 1 : Virus(es) found.
|
||||
* X : Error.
|
||||
* TODO: add errors?
|
||||
*/
|
||||
switch($result) {
|
||||
case 0:
|
||||
\OCP\Util::writeLog('files_antivirus', 'Result CLEAN!', \OCP\Util::DEBUG);
|
||||
return CLAMAV_SCANRESULT_CLEAN;
|
||||
|
||||
case 1:
|
||||
$line = 0;
|
||||
$report = array();
|
||||
while ( strpos($output[$line], "--- SCAN SUMMARY ---") === FALSE ) {
|
||||
if (preg_match('/.*: (.*) FOUND$/', $output[$line], $matches)) {
|
||||
$report[] = $matches[1];
|
||||
}
|
||||
$line++;
|
||||
}
|
||||
\OCP\Util::writeLog('files_antivirus', 'Virus detected in file. Clamscan reported: '.implode(', ', $report), \OCP\Util::WARN);
|
||||
return CLAMAV_SCANRESULT_INFECTED;
|
||||
|
||||
default:
|
||||
$descriptions = array(
|
||||
40 => "Unknown option passed.",
|
||||
50 => "Database initialization error.",
|
||||
52 => "Not supported file type.",
|
||||
53 => "Can't open directory.",
|
||||
54 => "Can't open file. (ofm)",
|
||||
55 => "Error reading file. (ofm)",
|
||||
56 => "Can't stat input file / directory.",
|
||||
57 => "Can't get absolute path name of current working directory.",
|
||||
58 => "I/O error, please check your file system.",
|
||||
62 => "Can't initialize logger.",
|
||||
63 => "Can't create temporary files/directories (check permissions).",
|
||||
64 => "Can't write to temporary directory (please specify another one).",
|
||||
70 => "Can't allocate memory (calloc).",
|
||||
71 => "Can't allocate memory (malloc).",
|
||||
);
|
||||
$description = (array_key_exists($result, $descriptions)) ? $descriptions[$result] : 'unknown error';
|
||||
|
||||
\OCP\Util::writeLog('files_antivirus', 'File could not be scanned. Clamscan reported: '.$result, \OCP\Util::WARN);
|
||||
return CLAMAV_SCANRESULT_UNCHECKED;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - files_antivirus
|
||||
*
|
||||
* @author Manuel Deglado
|
||||
* @copyright 2012 Manuel Deglado manuel.delgado@ucr.ac.cr
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
$params = array(
|
||||
'av_mode' => 'executable',
|
||||
'av_host' => '',
|
||||
'av_port' => '',
|
||||
'av_chunk_size' => '1024',
|
||||
'av_path' => '/usr/bin/clamscan',
|
||||
);
|
||||
|
||||
if($_POST){
|
||||
foreach($params as $param => $default){
|
||||
if(isset($_POST[$param])){
|
||||
OCP\Config::setAppValue('files_antivirus', $param, $_POST[$param]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill template
|
||||
$tmpl = new OC_Template( 'files_antivirus', 'settings');
|
||||
OCP\Util::addScript('files_antivirus', 'settings');
|
||||
foreach($params as $param => $default){
|
||||
$value = OCP\Config::getAppValue('files_antivirus', $param, $default);
|
||||
$tmpl->assign($param, $value);
|
||||
}
|
||||
|
||||
return $tmpl->fetchPage();
|
|
@ -0,0 +1,4 @@
|
|||
<p><?php echo str_replace('{user}', $_['user'], $l->t('Greetings {user},')); ?> </p>
|
||||
<p style='margin-left:20px'><?php echo $l->t('Sorry, but a malware was detected in a file you tried to upload and it had to be deleted.'); ?> <br />
|
||||
<?php echo str_replace('{host}', $_['host'], $l->t('This email is a notification from {host}. Please, do not reply.')); ?> </p>
|
||||
<p style='margin-left:20px'><?php echo str_replace('{file}', $_['file'], $l->t('File uploaded: {file}')); ?> </p>
|
|
@ -0,0 +1,13 @@
|
|||
<form id="antivirus" action="#" method="post">
|
||||
<fieldset class="personalblock">
|
||||
<legend><strong><?php echo $l->t('Antivirus Configuration');?></strong></legend>
|
||||
<p class='av_mode'><label for="av_mode"><?php echo $l->t('Mode');?></label>
|
||||
<select id="av_mode" name="av_mode"><?php echo html_select_options(array('executable' => $l->t('Executable'), 'daemon' => $l->t('Daemon')), $_['av_mode']) ?></select>
|
||||
</p>
|
||||
<p class='av_host'><label for="av_host"><?php echo $l->t('Host');?></label><input type="text" id="av_host" name="av_host" value="<?php echo $_['av_host']; ?>" title="<?php echo $l->t('Address of Antivirus Host.'). ' ' .$l->t('Not required in Executable Mode.');?>"></p>
|
||||
<p class='av_port'><label for="av_port"><?php echo $l->t('Port');?></label><input type="text" id="av_port" name="av_port" value="<?php echo $_['av_port']; ?>" title="<?php echo $l->t('Port number of Antivirus Host.'). ' ' .$l->t('Not required in Executable Mode.');?>"></p>
|
||||
<p class='av_chunk_size'><label for="av_chunk_size"><?php echo $l->t('Stream Length');?></label><input type="text" id="av_chunk_size" name="av_chunk_size" value="<?php echo $_['av_chunk_size']; ?>" title="<?php echo $l->t('ClamAV StreamMaxLength value in bytes.'). ' ' .$l->t('Not required in Executable Mode.');?>"> bytes</p>
|
||||
<p class='av_path'><label for="av_path"><?php echo $l->t('Path to clamscan');?></label><input type="text" id="av_path" name="av_path" value="<?php echo $_['av_path']; ?>" title="<?php echo $l->t('Path to clamscan executable.'). ' ' .$l->t('Not required in Daemon Mode.');?>"></p>
|
||||
<input type="submit" value="<?php echo $l->t('Save');?>" />
|
||||
</fieldset>
|
||||
</form>
|
Загрузка…
Ссылка в новой задаче