# HG changeset patch # User ft # Date 1415119182 -3600 # Node ID 2422a3542d94c8f9db69fb8058d33da73aefe4af # Parent 5b9fdcafd0dfd5a5d5b196ff7daa55eb272fe5db remove osecfs-deb commit Rollback to original diff -r 5b9fdcafd0df -r 2422a3542d94 Apache License, Version 2.0.txt --- a/Apache License, Version 2.0.txt Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff -r 5b9fdcafd0df -r 2422a3542d94 ClamAVScanner.cfg --- a/ClamAVScanner.cfg Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -[Main] -Nothing: placeholder \ No newline at end of file diff -r 5b9fdcafd0df -r 2422a3542d94 IkarusScanner.cfg --- a/IkarusScanner.cfg Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -[Main] -# the maximum file size in MB that is scanned -MaxFileSize: 50 - -# the URL of the local scan server -LocalScanserverURL: http://localhost/virusscan - -# the URL of the remote scan server -RemoteScanserverURL: http://10.215.5.166/virusscan - -# wait time in seconds until a new connection attempt to remote server is made -RetryTimeout: 600 diff -r 5b9fdcafd0df -r 2422a3542d94 clamavscanner/ClamAVScanner.py --- a/clamavscanner/ClamAVScanner.py Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -#!/usr/bin/python - -# ------------------------------------------------------------ -# opensecurity package file -# -# Autor: X-Net Services GmbH -# -# Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology -# -# -# X-Net Technologies GmbH -# Elisabethstrasse 1 -# 4020 Linz -# AUSTRIA -# https://www.x-net.at -# -# AIT Austrian Institute of Technology -# Donau City Strasse 1 -# 1220 Wien -# AUSTRIA -# http://www.ait.ac.at -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ------------------------------------------------------------ - -import ConfigParser - -import sys - -import logging -import os -import errno -import time - -import pyclamav - - -class ClamAVScanner: - - # User the existing logger instance - __LOG = logging.getLogger("IkarusScanner") - - __MINOPTS = { "Main" : ["Nothing"]} - __CONFIG_NOT_READABLE = "Configfile is not readable" - __CONFIG_WRONG = "Something is wrong with the config" - __CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing" - - - - def __init__ (self, scanner_config_path): - config = self.loadConfig (scanner_config_path) - - - - def checkMinimumOptions (self, config): - for section, options in self.__MINOPTS.iteritems (): - for option in options: - if (config.has_option(section, option) == False): - self.__LOG.error (self.__CONFIG_MISSING % (section, option)) - exit (129) - - def loadConfig (self, scanner_config_path): - - configfile = scanner_config_path - config = ConfigParser.SafeConfigParser () - - if ((os.path.exists (scanner_config_path) == False) or (os.path.isfile (scanner_config_path) == False) or (os.access (scanner_config_path, os.R_OK) == False)): - self.__LOG.error(self.__CONFIG_NOT_READABLE); - raise SystemError(self.__CONFIG_NOT_READABLE) - - try: - config.read (scanner_config_path) - except Exception, e: - self.__LOG.error("Error: %s" % (e)); - raise SystemError("Error: %s" % (e)) - - self.checkMinimumOptions (config) - - return config - - - def scanFile (self, path, fileobject): - return self.scanFileClamAV (path) - - def scanFileClamAV (self, path): - retval = { "infected" : False, "virusname" : "Unknown" } - - self.__LOG.debug ("Scan File: %s" % (path)) - - result = pyclamav.scanfile (path) - self.__LOG.debug ("Result of file \"%s\": %s" % (path, result)) - if (result[0] != 0): - retval["infected"] = True - retval["virusname"] = result[1] - - if (retval["infected"] == True): - self.__LOG.error ("Virus found, deny Access %s" % (result,)) - - return retval - diff -r 5b9fdcafd0df -r 2422a3542d94 ikarusscanner/IkarusScanner.py --- a/ikarusscanner/IkarusScanner.py Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -#!/usr/bin/python - -# ------------------------------------------------------------ -# opensecurity package file -# -# Autor: Karlberger Christoph -# X-Net Services GmbH -# -# Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology -# -# IKARUS Security Software GmbH -# Blechturmgasse 11 -# 1050 Wien -# AUSTRIA -# http://www.ikarussecurity.com -# -# X-Net Technologies GmbH -# Elisabethstrasse 1 -# 4020 Linz -# AUSTRIA -# https://www.x-net.at -# -# AIT Austrian Institute of Technology -# Donau City Strasse 1 -# 1220 Wien -# AUSTRIA -# http://www.ait.ac.at -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ------------------------------------------------------------ - -import ConfigParser - -import sys - -import logging -import os -import errno -import time - -import urllib3 -import xml.etree.ElementTree as ET - -class IkarusScanner: - - # User the existing logger instance - __LOG = logging.getLogger("IkarusScanner") - - __MINOPTS = { "Main" : ["LocalScanserverURL", "RemoteScanserverURL", "MaxFileSize", "RetryTimeout"]} - __CONFIG_NOT_READABLE = "Configfile is not readable" - __CONFIG_WRONG = "Something is wrong with the config" - __CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing" - __LOCAL_SCANSERVER_URL = "" - __REMOTE_SCANSERVER_URL = "" - __STATUS_CODE_OK = 200 - __STATUS_CODE_INFECTED = 210 - __STATUS_CODE_NOT_FOUND = 404 - __MAX_SCAN_FILE_SIZE = 50 * 0x100000 - __SCANSERVER_RETRY_TIMEOUT = 60 - - # Global http pool manager used to connect to the scan server - __remoteScanserverReachable = True - __scanserverTimestamp = 0 - __httpPool = urllib3.PoolManager(num_pools = 1, timeout = 3) - - def __init__ (self, scanner_config_path): - config = self.loadConfig (scanner_config_path) - - self.__scanserverTimestamp = time.time() - - self.__LOCAL_SCANSERVER_URL = config.get("Main", "LocalScanserverURL") - self.__REMOTE_SCANSERVER_URL = config.get("Main", "RemoteScanserverURL") - self.__SCANSERVER_RETRY_TIMEOUT = int(config.get("Main", "RetryTimeout")) - - # Convert file size from MB to byte - self.__MAX_SCAN_FILE_SIZE = int(config.get("Main", "MaxFileSize")) * 0x100000 - - - def checkMinimumOptions (self, config): - for section, options in self.__MINOPTS.iteritems (): - for option in options: - if (config.has_option(section, option) == False): - self.__LOG.error (self.__CONFIG_MISSING % (section, option)) - exit (129) - - def loadConfig (self, scanner_config_path): - - configfile = scanner_config_path - config = ConfigParser.SafeConfigParser () - - if ((os.path.exists (scanner_config_path) == False) or (os.path.isfile (scanner_config_path) == False) or (os.access (scanner_config_path, os.R_OK) == False)): - self.__LOG.error(self.__CONFIG_NOT_READABLE); - raise SystemError(self.__CONFIG_NOT_READABLE) - - try: - config.read (scanner_config_path) - except Exception, e: - self.__LOG.error("Error: %s" % (e)); - raise SystemError("Error: %s" % (e)) - - self.checkMinimumOptions (config) - - return config - - def contactScanserver(self, url, fields): - self.__LOG.debug("Contacting server %s" % url) - return self.__httpPool.request_encode_body('POST', url, fields = fields, retries = 0) - - def scanFile (self, path, fileobject): - return self.scanFileIkarus (path, fileobject) - - def scanFileIkarus (self, path, fileobject): - retval = { "infected" : False, "virusname" : "Unknown" } - self.__LOG.debug ("Scan File: %s" % (path)) - - if (os.fstat(fileobject.fileno()).st_size > self.__MAX_SCAN_FILE_SIZE): - self.__LOG.info("File max size exceeded. The file is not scanned.") - retval["infected"] = False - retval["virusname"] = "File is to big to be scanned." - return retval - - fields = { 'up_file' : fileobject.read() } - - if (self.__remoteScanserverReachable == False) and ((self.__scanserverTimestamp + self.__SCANSERVER_RETRY_TIMEOUT) < time.time()): - self.__remoteScanserverReachable = True - - if self.__remoteScanserverReachable: - try: - response = self.contactScanserver(self.__REMOTE_SCANSERVER_URL, fields) - # We should catch socket.error here, but this does not work. Needs checking. - except: - self.__LOG.info("Remote scan server unreachable, using local scan server.") - self.__LOG.debug("Exception: %s: %s" % (sys.exc_info()[0], sys.exc_info()[1])) - self.__LOG.info("Next check for remote server in %s seconds." % (self.__SCANSERVER_RETRY_TIMEOUT)) - - self.__remoteScanserverReachable = False - self.__scanserverTimestamp = time.time() - - try: - response = self.contactScanserver(self.__LOCAL_SCANSERVER_URL, fields) - except: - self.__LOG.error ("Connection to local scan server could not be established.") - self.__LOG.debug ("Exception: %s" % (sys.exc_info()[0])) - return retval - else: - try: - response = self.contactScanserver(self.__LOCAL_SCANSERVER_URL, fields) - except: - self.__LOG.error ("Connection to local scan server could not be established.") - self.__LOG.error ("Exception: %s" %(sys.exc_info()[0])) - return retval - - - if response.status == self.__STATUS_CODE_OK: - retval["infected"] = False - elif response.status == self.__STATUS_CODE_INFECTED: - # Parse xml for info - root = ET.fromstring(response.data) - - # this should be done in a more generic way - retval["virusname"] = root[1][3][0].text - retval["infected"] = True - else: - self.__LOG.error ("Connection error to scan server.") - - if (retval["infected"] == True): - self.__LOG.error ("Virus found, denying access.") - else: - self.__LOG.debug ("No virus found.") - - return retval - - - diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs --- a/osecfs Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,471 +0,0 @@ -#!/usr/bin/python - -# ------------------------------------------------------------ -# opensecurity package file -# -# Autor: X-Net Services GmbH -# -# Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology -# -# -# X-Net Technologies GmbH -# Elisabethstrasse 1 -# 4020 Linz -# AUSTRIA -# https://www.x-net.at -# -# AIT Austrian Institute of Technology -# Donau City Strasse 1 -# 1220 Wien -# AUSTRIA -# http://www.ait.ac.at -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ------------------------------------------------------------ - - -from fuse import Fuse -import fuse - -import ConfigParser - -import sys - -import logging -import os -import errno -import time - -from importlib import import_module - - -import subprocess - -import urllib3 -import netifaces -import netaddr -import hashlib - - -sys.stderr = open('/var/log/osecfs_error.log', 'a+') - - -MINOPTS = { "Main" : ["Logfile", "LogLevel", "Mountpoint", "Rootpath", "ScannerPath", "ScannerModuleName", "ScannerClassName", "ScannerConfig", "ReadOnly"]} - -CONFIG_NOT_READABLE = "Configfile is not readable" -CONFIG_WRONG = "Something is wrong with the config" -CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing" -SCAN_WRONG_RETURN_VALUE = "The return Value of the malware scanner is wrong. Has to be an dictionary" -SCAN_RETURN_VALUE_KEY_MISSING = "The dictionary has to include key \"infected\" (True, False) and \"virusname\" (String)" -VIRUS_FOUND = "Virus found. Access denied" -NOTIFICATION_CRITICAL = "critical" -NOTIFICATION_INFO = "info" -LOG = None -MalwareScanner = None -STATUS_CODE_OK = 200 - -SYSTEM_FILE_COMMAND = "file" -httpPool = urllib3.PoolManager(num_pools = 1, timeout = 3) - -def checkMinimumOptions (config): - for section, options in MINOPTS.iteritems (): - for option in options: - if (config.has_option(section, option) == False): - print (CONFIG_MISSING % (section, option)) - exit (129) - -def printUsage (): - print ("Usage:") - print ("%s configfile mountpath ro/rw" % (sys.argv[0])) - exit (128) - -def loadConfig (): - print ("load config") - - if (len (sys.argv) < 4): - printUsage () - - configfile = sys.argv[1] - config = ConfigParser.SafeConfigParser () - - if ((os.path.exists (configfile) == False) or (os.path.isfile (configfile) == False) or (os.access (configfile, os.R_OK) == False)): - print (CONFIG_NOT_READABLE) - printUsage () - - try: - config.read (sys.argv[1]) - except Exception, e: - print (CONFIG_WRONG) - print ("Error: %s" % (e)) - - - config.set("Main", "Mountpoint", sys.argv[2]) - if (sys.argv[3] == "rw"): - config.set("Main", "ReadOnly", "false") - else: - config.set("Main", "ReadOnly", "true") - - checkMinimumOptions (config) - - return config - -def initLog (config): - print ("init log") - - global LOG - logfile = config.get("Main", "Logfile") - - numeric_level = getattr(logging, config.get("Main", "LogLevel").upper(), None) - if not isinstance(numeric_level, int): - raise ValueError('Invalid log level: %s' % loglevel) - - # ToDo move log level and maybe other things to config file - logging.basicConfig( - level = numeric_level, - format = "%(asctime)s %(name)-12s %(funcName)-15s %(levelname)-8s %(message)s", - datefmt = "%Y-%m-%d %H:%M:%S", - filename = logfile, - filemode = "a+", - ) - LOG = logging.getLogger("fuse_main") - - -def fixPath (path): - return ".%s" % (path) - -def rootPath (rootpath, path): - return "%s%s" % (rootpath, path) - -def flag2mode (flags): - md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} - m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] - - # windows sets append even if it would overwrite the whole file (seek 0) - # so ignore append option - #if flags | os.O_APPEND: - # m = m.replace('w', 'a', 1) - - return m - -def scanFile (path, fileobject): - LOG.debug ("Scan File \"%s\" with malware Scanner" %(path,) ) - return MalwareScanner.scanFile (path, fileobject) - - -def scanFileClamAV (path): - infected = False - - LOG.debug ("Scan File: %s" % (path)) - - result = pyclamav.scanfile (path) - LOG.debug ("Result of file \"%s\": %s" % (path, result)) - if (result[0] != 0): - infected = True - - if (infected == True): - LOG.error ("Virus found, deny Access %s" % (result,)) - - return infected - -def whitelistFile (path): - whitelisted = False; - - LOG.debug ("Execute \"%s\" command on \"%s\"" %(SYSTEM_FILE_COMMAND, path)) - - result = None - try: - result = subprocess.check_output ([SYSTEM_FILE_COMMAND, path]); - # ToDo replace with real whitelist - whitelisted = True - except Exception as e: - LOG.error ("Call returns with an error!") - LOG.error (e) - - LOG.debug ("Type: %s" %(result)) - - return whitelisted - -def sendDataToRest (urlpath, data): - netifaces.ifaddresses("eth0")[2][0]["addr"] - - # Get first address in network (0 = network ip -> 192.168.0.0) - remote_ip = netaddr.IPNetwork("%s/%s" %(netifaces.ifaddresses("eth0")[2][0]["addr"], netifaces.ifaddresses("eth0")[2][0]["netmask"]))[1] - - url = ("http://%s:8090//%s" %(remote_ip, urlpath)) - - LOG.debug ("Send data to \"%s\"" %(url, )) - LOG.debug ("Data: %s" %(data, )) - - try: - response = httpPool.request_encode_body("POST", url, fields=data, retries=0) - except Exception, e: - LOG.error("Remote host not reachable") - LOG.error ("Exception: %s" %(e,)) - return - - if response.status == STATUS_CODE_OK: - LOG.info("Data sent successfully to rest server") - return True - else: - LOG.error("Server returned errorcode: %s" %(response.status,)) - return False - - -def sendNotification (type, message): - data = {"msgtype" : type, "text" : message} - - if (type == "information"): - sendDataToRest ("message", data) - else: - sendDataToRest ("notification", data) - -def sendReadOnlyNotification(): - sendNotification("critical", "Filesystem is in read only mode. If you want to export files please initialize an encrypted filesystem.") - -def sendLogNotPossibleNotification(): - sendNotification("critical", "Send log entry to opensecurity rest server failed.") - -def sendFileLog(filename, filesize, filehash, hashtype): - data = {"filename" : filename, "filesize" : "%s" %(filesize,), "filehash" : filehash, "hashtype" : hashtype} - retval = sendDataToRest ("log", data) - if (retval == False): - sendLogNotPossibleNotification() - -def calcMD5 (path, block_size=256*128, hr=True): - md5 = hashlib.md5() - with open(path,'rb') as f: - for chunk in iter(lambda: f.read(block_size), b''): - md5.update(chunk) - if hr: - return md5.hexdigest() - return md5.digest() - -class OsecFS (Fuse): - - __rootpath = None - - # default fuse init - def __init__(self, rootpath, *args, **kw): - self.__rootpath = rootpath - Fuse.__init__ (self, *args, **kw) - LOG.debug ("Init complete.") - sendNotification("information", "Filesystem successfully mounted.") - - # defines that our working directory will be the __rootpath - def fsinit(self): - os.chdir (self.__rootpath) - - def getattr(self, path): - LOG.debug ("*** getattr (%s)" % (fixPath (path))) - return os.lstat (fixPath (path)); - - def getdir(self, path): - LOG.debug ("*** getdir (%s)" % (path)); - return os.listdir (fixPath (path)) - - def readdir(self, path, offset): - LOG.debug ("*** readdir (%s %s)" % (path, offset)); - for e in os.listdir (fixPath (path)): - yield fuse.Direntry(e) - - def chmod (self, path, mode): - LOG.debug ("*** chmod %s %s" % (path, oct(mode))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.chmod (fixPath (path), mode) - - def chown (self, path, uid, gid): - LOG.debug ("*** chown %s %s %s" % (path, uid, gid)) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.chown (fixPath (path), uid, gid) - - def link (self, targetPath, linkPath): - LOG.debug ("*** link %s %s" % (targetPath, linkPath)) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.link (fixPath (targetPath), fixPath (linkPath)) - - def mkdir (self, path, mode): - LOG.debug ("*** mkdir %s %s" % (path, oct(mode))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.mkdir (fixPath (path), mode) - - def mknod (self, path, mode, dev): - LOG.debug ("*** mknod %s %s %s" % (path, oct (mode), dev)) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.mknod (fixPath (path), mode, dev) - - # to implement virus scan - def open (self, path, flags): - LOG.debug ("*** open %s %s" % (path, oct (flags))) - self.file = os.fdopen (os.open (fixPath (path), flags), flag2mode (flags)) - self.written = False - self.fd = self.file.fileno () - - LOG.debug(self.__rootpath) - LOG.debug(path) - - retval = scanFile (rootPath(self.__rootpath, path), self.file) - - #if type(retval) is not dict: - if (isinstance(retval, dict) == False): - LOG.error(SCAN_WRONG_RETURN_VALUE) - self.file.close () - return -errno.EACCES - - if ((retval.has_key("infected") == False) or (retval.has_key("virusname") == False)): - LOG.error(SCAN_RETURN_VALUE_KEY_MISSING) - self.file.close () - return -errno.EACCES - - - if (retval.get("infected") == True): - self.file.close () - sendNotification(NOTIFICATION_CRITICAL, "%s\nFile: %s\nVirus: %s" %(VIRUS_FOUND, path, retval.get("virusname"))) - LOG.error("%s" %(VIRUS_FOUND,)) - LOG.error("Virus: %s" %(retval.get("virusname"),)) - return -errno.EACCES - - whitelisted = whitelistFile (rootPath(self.__rootpath, path)) - if (whitelisted == False): - self.file.close () - sendNotification(NOTIFICATION_CRITICAL, "File not in whitelist. Access denied.") - return -errno.EACCES - - def read (self, path, length, offset): - LOG.debug ("*** read %s %s %s" % (path, length, offset)) - self.file.seek (offset) - return self.file.read (length) - - def readlink (self, path): - LOG.debug ("*** readlink %s" % (path)) - return os.readlink (fixPath (path)) - - def release (self, path, flags): - LOG.debug ("*** release %s %s" % (path, oct (flags))) - self.file.flush() - os.fsync(self.file.fileno()) - self.file.close () - - if (self.written == True): - hashsum = calcMD5(fixPath(path)) - filesize = os.path.getsize(fixPath(path)) - sendFileLog(path, filesize, hashsum, "md5") - - - def rename (self, oldPath, newPath): - LOG.debug ("*** rename %s %s %s" % (oldPath, newPath, config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.rename (fixPath (oldPath), fixPath (newPath)) - - def rmdir (self, path): - LOG.debug ("*** rmdir %s %s" % (path, config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.rmdir (fixPath (path)) - - def statfs (self): - LOG.debug ("*** statfs") - return os.statvfs(".") - - def symlink (self, targetPath, linkPath): - LOG.debug ("*** symlink %s %s %s" % (targetPath, linkPath, config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.symlink (fixPath (targetPath), fixPath (linkPath)) - - def truncate (self, path, length): - LOG.debug ("*** truncate %s %s %s" % (path, length, config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - f = open (fixPath (path), "w+") - f.truncate (length) - f.close () - - def unlink (self, path): - LOG.debug ("*** unlink %s %s" % (path, config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - os.unlink (fixPath (path)) - - def utime (self, path, times): - LOG.debug ("*** utime %s %s" % (path, times)) - os.utime (fixPath (path), times) - - def write (self, path, buf, offset): - #LOG.debug ("*** write %s %s %s %s" % (path, buf, offset, config.get("Main", "ReadOnly"))) - LOG.debug ("*** write %s %s %s %s" % (path, "filecontent", offset, config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - self.file.close() - sendReadOnlyNotification() - return -errno.EACCES - self.file.seek (offset) - self.file.write (buf) - self.written = True - return len (buf) - - def access (self, path, mode): - LOG.debug ("*** access %s %s" % (path, oct (mode))) - if not os.access (fixPath (path), mode): - return -errno.EACCES - - def create (self, path, flags, mode): - LOG.debug ("*** create %s %s %s %s %s" % (fixPath (path), oct (flags), oct (mode), flag2mode (flags), config.get("Main", "ReadOnly"))) - if (config.get("Main", "ReadOnly") == "true"): - sendReadOnlyNotification() - return -errno.EACCES - - self.file = os.fdopen (os.open (fixPath (path), flags), flag2mode(flags)) - self.written = True - self.fd = self.file.fileno () - - -if __name__ == "__main__": - # Set api version - fuse.fuse_python_api = (0, 2) - fuse.feature_assert ('stateful_files', 'has_init') - - config = loadConfig () - initLog (config) - - #sendNotification("Info", "OsecFS started") - - # Import the Malware Scanner - sys.path.append(config.get("Main", "ScannerPath")) - - MalwareModule = import_module(config.get("Main", "ScannerModuleName")) - MalwareClass = getattr(MalwareModule, config.get("Main", "ScannerClassName")) - - MalwareScanner = MalwareClass (config.get("Main", "ScannerConfig")); - - osecfs = OsecFS (config.get ("Main", "Rootpath")) - osecfs.flags = 0 - osecfs.multithreaded = 0 - - fuse_args = [sys.argv[0], config.get ("Main", "Mountpoint")]; - osecfs.main (fuse_args) diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs-package --- a/osecfs-package Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -### Commented entries have reasonable defaults. -### Uncomment to edit them. -# Source: -Section: misc -Priority: optional -# Homepage: -Standards-Version: 3.9.2 - -Package: osecfs -Version: 0.0.26 -Maintainer: ft -# Pre-Depends: -Depends: python,python-requests,python-fuse,python-clamav,python-pyclamav,clamav,python-urllib3,python-netifaces,python-netaddr -# Recommends: -# Suggests: -# Provides: -# Replaces: -Architecture: all -# Copyright: -# Changelog: -# Readme: -# Extra-Files: -Files: osecfs /usr/bin/ - ikarusscanner/IkarusScanner.py /usr/bin/ - clamavscanner/ClamAVScanner.py /usr/bin/ - osecfs_usb.cfg /etc/osecfs/ - osecfs_downloads.cfg /etc/osecfs/ - ClamAVScanner.cfg /etc/osecfs/ - IkarusScanner.cfg /etc/osecfs/ -Description: Mirror Filesystem for Open Security - An Mirror FS which makes virus scanning whitelistening and other things diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs-package.conf --- a/osecfs-package.conf Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -# Original main-package.conf file. -# Do not touch it!! It belongs to dpkg. diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.10_all.deb Binary file osecfs_0.0.10_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.11_all.deb Binary file osecfs_0.0.11_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.12_all.deb Binary file osecfs_0.0.12_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.13_all.deb Binary file osecfs_0.0.13_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.14_all.deb Binary file osecfs_0.0.14_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.15_all.deb Binary file osecfs_0.0.15_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.16_all.deb Binary file osecfs_0.0.16_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.17_all.deb Binary file osecfs_0.0.17_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.18_all.deb Binary file osecfs_0.0.18_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.19_all.deb Binary file osecfs_0.0.19_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.1_all.deb Binary file osecfs_0.0.1_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.20_all.deb Binary file osecfs_0.0.20_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.21_all.deb Binary file osecfs_0.0.21_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.22_all.deb Binary file osecfs_0.0.22_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.23_all.deb Binary file osecfs_0.0.23_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.24_all.deb Binary file osecfs_0.0.24_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.25_all.deb Binary file osecfs_0.0.25_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.26_all.deb Binary file osecfs_0.0.26_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.2_all.deb Binary file osecfs_0.0.2_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.3_all.deb Binary file osecfs_0.0.3_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.4_all.deb Binary file osecfs_0.0.4_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.5_all.deb Binary file osecfs_0.0.5_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.6_all.deb Binary file osecfs_0.0.6_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.7_all.deb Binary file osecfs_0.0.7_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.8_all.deb Binary file osecfs_0.0.8_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_0.0.9_all.deb Binary file osecfs_0.0.9_all.deb has changed diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_downloads.cfg --- a/osecfs_downloads.cfg Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -[Main] -# make sure this file is writeable -Logfile: /var/log/osecfs_downloads.log - -# DEBUG, INFO, WARNING, ERROR, CRITICAL -LogLevel: debug - -# where the files really are on the filesystem -Rootpath: /home/osecuser/Downloads - - - - -# path to scanner class -#ScannerPath: /usr/bin/ikarusscanner/ - -# scanner module name -#ScannerModuleName: IkarusScanner -#ScannerClassName: IkarusScanner - -# config file for scanner (path will be in the constructor) -#ScannerConfig: /etc/osecfs/IkarusScanner.cfg - -# path to scanner class -ScannerPath: /usr/bin/clamavscanner/ - -# scanner module name -ScannerModuleName: ClamAVScanner -ScannerClassName: ClamAVScanner - -# config file for scanner (path will be in the constructor) -ScannerConfig: /etc/osecfs/ClamAVScanner.cfg diff -r 5b9fdcafd0df -r 2422a3542d94 osecfs_usb.cfg --- a/osecfs_usb.cfg Tue Nov 04 16:35:33 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -[Main] -# make sure this file is writeable -Logfile: /var/log/osecfs_usb.log - -# DEBUG, INFO, WARNING, ERROR, CRITICAL -LogLevel: debug - -# where the files really are on the filesystem -Rootpath: /media/usb0 - - - - -# path to scanner class -#ScannerPath: /usr/bin/ikarusscanner/ - -# scanner module name -#ScannerModuleName: IkarusScanner -#ScannerClassName: IkarusScanner - -# config file for scanner (path will be in the constructor) -#ScannerConfig: /etc/osecfs/IkarusScanner.cfg - -# path to scanner class -ScannerPath: /usr/bin/clamavscanner/ - -# scanner module name -ScannerModuleName: ClamAVScanner -ScannerClassName: ClamAVScanner - -# config file for scanner (path will be in the constructor) -ScannerConfig: /etc/osecfs/ClamAVScanner.cfg