���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home3/cpr76684/public_html/clamav.tar
���ѧ٧ѧ�
db/upgrade.php 0000644 00000003013 15151251326 0007267 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * ClamAV antivirus plugin upgrade script. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Run all ClamAV plugin upgrade steps between the current DB version and the current version on disk. * * @param int $oldversion The old version of atto in the DB. * @return bool */ function xmldb_antivirus_clamav_upgrade($oldversion) { // Automatically generated Moodle v3.9.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.0.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.1.0 release upgrade line. // Put any upgrade step following this. return true; } tests/scanner_test.php 0000644 00000044751 15151251326 0011123 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace antivirus_clamav; /** * Tests for ClamAV antivirus scanner class. * * @package antivirus_clamav * @category test * @copyright 2016 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class scanner_test extends \advanced_testcase { /** @var string temporary file used in testing */ protected $tempfile; protected function setUp(): void { $this->resetAfterTest(); // Create tempfile. $tempfolder = make_request_directory(false); $this->tempfile = $tempfolder . '/' . rand(); touch($this->tempfile); } protected function tearDown(): void { @unlink($this->tempfile); } public function test_scan_file_not_exists() { $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods(array('scan_file_execute_commandline', 'message_admins')) ->getMock(); // Test specifying file that does not exist. $nonexistingfile = $this->tempfile . '_'; $this->assertFileDoesNotExist($nonexistingfile); // Run mock scanning, we expect SCAN_RESULT_ERROR. $this->assertEquals(2, $antivirus->scan_file($nonexistingfile, '')); $this->assertDebuggingCalled(); } public function test_scan_file_no_virus() { $methods = array( 'scan_file_execute_commandline', 'scan_file_execute_socket', 'message_admins', 'get_config', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Initiate mock scanning with configuration setting to use commandline. $configmap = array(array('runningmethod', 'commandline')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Configure scan_file_execute_commandline and scan_file_execute_socket // method stubs to behave as if no virus has been found (SCAN_RESULT_OK). $antivirus->method('scan_file_execute_commandline')->willReturn(0); $antivirus->method('scan_file_execute_socket')->willReturn(0); // Set expectation that message_admins is NOT called. $antivirus->expects($this->never())->method('message_admins'); // Run mock scanning. $this->assertFileExists($this->tempfile); $this->assertEquals(0, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to use unixsocket. $configmap = array(array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertEquals(0, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to use tcpsocket. $configmap = array(array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertEquals(0, $antivirus->scan_file($this->tempfile, '')); } public function test_scan_file_virus() { $methods = array( 'scan_file_execute_commandline', 'scan_file_execute_socket', 'message_admins', 'get_config', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Initiate mock scanning with configuration setting to use commandline. $configmap = array(array('runningmethod', 'commandline')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Configure scan_file_execute_commandline and scan_file_execute_socket // method stubs to behave as if virus has been found (SCAN_RESULT_FOUND). $antivirus->method('scan_file_execute_commandline')->willReturn(1); $antivirus->method('scan_file_execute_socket')->willReturn(1); // Set expectation that message_admins is NOT called. $antivirus->expects($this->never())->method('message_admins'); // Run mock scanning. $this->assertFileExists($this->tempfile); $this->assertEquals(1, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to use unixsocket. $configmap = array(array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertEquals(1, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to use tcpsocket. $configmap = array(array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertEquals(1, $antivirus->scan_file($this->tempfile, '')); } public function test_scan_file_error_donothing() { $methods = array( 'scan_file_execute_commandline', 'scan_file_execute_socket', 'message_admins', 'get_config', 'get_scanning_notice', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Configure scan_file_execute_commandline and scan_file_execute_socket // method stubs to behave as if there is a scanning error (SCAN_RESULT_ERROR). $antivirus->method('scan_file_execute_commandline')->willReturn(2); $antivirus->method('scan_file_execute_socket')->willReturn(2); $antivirus->method('get_scanning_notice')->willReturn('someerror'); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Initiate mock scanning with configuration setting to do nothing on // scanning error and using commandline. $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'commandline')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertFileExists($this->tempfile); $this->assertEquals(2, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to do nothing on // scanning error and using unixsocket. $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertEquals(2, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to do nothing on // scanning error and using tcpsocket. $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertEquals(2, $antivirus->scan_file($this->tempfile, '')); } public function test_scan_file_error_actlikevirus() { $methods = array( 'scan_file_execute_commandline', 'scan_file_execute_socket', 'message_admins', 'get_config', 'get_scanning_notice', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Configure scan_file_execute_commandline and scan_file_execute_socket // method stubs to behave as if there is a scanning error (SCAN_RESULT_ERROR). $antivirus->method('scan_file_execute_commandline')->willReturn(2); $antivirus->method('scan_file_execute_socket')->willReturn(2); $antivirus->method('get_scanning_notice')->willReturn('someerror'); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Initiate mock scanning with configuration setting to act like virus on // scanning error and using commandline. $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'commandline')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration // require us to act like virus. $this->assertFileExists($this->tempfile); $this->assertEquals(1, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to act like virus on // scanning error and using unixsocket. $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration // require us to act like virus. $this->assertEquals(1, $antivirus->scan_file($this->tempfile, '')); // Initiate mock scanning with configuration setting to act like virus on // scanning error and using tcpsocket. $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration // require us to act like virus. $this->assertEquals(1, $antivirus->scan_file($this->tempfile, '')); } public function test_scan_file_error_tryagain() { $methods = array( 'scan_file_execute_commandline', 'scan_file_execute_unixsocket', 'message_admins', 'get_config', 'get_scanning_notice', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')->onlyMethods($methods)->getMock(); // Configure scan_file_execute_commandline and scan_file_execute_unixsocket // method stubs to behave as if there is a scanning error (SCAN_RESULT_ERROR). $antivirus->method('scan_file_execute_commandline')->willReturn(2); $antivirus->method('scan_file_execute_unixsocket')->willReturn(2); $antivirus->method('get_scanning_notice')->willReturn('someerror'); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Initiate mock scanning with configuration setting to act like virus on // scanning error and using commandline. $configmap = array(array('clamfailureonupload', 'tryagain'), array('runningmethod', 'commandline')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Run mock scanning. $this->assertFileExists($this->tempfile); $this->expectException(\core\antivirus\scanner_exception::class); $antivirus->scan_file($this->tempfile, ''); $this->assertEquals('antivirusfailed', $this->getExpectedExceptionCode()); $this->assertFileDoesNotExist($this->tempfile); } public function test_scan_data_no_virus() { $methods = array( 'scan_data_execute_socket', 'message_admins', 'get_config', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Initiate mock scanning with configuration setting to use unixsocket. $configmap = array(array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Configure scan_data_execute_socket method stubs to behave as if // no virus has been found (SCAN_RESULT_OK). $antivirus->method('scan_data_execute_socket')->willReturn(0); // Set expectation that message_admins is NOT called. $antivirus->expects($this->never())->method('message_admins'); // Run mock scanning. $this->assertEquals(0, $antivirus->scan_data('')); // Re-initiate mock scanning with configuration setting to use tcpsocket. $configmap = array(array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Set expectation that message_admins is NOT called. $antivirus->expects($this->never())->method('message_admins'); // Run mock scanning. $this->assertEquals(0, $antivirus->scan_data('')); } public function test_scan_data_virus() { $methods = array( 'scan_data_execute_socket', 'message_admins', 'get_config', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Initiate mock scanning with configuration setting to use unixsocket. $configmap = array(array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Configure scan_data_execute_socket method stubs to behave as if // no virus has been found (SCAN_RESULT_FOUND). $antivirus->method('scan_data_execute_socket')->willReturn(1); // Set expectation that message_admins is NOT called. $antivirus->expects($this->never())->method('message_admins'); // Run mock scanning. $this->assertEquals(1, $antivirus->scan_data('')); // Re-initiate mock scanning with configuration setting to use tcpsocket. $configmap = array(array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Set expectation that message_admins is NOT called. $antivirus->expects($this->never())->method('message_admins'); // Run mock scanning. $this->assertEquals(1, $antivirus->scan_data('')); } public function test_scan_data_error_donothing() { $methods = array( 'scan_data_execute_socket', 'message_admins', 'get_config', 'get_scanning_notice', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Initiate mock scanning with configuration setting to do nothing on // scanning error and using unixsocket. $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Configure scan_data_execute_socket method stubs to behave as if // there is a scanning error (SCAN_RESULT_ERROR). $antivirus->method('scan_data_execute_socket')->willReturn(2); $antivirus->method('get_scanning_notice')->willReturn('someerror'); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Run mock scanning. $this->assertEquals(2, $antivirus->scan_data('')); // Re-initiate mock scanning with configuration setting to do nothing on // scanning error and using tcsocket. $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Run mock scanning. $this->assertEquals(2, $antivirus->scan_data('')); } public function test_scan_data_error_actlikevirus() { $methods = array( 'scan_data_execute_socket', 'message_admins', 'get_config', 'get_scanning_notice', ); $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner') ->onlyMethods($methods) ->getMock(); // Initiate mock scanning with configuration setting to act like virus on // scanning error and using unixsocket. $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'unixsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Configure scan_data_execute_socket method stubs to behave as if // there is a scanning error (SCAN_RESULT_ERROR). $antivirus->method('scan_data_execute_socket')->willReturn(2); $antivirus->method('get_scanning_notice')->willReturn('someerror'); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration // require us to act like virus. $this->assertEquals(1, $antivirus->scan_data('')); // Re-initiate mock scanning with configuration setting to act like virus on // scanning error and using tcpsocket. $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'tcpsocket')); $antivirus->method('get_config')->will($this->returnValueMap($configmap)); // Set expectation that message_admins is called. $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror')); // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration // require us to act like virus. $this->assertEquals(1, $antivirus->scan_data('')); } } adminlib.php 0000644 00000013011 15151251326 0007031 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * ClamAV antivirus adminlib. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Admin setting for running, adds verification. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class antivirus_clamav_runningmethod_setting extends admin_setting_configselect { /** * Save a setting * * @param string $data * @return string empty or error string */ public function write_setting($data) { $validated = $this->validate($data); if ($validated !== true) { return $validated; } return parent::write_setting($data); } /** * Validate data. * * This ensures that the selected socket transport is supported by this system. * * @param string $data * @return mixed True on success, else error message. */ public function validate($data) { $supportedtransports = stream_get_transports(); if ($data === 'unixsocket') { if (array_search('unix', $supportedtransports) === false) { return get_string('errornounixsocketssupported', 'antivirus_clamav'); } } else if ($data === 'tcpsocket') { if (array_search('tcp', $supportedtransports) === false) { return get_string('errornotcpsocketssupported', 'antivirus_clamav'); } } return true; } } /** * Abstract socket checking class * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @copyright 2019 Didier Raboud, Liip AG. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class antivirus_clamav_socket_setting extends admin_setting_configtext { /** * Ping ClamAV socket. * * This ensures that a socket setting is correct and that ClamAV is running. * * @param string $socketaddress Address to the socket to connect to (for stream_socket_client) * @return mixed True on success, else error message. */ protected function validate_clamav_socket($socketaddress) { $socket = stream_socket_client($socketaddress, $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT); if (!$socket) { return get_string('errorcantopensocket', 'antivirus_clamav', "$errstr ($errno)"); } else { // Send PING query to ClamAV socket to check its running state. fwrite($socket, "nPING\n"); $response = stream_get_line($socket, 4); fclose($socket); if ($response !== 'PONG') { return get_string('errorclamavnoresponse', 'antivirus_clamav'); } } return true; } } /** * Admin setting for unix socket path, adds verification. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class antivirus_clamav_pathtounixsocket_setting extends antivirus_clamav_socket_setting { /** * Validate data. * * This ensures that unix socket setting is correct and ClamAV is running. * * @param string $data * @return mixed True on success, else error message. */ public function validate($data) { $result = parent::validate($data); if ($result !== true) { return $result; } $runningmethod = get_config('antivirus_clamav', 'runningmethod'); if ($runningmethod === 'unixsocket') { return $this->validate_clamav_socket('unix://' . $data); } return true; } } /** * Admin setting for Internet domain socket host, adds verification. * * @package antivirus_clamav * @copyright 2019 Didier Raboud, Liip AG. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class antivirus_clamav_tcpsockethost_setting extends antivirus_clamav_socket_setting { /** * Validate data. * * This ensures that Internet domain socket setting is correct and ClamAV is running. * * @param string $data * @return mixed True on success, else error message. */ public function validate($data) { $result = parent::validate($data); if ($result !== true) { return $result; } $runningmethod = get_config('antivirus_clamav', 'runningmethod'); $tcpport = get_config('antivirus_clamav', 'tcpsocketport'); if ($tcpport === false) { $tcpport = 3310; } if ($runningmethod === 'tcpsocket') { return $this->validate_clamav_socket('tcp://' . $data . ':' . $tcpport); } return true; } } settings.php 0000644 00000007405 15151251326 0007124 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * ClamAV admin settings. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); if ($ADMIN->fulltree) { require_once(__DIR__ . '/adminlib.php'); require_once(__DIR__ . '/classes/scanner.php'); // Running method. $runningmethodchoice = array( 'commandline' => get_string('runningmethodcommandline', 'antivirus_clamav'), 'unixsocket' => get_string('runningmethodunixsocket', 'antivirus_clamav'), 'tcpsocket' => get_string('runningmethodtcpsocket', 'antivirus_clamav'), ); $settings->add(new antivirus_clamav_runningmethod_setting('antivirus_clamav/runningmethod', get_string('runningmethod', 'antivirus_clamav'), get_string('runningmethoddesc', 'antivirus_clamav'), 'commandline', $runningmethodchoice)); // Path to ClamAV scanning utility (used in command line running method). $settings->add(new admin_setting_configexecutable('antivirus_clamav/pathtoclam', new lang_string('pathtoclam', 'antivirus_clamav'), new lang_string('pathtoclamdesc', 'antivirus_clamav'), '')); // Path to ClamAV unix socket (used in unix socket running method). $settings->add(new antivirus_clamav_pathtounixsocket_setting('antivirus_clamav/pathtounixsocket', new lang_string('pathtounixsocket', 'antivirus_clamav'), new lang_string('pathtounixsocketdesc', 'antivirus_clamav'), '', PARAM_PATH)); // Hostname to reach ClamAV tcp socket (used in tcp socket running method). $settings->add(new antivirus_clamav_tcpsockethost_setting('antivirus_clamav/tcpsockethost', new lang_string('tcpsockethost', 'antivirus_clamav'), new lang_string('tcpsockethostdesc', 'antivirus_clamav'), '', PARAM_HOST)); // Port to reach ClamAV tcp socket (used in tcp socket running method). $settings->add(new admin_setting_configtext('antivirus_clamav/tcpsocketport', new lang_string('tcpsocketport', 'antivirus_clamav'), new lang_string('tcpsocketportdesc', 'antivirus_clamav'), 3310, PARAM_INT)); // How to act on ClamAV failure. $options = array( 'donothing' => new lang_string('configclamdonothing', 'antivirus_clamav'), 'actlikevirus' => new lang_string('configclamactlikevirus', 'antivirus_clamav'), 'tryagain' => new lang_string('configclamtryagain', 'antivirus_clamav') ); $settings->add(new admin_setting_configselect('antivirus_clamav/clamfailureonupload', new lang_string('clamfailureonupload', 'antivirus_clamav'), new lang_string('configclamfailureonupload', 'antivirus_clamav'), 'tryagain', $options)); // Number of attempts clamav will try when there is error during a scanning process. $options = array(1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5); $settings->add(new admin_setting_configselect('antivirus_clamav/tries', new lang_string('tries', 'antivirus_clamav'), new lang_string('tries_desc', 'antivirus_clamav'), 1, $options)); } version.php 0000644 00000002254 15151251326 0006746 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * ClamAV antivirus version file. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->version = 2022112800; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2022111800; // Requires this Moodle version. $plugin->component = 'antivirus_clamav'; // Full name of the plugin (used for diagnostics). classes/privacy/provider.php 0000644 00000003006 15151251326 0012221 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Privacy Subsystem implementation for antivirus_clamav. * * @package antivirus_clamav * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace antivirus_clamav\privacy; defined('MOODLE_INTERNAL') || die(); /** * Privacy Subsystem for antivirus_clamav implementing null_provider. * * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\null_provider { /** * Get the language string identifier with the component's language * file to explain why this plugin stores no data. * * @return string */ public static function get_reason() : string { return 'privacy:metadata'; } } classes/scanner.php 0000644 00000044103 15151251326 0010346 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * ClamAV antivirus integration. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace antivirus_clamav; defined('MOODLE_INTERNAL') || die(); /** Default socket timeout */ define('ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT', 10); /** Default socket data stream chunk size (32Mb: 32 * 1024 * 1024) */ define('ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE', 33554432); /** * Class implementing ClamAV antivirus. * @copyright 2015 Ruslan Kabalin, Lancaster University. * @copyright 2019 Didier Raboud, Liip AG. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class scanner extends \core\antivirus\scanner { /** * Are the necessary antivirus settings configured? * * @return bool True if all necessary config settings been entered */ public function is_configured() { if ($this->get_config('runningmethod') === 'commandline') { return (bool)$this->get_config('pathtoclam'); } else if ($this->get_config('runningmethod') === 'unixsocket') { return (bool)$this->get_config('pathtounixsocket'); } else if ($this->get_config('runningmethod') === 'tcpsocket') { return (bool)$this->get_config('tcpsockethost') && (bool)$this->get_config('tcpsocketport'); } return false; } /** * Scan file. * * This method is normally called from antivirus manager (\core\antivirus\manager::scan_file). * * @param string $file Full path to the file. * @param string $filename Name of the file (could be different from physical file if temp file is used). * @return int Scanning result constant. */ public function scan_file($file, $filename) { if (!is_readable($file)) { // This should not happen. debugging('File is not readable.'); return self::SCAN_RESULT_ERROR; } // We can do direct stream scanning if unixsocket or tcpsocket running methods are in use, // if not, use default process. $maxtries = get_config('antivirus_clamav', 'tries'); $tries = 0; do { $runningmethod = $this->get_config('runningmethod'); $tries++; switch ($runningmethod) { case 'unixsocket': case 'tcpsocket': $return = $this->scan_file_execute_socket($file, $runningmethod); break; case 'commandline': $return = $this->scan_file_execute_commandline($file); break; default: // This should not happen. throw new \coding_exception('Unknown running method.'); } } while ($return == self::SCAN_RESULT_ERROR && $tries < $maxtries); $notice = get_string('tries_notice', 'antivirus_clamav', ['tries' => $tries, 'notice' => $this->get_scanning_notice()]); $this->set_scanning_notice($notice); if ($return === self::SCAN_RESULT_ERROR) { $this->message_admins($this->get_scanning_notice()); // If plugin settings require us to act like virus on any error, // return SCAN_RESULT_FOUND result. if ($this->get_config('clamfailureonupload') === 'actlikevirus') { return self::SCAN_RESULT_FOUND; } else if ($this->get_config('clamfailureonupload') === 'tryagain') { // Do not upload the file, just give a message to the user to try again later. unlink($file); throw new \core\antivirus\scanner_exception('antivirusfailed', '', ['item' => $filename], null, 'antivirus_clamav'); } } return $return; } /** * Scan data. * * @param string $data The variable containing the data to scan. * @return int Scanning result constant. */ public function scan_data($data) { // We can do direct stream scanning if unixsocket or tcpsocket running methods are in use, // if not, use default process. $runningmethod = $this->get_config('runningmethod'); if (in_array($runningmethod, array('unixsocket', 'tcpsocket'))) { $return = $this->scan_data_execute_socket($data, $runningmethod); if ($return === self::SCAN_RESULT_ERROR) { $this->message_admins($this->get_scanning_notice()); // If plugin settings require us to act like virus on any error, // return SCAN_RESULT_FOUND result. if ($this->get_config('clamfailureonupload') === 'actlikevirus') { return self::SCAN_RESULT_FOUND; } } return $return; } else { return parent::scan_data($data); } } /** * Returns a Unix domain socket destination url * * @return string The socket url, fit for stream_socket_client() */ private function get_unixsocket_destination() { return 'unix://' . $this->get_config('pathtounixsocket'); } /** * Returns a Internet domain socket destination url * * @return string The socket url, fit for stream_socket_client() */ private function get_tcpsocket_destination() { return 'tcp://' . $this->get_config('tcpsockethost') . ':' . $this->get_config('tcpsocketport'); } /** * Returns the string equivalent of a numeric clam error code * * @param int $returncode The numeric error code in question. * @return string The definition of the error code */ private function get_clam_error_code($returncode) { $returncodes = array(); $returncodes[0] = 'No virus found.'; $returncodes[1] = 'Virus(es) found.'; $returncodes[2] = ' An error occured'; // Specific to clamdscan. // All after here are specific to clamscan. $returncodes[40] = 'Unknown option passed.'; $returncodes[50] = 'Database initialization error.'; $returncodes[52] = 'Not supported file type.'; $returncodes[53] = 'Can\'t open directory.'; $returncodes[54] = 'Can\'t open file. (ofm)'; $returncodes[55] = 'Error reading file. (ofm)'; $returncodes[56] = 'Can\'t stat input file / directory.'; $returncodes[57] = 'Can\'t get absolute path name of current working directory.'; $returncodes[58] = 'I/O error, please check your filesystem.'; $returncodes[59] = 'Can\'t get information about current user from /etc/passwd.'; $returncodes[60] = 'Can\'t get information about user \'clamav\' (default name) from /etc/passwd.'; $returncodes[61] = 'Can\'t fork.'; $returncodes[63] = 'Can\'t create temporary files/directories (check permissions).'; $returncodes[64] = 'Can\'t write to temporary directory (please specify another one).'; $returncodes[70] = 'Can\'t allocate and clear memory (calloc).'; $returncodes[71] = 'Can\'t allocate memory (malloc).'; if (isset($returncodes[$returncode])) { return $returncodes[$returncode]; } return get_string('unknownerror', 'antivirus_clamav'); } /** * Scan file using command line utility. * * @param string $file Full path to the file. * @return int Scanning result constant. */ public function scan_file_execute_commandline($file) { $pathtoclam = trim($this->get_config('pathtoclam')); if (!file_exists($pathtoclam) or !is_executable($pathtoclam)) { // Misconfigured clam, notify admins. $notice = get_string('invalidpathtoclam', 'antivirus_clamav', $pathtoclam); $this->set_scanning_notice($notice); return self::SCAN_RESULT_ERROR; } $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($pathtoclam) == 'clamdscan') { $clamparam .= '--fdpass '; } // Execute scan. $cmd = escapeshellcmd($pathtoclam).$clamparam.escapeshellarg($file); exec($cmd, $output, $return); // Return variable will contain execution return code. It will be 0 if no virus is found, // 1 if virus is found, and 2 or above for the error. Return codes 0 and 1 correspond to // SCAN_RESULT_OK and SCAN_RESULT_FOUND constants, so we return them as it is. // If there is an error, it gets stored as scanning notice and function // returns SCAN_RESULT_ERROR. if ($return > self::SCAN_RESULT_FOUND) { $notice = get_string('clamfailed', 'antivirus_clamav', $this->get_clam_error_code($return)); $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; } /** * Scan file using sockets. * * @param string $file Full path to the file. * @param string $type Either 'tcpsocket' or 'unixsocket' * @return int Scanning result constant. */ public function scan_file_execute_socket($file, $type) { switch ($type) { case "tcpsocket": $socketurl = $this->get_tcpsocket_destination(); break; case "unixsocket": $socketurl = $this->get_unixsocket_destination(); break; default; // This should not happen. debugging('Unknown socket type.'); return self::SCAN_RESULT_ERROR; } $socket = stream_socket_client($socketurl, $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT); if (!$socket) { // Can't open socket for some reason, notify admins. $notice = get_string('errorcantopensocket', 'antivirus_clamav', "$errstr ($errno)"); $this->set_scanning_notice($notice); return self::SCAN_RESULT_ERROR; } else { if ($type == "unixsocket") { // Execute scanning. We are running SCAN command and passing file as an argument, // it is the fastest option, but clamav user need to be able to access it, so // we give group read permissions first and assume 'clamav' user is in web server // group (in Debian the default webserver group is 'www-data'). // Using 'n' as command prefix is forcing clamav to only treat \n as newline delimeter, // this is to avoid unexpected newline characters on different systems. $perms = fileperms($file); chmod($file, 0640); // Actual scan. fwrite($socket, "nSCAN ".$file."\n"); // Get ClamAV answer. $output = stream_get_line($socket, 4096); // After scanning we revert permissions to initial ones. chmod($file, $perms); } else if ($type == "tcpsocket") { // Execute scanning by passing the entire file through the TCP socket. // This is not fast, but is the only possibility over a network. // Using 'n' as command prefix is forcing clamav to only treat \n as newline delimeter, // this is to avoid unexpected newline characters on different systems. // Actual scan. fwrite($socket, "nINSTREAM\n"); // Open the file for reading. $fhandle = fopen($file, 'rb'); while (!feof($fhandle)) { // Read it by chunks; write them to the TCP socket. $chunk = fread($fhandle, ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE); $size = pack('N', strlen($chunk)); fwrite($socket, $size); fwrite($socket, $chunk); } // Terminate streaming. fwrite($socket, pack('N', 0)); // Get ClamAV answer. $output = stream_get_line($socket, 4096); fclose($fhandle); } // Free up the ClamAV socket. fclose($socket); // Parse the output. return $this->parse_socket_response($output); } } /** * Scan data socket. * * We are running INSTREAM command and passing data stream in chunks. * The format of the chunk is: <length><data> where <length> is the size of the following * data in bytes expressed as a 4 byte unsigned integer in network byte order and <data> * is the actual chunk. Streaming is terminated by sending a zero-length chunk. * Do not exceed StreamMaxLength as defined in clamd.conf, otherwise clamd will * reply with INSTREAM size limit exceeded and close the connection. * * @param string $data The variable containing the data to scan. * @param string $type Either 'tcpsocket' or 'unixsocket' * @return int Scanning result constant. */ public function scan_data_execute_socket($data, $type) { switch ($type) { case "tcpsocket": $socketurl = $this->get_tcpsocket_destination(); break; case "unixsocket": $socketurl = $this->get_unixsocket_destination(); break; default; // This should not happen. debugging('Unknown socket type!'); return self::SCAN_RESULT_ERROR; } $socket = stream_socket_client($socketurl, $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT); if (!$socket) { // Can't open socket for some reason, notify admins. $notice = get_string('errorcantopensocket', 'antivirus_clamav', "$errstr ($errno)"); $this->set_scanning_notice($notice); return self::SCAN_RESULT_ERROR; } else { // Initiate data stream scanning. // Using 'n' as command prefix is forcing clamav to only treat \n as newline delimeter, // this is to avoid unexpected newline characters on different systems. fwrite($socket, "nINSTREAM\n"); // Send data in chunks of ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE size. while (strlen($data) > 0) { $chunk = substr($data, 0, ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE); $data = substr($data, ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE); $size = pack('N', strlen($chunk)); fwrite($socket, $size); fwrite($socket, $chunk); } // Terminate streaming. fwrite($socket, pack('N', 0)); $output = stream_get_line($socket, 4096); fclose($socket); // Parse the output. return $this->parse_socket_response($output); } } /** * Parse socket command response. * * @param string $output The socket response. * @return int Scanning result constant. */ private function parse_socket_response($output) { $splitoutput = explode(': ', $output); $message = trim($splitoutput[1]); if ($message === 'OK') { return self::SCAN_RESULT_OK; } else { $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)); $notice .= "\n\n" . $output; $this->set_scanning_notice($notice); return self::SCAN_RESULT_ERROR; } } } /** * Scan data using Unix domain socket. * * @deprecated since Moodle 3.9 MDL-64075 - please do not use this function any more. * @see antivirus_clamav\scanner::scan_data_execute_socket() * * @param string $data The variable containing the data to scan. * @return int Scanning result constant. */ public function scan_data_execute_unixsocket($data) { debugging('antivirus_clamav\scanner::scan_data_execute_unixsocket() is deprecated. ' . 'Use antivirus_clamav\scanner::scan_data_execute_socket() instead.', DEBUG_DEVELOPER); return $this->scan_data_execute_socket($data, "unixsocket"); } /** * Scan file using Unix domain socket. * * @deprecated since Moodle 3.9 MDL-64075 - please do not use this function any more. * @see antivirus_clamav\scanner::scan_file_execute_socket() * * @param string $file Full path to the file. * @return int Scanning result constant. */ public function scan_file_execute_unixsocket($file) { debugging('antivirus_clamav\scanner::scan_file_execute_unixsocket() is deprecated. ' . 'Use antivirus_clamav\scanner::scan_file_execute_socket() instead.', DEBUG_DEVELOPER); return $this->scan_file_execute_socket($file, "unixsocket"); } } lang/en/antivirus_clamav.php 0000644 00000010020 15151251326 0012141 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Strings for component 'antivirus_clamav', language 'en'. * * @package antivirus_clamav * @copyright 2015 Ruslan Kabalin, Lancaster University. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['antivirusfailed'] = 'There is a problem with AntiVirus scanning at the moment. Your file {$a->item} has not been uploaded. Please try again later.'; $string['configclamactlikevirus'] = 'Treat files like viruses'; $string['configclamdonothing'] = 'Treat files as OK'; $string['configclamfailureonupload'] = 'If \'Treat files as OK\' is selected, files will be moved to the destination directory. If \'Refuse upload, try again\' is selected, the user will be prompted to try again later. If \'Treat files like viruses\' is selected, files will be moved into the quarantine area, or deleted. Warning: With this option, if for some reason clam fails to run (usually because of an invalid pathtoclam), then ALL uploaded files will be moved to the given quarantine area, or deleted.'; $string['configclamtryagain'] = 'Refuse upload, try again'; $string['clamfailed'] = 'ClamAV has failed to run. The return error message was "{$a}". Here is the output from ClamAV:'; $string['clamfailureonupload'] = 'On ClamAV failure'; $string['errorcantopensocket'] = 'Connecting to Unix domain socket resulted in error {$a}'; $string['errorclamavnoresponse'] = 'ClamAV does not respond; check daemon running state.'; $string['errornounixsocketssupported'] = 'Unix domain socket transport is not supported on this system. Please use the command line option instead.'; $string['invalidpathtoclam'] = 'Path to ClamAV, {$a}, is invalid.'; $string['pathtoclam'] = 'Command line'; $string['pathtoclamdesc'] = 'If the running method is set to "command line", enter the path to ClamAV here. On Linux this will be /usr/bin/clamscan or /usr/bin/clamdscan.'; $string['pathtounixsocket'] = 'Unix domain socket'; $string['pathtounixsocketdesc'] = 'If the running method is set to "Unix domain socket", enter the path to ClamAV Unix socket here. On Debian Linux this will be /var/run/clamav/clamd.ctl. Please make sure that clamav daemon has read access to uploaded files, the easiest way to ensure that is to add \'clamav\' user to your webserver group (\'www-data\' on Debian Linux).'; $string['pluginname'] = 'ClamAV antivirus'; $string['privacy:metadata'] = 'The ClamAV antivirus plugin does not store any personal data.'; $string['quarantinedir'] = 'Quarantine directory'; $string['runningmethod'] = 'Running method'; $string['runningmethoddesc'] = 'Method of running ClamAV. Command line is used by default, however on Unix systems better performance can be obtained by using system sockets.'; $string['runningmethodcommandline'] = 'Command line'; $string['runningmethodunixsocket'] = 'Unix domain socket'; $string['runningmethodtcpsocket'] = 'TCP socket'; $string['tcpsockethost'] = 'TCP socket hostname'; $string['tcpsockethostdesc'] = 'Domain name of the ClamAV server'; $string['tcpsocketport'] = 'TCP socket port'; $string['tcpsocketportdesc'] = 'The port to use when connecting to ClamAV'; $string['unknownerror'] = 'There was an unknown error with ClamAV.'; $string['tries'] = 'Scanning attempts'; $string['tries_desc'] = 'Number of attempts made by ClamAV if there is an error during the scanning process.'; $string['tries_notice'] = 'Clamav scanning has tried {$a->tries} time(s). {$a->notice}';
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | ���֧ߧ֧�ѧ�ڧ� ����ѧߧڧ��: 0 |
proxy
|
phpinfo
|
���ѧ����ۧܧ�