1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/Apache License, Version 2.0.txt Tue Nov 04 17:44:32 2014 +0100
1.3 @@ -0,0 +1,202 @@
1.4 +
1.5 + Apache License
1.6 + Version 2.0, January 2004
1.7 + http://www.apache.org/licenses/
1.8 +
1.9 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1.10 +
1.11 + 1. Definitions.
1.12 +
1.13 + "License" shall mean the terms and conditions for use, reproduction,
1.14 + and distribution as defined by Sections 1 through 9 of this document.
1.15 +
1.16 + "Licensor" shall mean the copyright owner or entity authorized by
1.17 + the copyright owner that is granting the License.
1.18 +
1.19 + "Legal Entity" shall mean the union of the acting entity and all
1.20 + other entities that control, are controlled by, or are under common
1.21 + control with that entity. For the purposes of this definition,
1.22 + "control" means (i) the power, direct or indirect, to cause the
1.23 + direction or management of such entity, whether by contract or
1.24 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
1.25 + outstanding shares, or (iii) beneficial ownership of such entity.
1.26 +
1.27 + "You" (or "Your") shall mean an individual or Legal Entity
1.28 + exercising permissions granted by this License.
1.29 +
1.30 + "Source" form shall mean the preferred form for making modifications,
1.31 + including but not limited to software source code, documentation
1.32 + source, and configuration files.
1.33 +
1.34 + "Object" form shall mean any form resulting from mechanical
1.35 + transformation or translation of a Source form, including but
1.36 + not limited to compiled object code, generated documentation,
1.37 + and conversions to other media types.
1.38 +
1.39 + "Work" shall mean the work of authorship, whether in Source or
1.40 + Object form, made available under the License, as indicated by a
1.41 + copyright notice that is included in or attached to the work
1.42 + (an example is provided in the Appendix below).
1.43 +
1.44 + "Derivative Works" shall mean any work, whether in Source or Object
1.45 + form, that is based on (or derived from) the Work and for which the
1.46 + editorial revisions, annotations, elaborations, or other modifications
1.47 + represent, as a whole, an original work of authorship. For the purposes
1.48 + of this License, Derivative Works shall not include works that remain
1.49 + separable from, or merely link (or bind by name) to the interfaces of,
1.50 + the Work and Derivative Works thereof.
1.51 +
1.52 + "Contribution" shall mean any work of authorship, including
1.53 + the original version of the Work and any modifications or additions
1.54 + to that Work or Derivative Works thereof, that is intentionally
1.55 + submitted to Licensor for inclusion in the Work by the copyright owner
1.56 + or by an individual or Legal Entity authorized to submit on behalf of
1.57 + the copyright owner. For the purposes of this definition, "submitted"
1.58 + means any form of electronic, verbal, or written communication sent
1.59 + to the Licensor or its representatives, including but not limited to
1.60 + communication on electronic mailing lists, source code control systems,
1.61 + and issue tracking systems that are managed by, or on behalf of, the
1.62 + Licensor for the purpose of discussing and improving the Work, but
1.63 + excluding communication that is conspicuously marked or otherwise
1.64 + designated in writing by the copyright owner as "Not a Contribution."
1.65 +
1.66 + "Contributor" shall mean Licensor and any individual or Legal Entity
1.67 + on behalf of whom a Contribution has been received by Licensor and
1.68 + subsequently incorporated within the Work.
1.69 +
1.70 + 2. Grant of Copyright License. Subject to the terms and conditions of
1.71 + this License, each Contributor hereby grants to You a perpetual,
1.72 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
1.73 + copyright license to reproduce, prepare Derivative Works of,
1.74 + publicly display, publicly perform, sublicense, and distribute the
1.75 + Work and such Derivative Works in Source or Object form.
1.76 +
1.77 + 3. Grant of Patent License. Subject to the terms and conditions of
1.78 + this License, each Contributor hereby grants to You a perpetual,
1.79 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
1.80 + (except as stated in this section) patent license to make, have made,
1.81 + use, offer to sell, sell, import, and otherwise transfer the Work,
1.82 + where such license applies only to those patent claims licensable
1.83 + by such Contributor that are necessarily infringed by their
1.84 + Contribution(s) alone or by combination of their Contribution(s)
1.85 + with the Work to which such Contribution(s) was submitted. If You
1.86 + institute patent litigation against any entity (including a
1.87 + cross-claim or counterclaim in a lawsuit) alleging that the Work
1.88 + or a Contribution incorporated within the Work constitutes direct
1.89 + or contributory patent infringement, then any patent licenses
1.90 + granted to You under this License for that Work shall terminate
1.91 + as of the date such litigation is filed.
1.92 +
1.93 + 4. Redistribution. You may reproduce and distribute copies of the
1.94 + Work or Derivative Works thereof in any medium, with or without
1.95 + modifications, and in Source or Object form, provided that You
1.96 + meet the following conditions:
1.97 +
1.98 + (a) You must give any other recipients of the Work or
1.99 + Derivative Works a copy of this License; and
1.100 +
1.101 + (b) You must cause any modified files to carry prominent notices
1.102 + stating that You changed the files; and
1.103 +
1.104 + (c) You must retain, in the Source form of any Derivative Works
1.105 + that You distribute, all copyright, patent, trademark, and
1.106 + attribution notices from the Source form of the Work,
1.107 + excluding those notices that do not pertain to any part of
1.108 + the Derivative Works; and
1.109 +
1.110 + (d) If the Work includes a "NOTICE" text file as part of its
1.111 + distribution, then any Derivative Works that You distribute must
1.112 + include a readable copy of the attribution notices contained
1.113 + within such NOTICE file, excluding those notices that do not
1.114 + pertain to any part of the Derivative Works, in at least one
1.115 + of the following places: within a NOTICE text file distributed
1.116 + as part of the Derivative Works; within the Source form or
1.117 + documentation, if provided along with the Derivative Works; or,
1.118 + within a display generated by the Derivative Works, if and
1.119 + wherever such third-party notices normally appear. The contents
1.120 + of the NOTICE file are for informational purposes only and
1.121 + do not modify the License. You may add Your own attribution
1.122 + notices within Derivative Works that You distribute, alongside
1.123 + or as an addendum to the NOTICE text from the Work, provided
1.124 + that such additional attribution notices cannot be construed
1.125 + as modifying the License.
1.126 +
1.127 + You may add Your own copyright statement to Your modifications and
1.128 + may provide additional or different license terms and conditions
1.129 + for use, reproduction, or distribution of Your modifications, or
1.130 + for any such Derivative Works as a whole, provided Your use,
1.131 + reproduction, and distribution of the Work otherwise complies with
1.132 + the conditions stated in this License.
1.133 +
1.134 + 5. Submission of Contributions. Unless You explicitly state otherwise,
1.135 + any Contribution intentionally submitted for inclusion in the Work
1.136 + by You to the Licensor shall be under the terms and conditions of
1.137 + this License, without any additional terms or conditions.
1.138 + Notwithstanding the above, nothing herein shall supersede or modify
1.139 + the terms of any separate license agreement you may have executed
1.140 + with Licensor regarding such Contributions.
1.141 +
1.142 + 6. Trademarks. This License does not grant permission to use the trade
1.143 + names, trademarks, service marks, or product names of the Licensor,
1.144 + except as required for reasonable and customary use in describing the
1.145 + origin of the Work and reproducing the content of the NOTICE file.
1.146 +
1.147 + 7. Disclaimer of Warranty. Unless required by applicable law or
1.148 + agreed to in writing, Licensor provides the Work (and each
1.149 + Contributor provides its Contributions) on an "AS IS" BASIS,
1.150 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1.151 + implied, including, without limitation, any warranties or conditions
1.152 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
1.153 + PARTICULAR PURPOSE. You are solely responsible for determining the
1.154 + appropriateness of using or redistributing the Work and assume any
1.155 + risks associated with Your exercise of permissions under this License.
1.156 +
1.157 + 8. Limitation of Liability. In no event and under no legal theory,
1.158 + whether in tort (including negligence), contract, or otherwise,
1.159 + unless required by applicable law (such as deliberate and grossly
1.160 + negligent acts) or agreed to in writing, shall any Contributor be
1.161 + liable to You for damages, including any direct, indirect, special,
1.162 + incidental, or consequential damages of any character arising as a
1.163 + result of this License or out of the use or inability to use the
1.164 + Work (including but not limited to damages for loss of goodwill,
1.165 + work stoppage, computer failure or malfunction, or any and all
1.166 + other commercial damages or losses), even if such Contributor
1.167 + has been advised of the possibility of such damages.
1.168 +
1.169 + 9. Accepting Warranty or Additional Liability. While redistributing
1.170 + the Work or Derivative Works thereof, You may choose to offer,
1.171 + and charge a fee for, acceptance of support, warranty, indemnity,
1.172 + or other liability obligations and/or rights consistent with this
1.173 + License. However, in accepting such obligations, You may act only
1.174 + on Your own behalf and on Your sole responsibility, not on behalf
1.175 + of any other Contributor, and only if You agree to indemnify,
1.176 + defend, and hold each Contributor harmless for any liability
1.177 + incurred by, or claims asserted against, such Contributor by reason
1.178 + of your accepting any such warranty or additional liability.
1.179 +
1.180 + END OF TERMS AND CONDITIONS
1.181 +
1.182 + APPENDIX: How to apply the Apache License to your work.
1.183 +
1.184 + To apply the Apache License to your work, attach the following
1.185 + boilerplate notice, with the fields enclosed by brackets "[]"
1.186 + replaced with your own identifying information. (Don't include
1.187 + the brackets!) The text should be enclosed in the appropriate
1.188 + comment syntax for the file format. We also recommend that a
1.189 + file or class name and description of purpose be included on the
1.190 + same "printed page" as the copyright notice for easier
1.191 + identification within third-party archives.
1.192 +
1.193 + Copyright [yyyy] [name of copyright owner]
1.194 +
1.195 + Licensed under the Apache License, Version 2.0 (the "License");
1.196 + you may not use this file except in compliance with the License.
1.197 + You may obtain a copy of the License at
1.198 +
1.199 + http://www.apache.org/licenses/LICENSE-2.0
1.200 +
1.201 + Unless required by applicable law or agreed to in writing, software
1.202 + distributed under the License is distributed on an "AS IS" BASIS,
1.203 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1.204 + See the License for the specific language governing permissions and
1.205 + limitations under the License.
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/ClamAVScanner.cfg Tue Nov 04 17:44:32 2014 +0100
2.3 @@ -0,0 +1,2 @@
2.4 +[Main]
2.5 +Nothing: placeholder
2.6 \ No newline at end of file
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/IkarusScanner.cfg Tue Nov 04 17:44:32 2014 +0100
3.3 @@ -0,0 +1,12 @@
3.4 +[Main]
3.5 +# the maximum file size in MB that is scanned
3.6 +MaxFileSize: 50
3.7 +
3.8 +# the URL of the local scan server
3.9 +LocalScanserverURL: http://localhost/virusscan
3.10 +
3.11 +# the URL of the remote scan server
3.12 +RemoteScanserverURL: http://10.215.5.166/virusscan
3.13 +
3.14 +# wait time in seconds until a new connection attempt to remote server is made
3.15 +RetryTimeout: 600
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/clamavscanner/ClamAVScanner.py Tue Nov 04 17:44:32 2014 +0100
4.3 @@ -0,0 +1,111 @@
4.4 +#!/usr/bin/python
4.5 +
4.6 +# ------------------------------------------------------------
4.7 +# opensecurity package file
4.8 +#
4.9 +# Autor: X-Net Services GmbH <office@x-net.at>
4.10 +#
4.11 +# Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology
4.12 +#
4.13 +#
4.14 +# X-Net Technologies GmbH
4.15 +# Elisabethstrasse 1
4.16 +# 4020 Linz
4.17 +# AUSTRIA
4.18 +# https://www.x-net.at
4.19 +#
4.20 +# AIT Austrian Institute of Technology
4.21 +# Donau City Strasse 1
4.22 +# 1220 Wien
4.23 +# AUSTRIA
4.24 +# http://www.ait.ac.at
4.25 +#
4.26 +#
4.27 +# Licensed under the Apache License, Version 2.0 (the "License");
4.28 +# you may not use this file except in compliance with the License.
4.29 +# You may obtain a copy of the License at
4.30 +#
4.31 +# http://www.apache.org/licenses/LICENSE-2.0
4.32 +#
4.33 +# Unless required by applicable law or agreed to in writing, software
4.34 +# distributed under the License is distributed on an "AS IS" BASIS,
4.35 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4.36 +# See the License for the specific language governing permissions and
4.37 +# limitations under the License.
4.38 +# ------------------------------------------------------------
4.39 +
4.40 +import ConfigParser
4.41 +
4.42 +import sys
4.43 +
4.44 +import logging
4.45 +import os
4.46 +import errno
4.47 +import time
4.48 +
4.49 +import pyclamav
4.50 +
4.51 +
4.52 +class ClamAVScanner:
4.53 +
4.54 + # User the existing logger instance
4.55 + __LOG = logging.getLogger("IkarusScanner")
4.56 +
4.57 + __MINOPTS = { "Main" : ["Nothing"]}
4.58 + __CONFIG_NOT_READABLE = "Configfile is not readable"
4.59 + __CONFIG_WRONG = "Something is wrong with the config"
4.60 + __CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing"
4.61 +
4.62 +
4.63 +
4.64 + def __init__ (self, scanner_config_path):
4.65 + config = self.loadConfig (scanner_config_path)
4.66 +
4.67 +
4.68 +
4.69 + def checkMinimumOptions (self, config):
4.70 + for section, options in self.__MINOPTS.iteritems ():
4.71 + for option in options:
4.72 + if (config.has_option(section, option) == False):
4.73 + self.__LOG.error (self.__CONFIG_MISSING % (section, option))
4.74 + exit (129)
4.75 +
4.76 + def loadConfig (self, scanner_config_path):
4.77 +
4.78 + configfile = scanner_config_path
4.79 + config = ConfigParser.SafeConfigParser ()
4.80 +
4.81 + 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)):
4.82 + self.__LOG.error(self.__CONFIG_NOT_READABLE);
4.83 + raise SystemError(self.__CONFIG_NOT_READABLE)
4.84 +
4.85 + try:
4.86 + config.read (scanner_config_path)
4.87 + except Exception, e:
4.88 + self.__LOG.error("Error: %s" % (e));
4.89 + raise SystemError("Error: %s" % (e))
4.90 +
4.91 + self.checkMinimumOptions (config)
4.92 +
4.93 + return config
4.94 +
4.95 +
4.96 + def scanFile (self, path, fileobject):
4.97 + return self.scanFileClamAV (path)
4.98 +
4.99 + def scanFileClamAV (self, path):
4.100 + retval = { "infected" : False, "virusname" : "Unknown" }
4.101 +
4.102 + self.__LOG.debug ("Scan File: %s" % (path))
4.103 +
4.104 + result = pyclamav.scanfile (path)
4.105 + self.__LOG.debug ("Result of file \"%s\": %s" % (path, result))
4.106 + if (result[0] != 0):
4.107 + retval["infected"] = True
4.108 + retval["virusname"] = result[1]
4.109 +
4.110 + if (retval["infected"] == True):
4.111 + self.__LOG.error ("Virus found, deny Access %s" % (result,))
4.112 +
4.113 + return retval
4.114 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/ikarusscanner/IkarusScanner.py Tue Nov 04 17:44:32 2014 +0100
5.3 @@ -0,0 +1,185 @@
5.4 +#!/usr/bin/python
5.5 +
5.6 +# ------------------------------------------------------------
5.7 +# opensecurity package file
5.8 +#
5.9 +# Autor: Karlberger Christoph <Karlberger.C@ikarus.at>
5.10 +# X-Net Services GmbH <office@x-net.at>
5.11 +#
5.12 +# Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology
5.13 +#
5.14 +# IKARUS Security Software GmbH
5.15 +# Blechturmgasse 11
5.16 +# 1050 Wien
5.17 +# AUSTRIA
5.18 +# http://www.ikarussecurity.com
5.19 +#
5.20 +# X-Net Technologies GmbH
5.21 +# Elisabethstrasse 1
5.22 +# 4020 Linz
5.23 +# AUSTRIA
5.24 +# https://www.x-net.at
5.25 +#
5.26 +# AIT Austrian Institute of Technology
5.27 +# Donau City Strasse 1
5.28 +# 1220 Wien
5.29 +# AUSTRIA
5.30 +# http://www.ait.ac.at
5.31 +#
5.32 +#
5.33 +# Licensed under the Apache License, Version 2.0 (the "License");
5.34 +# you may not use this file except in compliance with the License.
5.35 +# You may obtain a copy of the License at
5.36 +#
5.37 +# http://www.apache.org/licenses/LICENSE-2.0
5.38 +#
5.39 +# Unless required by applicable law or agreed to in writing, software
5.40 +# distributed under the License is distributed on an "AS IS" BASIS,
5.41 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5.42 +# See the License for the specific language governing permissions and
5.43 +# limitations under the License.
5.44 +# ------------------------------------------------------------
5.45 +
5.46 +import ConfigParser
5.47 +
5.48 +import sys
5.49 +
5.50 +import logging
5.51 +import os
5.52 +import errno
5.53 +import time
5.54 +
5.55 +import urllib3
5.56 +import xml.etree.ElementTree as ET
5.57 +
5.58 +class IkarusScanner:
5.59 +
5.60 + # User the existing logger instance
5.61 + __LOG = logging.getLogger("IkarusScanner")
5.62 +
5.63 + __MINOPTS = { "Main" : ["LocalScanserverURL", "RemoteScanserverURL", "MaxFileSize", "RetryTimeout"]}
5.64 + __CONFIG_NOT_READABLE = "Configfile is not readable"
5.65 + __CONFIG_WRONG = "Something is wrong with the config"
5.66 + __CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing"
5.67 + __LOCAL_SCANSERVER_URL = ""
5.68 + __REMOTE_SCANSERVER_URL = ""
5.69 + __STATUS_CODE_OK = 200
5.70 + __STATUS_CODE_INFECTED = 210
5.71 + __STATUS_CODE_NOT_FOUND = 404
5.72 + __MAX_SCAN_FILE_SIZE = 50 * 0x100000
5.73 + __SCANSERVER_RETRY_TIMEOUT = 60
5.74 +
5.75 + # Global http pool manager used to connect to the scan server
5.76 + __remoteScanserverReachable = True
5.77 + __scanserverTimestamp = 0
5.78 + __httpPool = urllib3.PoolManager(num_pools = 1, timeout = 3)
5.79 +
5.80 + def __init__ (self, scanner_config_path):
5.81 + config = self.loadConfig (scanner_config_path)
5.82 +
5.83 + self.__scanserverTimestamp = time.time()
5.84 +
5.85 + self.__LOCAL_SCANSERVER_URL = config.get("Main", "LocalScanserverURL")
5.86 + self.__REMOTE_SCANSERVER_URL = config.get("Main", "RemoteScanserverURL")
5.87 + self.__SCANSERVER_RETRY_TIMEOUT = int(config.get("Main", "RetryTimeout"))
5.88 +
5.89 + # Convert file size from MB to byte
5.90 + self.__MAX_SCAN_FILE_SIZE = int(config.get("Main", "MaxFileSize")) * 0x100000
5.91 +
5.92 +
5.93 + def checkMinimumOptions (self, config):
5.94 + for section, options in self.__MINOPTS.iteritems ():
5.95 + for option in options:
5.96 + if (config.has_option(section, option) == False):
5.97 + self.__LOG.error (self.__CONFIG_MISSING % (section, option))
5.98 + exit (129)
5.99 +
5.100 + def loadConfig (self, scanner_config_path):
5.101 +
5.102 + configfile = scanner_config_path
5.103 + config = ConfigParser.SafeConfigParser ()
5.104 +
5.105 + 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)):
5.106 + self.__LOG.error(self.__CONFIG_NOT_READABLE);
5.107 + raise SystemError(self.__CONFIG_NOT_READABLE)
5.108 +
5.109 + try:
5.110 + config.read (scanner_config_path)
5.111 + except Exception, e:
5.112 + self.__LOG.error("Error: %s" % (e));
5.113 + raise SystemError("Error: %s" % (e))
5.114 +
5.115 + self.checkMinimumOptions (config)
5.116 +
5.117 + return config
5.118 +
5.119 + def contactScanserver(self, url, fields):
5.120 + self.__LOG.debug("Contacting server %s" % url)
5.121 + return self.__httpPool.request_encode_body('POST', url, fields = fields, retries = 0)
5.122 +
5.123 + def scanFile (self, path, fileobject):
5.124 + return self.scanFileIkarus (path, fileobject)
5.125 +
5.126 + def scanFileIkarus (self, path, fileobject):
5.127 + retval = { "infected" : False, "virusname" : "Unknown" }
5.128 + self.__LOG.debug ("Scan File: %s" % (path))
5.129 +
5.130 + if (os.fstat(fileobject.fileno()).st_size > self.__MAX_SCAN_FILE_SIZE):
5.131 + self.__LOG.info("File max size exceeded. The file is not scanned.")
5.132 + retval["infected"] = False
5.133 + retval["virusname"] = "File is to big to be scanned."
5.134 + return retval
5.135 +
5.136 + fields = { 'up_file' : fileobject.read() }
5.137 +
5.138 + if (self.__remoteScanserverReachable == False) and ((self.__scanserverTimestamp + self.__SCANSERVER_RETRY_TIMEOUT) < time.time()):
5.139 + self.__remoteScanserverReachable = True
5.140 +
5.141 + if self.__remoteScanserverReachable:
5.142 + try:
5.143 + response = self.contactScanserver(self.__REMOTE_SCANSERVER_URL, fields)
5.144 + # We should catch socket.error here, but this does not work. Needs checking.
5.145 + except:
5.146 + self.__LOG.info("Remote scan server unreachable, using local scan server.")
5.147 + self.__LOG.debug("Exception: %s: %s" % (sys.exc_info()[0], sys.exc_info()[1]))
5.148 + self.__LOG.info("Next check for remote server in %s seconds." % (self.__SCANSERVER_RETRY_TIMEOUT))
5.149 +
5.150 + self.__remoteScanserverReachable = False
5.151 + self.__scanserverTimestamp = time.time()
5.152 +
5.153 + try:
5.154 + response = self.contactScanserver(self.__LOCAL_SCANSERVER_URL, fields)
5.155 + except:
5.156 + self.__LOG.error ("Connection to local scan server could not be established.")
5.157 + self.__LOG.debug ("Exception: %s" % (sys.exc_info()[0]))
5.158 + return retval
5.159 + else:
5.160 + try:
5.161 + response = self.contactScanserver(self.__LOCAL_SCANSERVER_URL, fields)
5.162 + except:
5.163 + self.__LOG.error ("Connection to local scan server could not be established.")
5.164 + self.__LOG.error ("Exception: %s" %(sys.exc_info()[0]))
5.165 + return retval
5.166 +
5.167 +
5.168 + if response.status == self.__STATUS_CODE_OK:
5.169 + retval["infected"] = False
5.170 + elif response.status == self.__STATUS_CODE_INFECTED:
5.171 + # Parse xml for info
5.172 + root = ET.fromstring(response.data)
5.173 +
5.174 + # this should be done in a more generic way
5.175 + retval["virusname"] = root[1][3][0].text
5.176 + retval["infected"] = True
5.177 + else:
5.178 + self.__LOG.error ("Connection error to scan server.")
5.179 +
5.180 + if (retval["infected"] == True):
5.181 + self.__LOG.error ("Virus found, denying access.")
5.182 + else:
5.183 + self.__LOG.debug ("No virus found.")
5.184 +
5.185 + return retval
5.186 +
5.187 +
5.188 +
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/osecfs Tue Nov 04 17:44:32 2014 +0100
6.3 @@ -0,0 +1,471 @@
6.4 +#!/usr/bin/python
6.5 +
6.6 +# ------------------------------------------------------------
6.7 +# opensecurity package file
6.8 +#
6.9 +# Autor: X-Net Services GmbH <office@x-net.at>
6.10 +#
6.11 +# Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology
6.12 +#
6.13 +#
6.14 +# X-Net Technologies GmbH
6.15 +# Elisabethstrasse 1
6.16 +# 4020 Linz
6.17 +# AUSTRIA
6.18 +# https://www.x-net.at
6.19 +#
6.20 +# AIT Austrian Institute of Technology
6.21 +# Donau City Strasse 1
6.22 +# 1220 Wien
6.23 +# AUSTRIA
6.24 +# http://www.ait.ac.at
6.25 +#
6.26 +#
6.27 +# Licensed under the Apache License, Version 2.0 (the "License");
6.28 +# you may not use this file except in compliance with the License.
6.29 +# You may obtain a copy of the License at
6.30 +#
6.31 +# http://www.apache.org/licenses/LICENSE-2.0
6.32 +#
6.33 +# Unless required by applicable law or agreed to in writing, software
6.34 +# distributed under the License is distributed on an "AS IS" BASIS,
6.35 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6.36 +# See the License for the specific language governing permissions and
6.37 +# limitations under the License.
6.38 +# ------------------------------------------------------------
6.39 +
6.40 +
6.41 +from fuse import Fuse
6.42 +import fuse
6.43 +
6.44 +import ConfigParser
6.45 +
6.46 +import sys
6.47 +
6.48 +import logging
6.49 +import os
6.50 +import errno
6.51 +import time
6.52 +
6.53 +from importlib import import_module
6.54 +
6.55 +
6.56 +import subprocess
6.57 +
6.58 +import urllib3
6.59 +import netifaces
6.60 +import netaddr
6.61 +import hashlib
6.62 +
6.63 +
6.64 +sys.stderr = open('/var/log/osecfs_error.log', 'a+')
6.65 +
6.66 +
6.67 +MINOPTS = { "Main" : ["Logfile", "LogLevel", "Mountpoint", "Rootpath", "ScannerPath", "ScannerModuleName", "ScannerClassName", "ScannerConfig", "ReadOnly"]}
6.68 +
6.69 +CONFIG_NOT_READABLE = "Configfile is not readable"
6.70 +CONFIG_WRONG = "Something is wrong with the config"
6.71 +CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing"
6.72 +SCAN_WRONG_RETURN_VALUE = "The return Value of the malware scanner is wrong. Has to be an dictionary"
6.73 +SCAN_RETURN_VALUE_KEY_MISSING = "The dictionary has to include key \"infected\" (True, False) and \"virusname\" (String)"
6.74 +VIRUS_FOUND = "Virus found. Access denied"
6.75 +NOTIFICATION_CRITICAL = "critical"
6.76 +NOTIFICATION_INFO = "info"
6.77 +LOG = None
6.78 +MalwareScanner = None
6.79 +STATUS_CODE_OK = 200
6.80 +
6.81 +SYSTEM_FILE_COMMAND = "file"
6.82 +httpPool = urllib3.PoolManager(num_pools = 1, timeout = 3)
6.83 +
6.84 +def checkMinimumOptions (config):
6.85 + for section, options in MINOPTS.iteritems ():
6.86 + for option in options:
6.87 + if (config.has_option(section, option) == False):
6.88 + print (CONFIG_MISSING % (section, option))
6.89 + exit (129)
6.90 +
6.91 +def printUsage ():
6.92 + print ("Usage:")
6.93 + print ("%s configfile mountpath ro/rw" % (sys.argv[0]))
6.94 + exit (128)
6.95 +
6.96 +def loadConfig ():
6.97 + print ("load config")
6.98 +
6.99 + if (len (sys.argv) < 4):
6.100 + printUsage ()
6.101 +
6.102 + configfile = sys.argv[1]
6.103 + config = ConfigParser.SafeConfigParser ()
6.104 +
6.105 + if ((os.path.exists (configfile) == False) or (os.path.isfile (configfile) == False) or (os.access (configfile, os.R_OK) == False)):
6.106 + print (CONFIG_NOT_READABLE)
6.107 + printUsage ()
6.108 +
6.109 + try:
6.110 + config.read (sys.argv[1])
6.111 + except Exception, e:
6.112 + print (CONFIG_WRONG)
6.113 + print ("Error: %s" % (e))
6.114 +
6.115 +
6.116 + config.set("Main", "Mountpoint", sys.argv[2])
6.117 + if (sys.argv[3] == "rw"):
6.118 + config.set("Main", "ReadOnly", "false")
6.119 + else:
6.120 + config.set("Main", "ReadOnly", "true")
6.121 +
6.122 + checkMinimumOptions (config)
6.123 +
6.124 + return config
6.125 +
6.126 +def initLog (config):
6.127 + print ("init log")
6.128 +
6.129 + global LOG
6.130 + logfile = config.get("Main", "Logfile")
6.131 +
6.132 + numeric_level = getattr(logging, config.get("Main", "LogLevel").upper(), None)
6.133 + if not isinstance(numeric_level, int):
6.134 + raise ValueError('Invalid log level: %s' % loglevel)
6.135 +
6.136 + # ToDo move log level and maybe other things to config file
6.137 + logging.basicConfig(
6.138 + level = numeric_level,
6.139 + format = "%(asctime)s %(name)-12s %(funcName)-15s %(levelname)-8s %(message)s",
6.140 + datefmt = "%Y-%m-%d %H:%M:%S",
6.141 + filename = logfile,
6.142 + filemode = "a+",
6.143 + )
6.144 + LOG = logging.getLogger("fuse_main")
6.145 +
6.146 +
6.147 +def fixPath (path):
6.148 + return ".%s" % (path)
6.149 +
6.150 +def rootPath (rootpath, path):
6.151 + return "%s%s" % (rootpath, path)
6.152 +
6.153 +def flag2mode (flags):
6.154 + md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
6.155 + m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)]
6.156 +
6.157 + # windows sets append even if it would overwrite the whole file (seek 0)
6.158 + # so ignore append option
6.159 + #if flags | os.O_APPEND:
6.160 + # m = m.replace('w', 'a', 1)
6.161 +
6.162 + return m
6.163 +
6.164 +def scanFile (path, fileobject):
6.165 + LOG.debug ("Scan File \"%s\" with malware Scanner" %(path,) )
6.166 + return MalwareScanner.scanFile (path, fileobject)
6.167 +
6.168 +
6.169 +def scanFileClamAV (path):
6.170 + infected = False
6.171 +
6.172 + LOG.debug ("Scan File: %s" % (path))
6.173 +
6.174 + result = pyclamav.scanfile (path)
6.175 + LOG.debug ("Result of file \"%s\": %s" % (path, result))
6.176 + if (result[0] != 0):
6.177 + infected = True
6.178 +
6.179 + if (infected == True):
6.180 + LOG.error ("Virus found, deny Access %s" % (result,))
6.181 +
6.182 + return infected
6.183 +
6.184 +def whitelistFile (path):
6.185 + whitelisted = False;
6.186 +
6.187 + LOG.debug ("Execute \"%s\" command on \"%s\"" %(SYSTEM_FILE_COMMAND, path))
6.188 +
6.189 + result = None
6.190 + try:
6.191 + result = subprocess.check_output ([SYSTEM_FILE_COMMAND, path]);
6.192 + # ToDo replace with real whitelist
6.193 + whitelisted = True
6.194 + except Exception as e:
6.195 + LOG.error ("Call returns with an error!")
6.196 + LOG.error (e)
6.197 +
6.198 + LOG.debug ("Type: %s" %(result))
6.199 +
6.200 + return whitelisted
6.201 +
6.202 +def sendDataToRest (urlpath, data):
6.203 + netifaces.ifaddresses("eth0")[2][0]["addr"]
6.204 +
6.205 + # Get first address in network (0 = network ip -> 192.168.0.0)
6.206 + remote_ip = netaddr.IPNetwork("%s/%s" %(netifaces.ifaddresses("eth0")[2][0]["addr"], netifaces.ifaddresses("eth0")[2][0]["netmask"]))[1]
6.207 +
6.208 + url = ("http://%s:8090//%s" %(remote_ip, urlpath))
6.209 +
6.210 + LOG.debug ("Send data to \"%s\"" %(url, ))
6.211 + LOG.debug ("Data: %s" %(data, ))
6.212 +
6.213 + try:
6.214 + response = httpPool.request_encode_body("POST", url, fields=data, retries=0)
6.215 + except Exception, e:
6.216 + LOG.error("Remote host not reachable")
6.217 + LOG.error ("Exception: %s" %(e,))
6.218 + return
6.219 +
6.220 + if response.status == STATUS_CODE_OK:
6.221 + LOG.info("Data sent successfully to rest server")
6.222 + return True
6.223 + else:
6.224 + LOG.error("Server returned errorcode: %s" %(response.status,))
6.225 + return False
6.226 +
6.227 +
6.228 +def sendNotification (type, message):
6.229 + data = {"msgtype" : type, "text" : message}
6.230 +
6.231 + if (type == "information"):
6.232 + sendDataToRest ("message", data)
6.233 + else:
6.234 + sendDataToRest ("notification", data)
6.235 +
6.236 +def sendReadOnlyNotification():
6.237 + sendNotification("critical", "Filesystem is in read only mode. If you want to export files please initialize an encrypted filesystem.")
6.238 +
6.239 +def sendLogNotPossibleNotification():
6.240 + sendNotification("critical", "Send log entry to opensecurity rest server failed.")
6.241 +
6.242 +def sendFileLog(filename, filesize, filehash, hashtype):
6.243 + data = {"filename" : filename, "filesize" : "%s" %(filesize,), "filehash" : filehash, "hashtype" : hashtype}
6.244 + retval = sendDataToRest ("log", data)
6.245 + if (retval == False):
6.246 + sendLogNotPossibleNotification()
6.247 +
6.248 +def calcMD5 (path, block_size=256*128, hr=True):
6.249 + md5 = hashlib.md5()
6.250 + with open(path,'rb') as f:
6.251 + for chunk in iter(lambda: f.read(block_size), b''):
6.252 + md5.update(chunk)
6.253 + if hr:
6.254 + return md5.hexdigest()
6.255 + return md5.digest()
6.256 +
6.257 +class OsecFS (Fuse):
6.258 +
6.259 + __rootpath = None
6.260 +
6.261 + # default fuse init
6.262 + def __init__(self, rootpath, *args, **kw):
6.263 + self.__rootpath = rootpath
6.264 + Fuse.__init__ (self, *args, **kw)
6.265 + LOG.debug ("Init complete.")
6.266 + sendNotification("information", "Filesystem successfully mounted.")
6.267 +
6.268 + # defines that our working directory will be the __rootpath
6.269 + def fsinit(self):
6.270 + os.chdir (self.__rootpath)
6.271 +
6.272 + def getattr(self, path):
6.273 + LOG.debug ("*** getattr (%s)" % (fixPath (path)))
6.274 + return os.lstat (fixPath (path));
6.275 +
6.276 + def getdir(self, path):
6.277 + LOG.debug ("*** getdir (%s)" % (path));
6.278 + return os.listdir (fixPath (path))
6.279 +
6.280 + def readdir(self, path, offset):
6.281 + LOG.debug ("*** readdir (%s %s)" % (path, offset));
6.282 + for e in os.listdir (fixPath (path)):
6.283 + yield fuse.Direntry(e)
6.284 +
6.285 + def chmod (self, path, mode):
6.286 + LOG.debug ("*** chmod %s %s" % (path, oct(mode)))
6.287 + if (config.get("Main", "ReadOnly") == "true"):
6.288 + sendReadOnlyNotification()
6.289 + return -errno.EACCES
6.290 + os.chmod (fixPath (path), mode)
6.291 +
6.292 + def chown (self, path, uid, gid):
6.293 + LOG.debug ("*** chown %s %s %s" % (path, uid, gid))
6.294 + if (config.get("Main", "ReadOnly") == "true"):
6.295 + sendReadOnlyNotification()
6.296 + return -errno.EACCES
6.297 + os.chown (fixPath (path), uid, gid)
6.298 +
6.299 + def link (self, targetPath, linkPath):
6.300 + LOG.debug ("*** link %s %s" % (targetPath, linkPath))
6.301 + if (config.get("Main", "ReadOnly") == "true"):
6.302 + sendReadOnlyNotification()
6.303 + return -errno.EACCES
6.304 + os.link (fixPath (targetPath), fixPath (linkPath))
6.305 +
6.306 + def mkdir (self, path, mode):
6.307 + LOG.debug ("*** mkdir %s %s" % (path, oct(mode)))
6.308 + if (config.get("Main", "ReadOnly") == "true"):
6.309 + sendReadOnlyNotification()
6.310 + return -errno.EACCES
6.311 + os.mkdir (fixPath (path), mode)
6.312 +
6.313 + def mknod (self, path, mode, dev):
6.314 + LOG.debug ("*** mknod %s %s %s" % (path, oct (mode), dev))
6.315 + if (config.get("Main", "ReadOnly") == "true"):
6.316 + sendReadOnlyNotification()
6.317 + return -errno.EACCES
6.318 + os.mknod (fixPath (path), mode, dev)
6.319 +
6.320 + # to implement virus scan
6.321 + def open (self, path, flags):
6.322 + LOG.debug ("*** open %s %s" % (path, oct (flags)))
6.323 + self.file = os.fdopen (os.open (fixPath (path), flags), flag2mode (flags))
6.324 + self.written = False
6.325 + self.fd = self.file.fileno ()
6.326 +
6.327 + LOG.debug(self.__rootpath)
6.328 + LOG.debug(path)
6.329 +
6.330 + retval = scanFile (rootPath(self.__rootpath, path), self.file)
6.331 +
6.332 + #if type(retval) is not dict:
6.333 + if (isinstance(retval, dict) == False):
6.334 + LOG.error(SCAN_WRONG_RETURN_VALUE)
6.335 + self.file.close ()
6.336 + return -errno.EACCES
6.337 +
6.338 + if ((retval.has_key("infected") == False) or (retval.has_key("virusname") == False)):
6.339 + LOG.error(SCAN_RETURN_VALUE_KEY_MISSING)
6.340 + self.file.close ()
6.341 + return -errno.EACCES
6.342 +
6.343 +
6.344 + if (retval.get("infected") == True):
6.345 + self.file.close ()
6.346 + sendNotification(NOTIFICATION_CRITICAL, "%s\nFile: %s\nVirus: %s" %(VIRUS_FOUND, path, retval.get("virusname")))
6.347 + LOG.error("%s" %(VIRUS_FOUND,))
6.348 + LOG.error("Virus: %s" %(retval.get("virusname"),))
6.349 + return -errno.EACCES
6.350 +
6.351 + whitelisted = whitelistFile (rootPath(self.__rootpath, path))
6.352 + if (whitelisted == False):
6.353 + self.file.close ()
6.354 + sendNotification(NOTIFICATION_CRITICAL, "File not in whitelist. Access denied.")
6.355 + return -errno.EACCES
6.356 +
6.357 + def read (self, path, length, offset):
6.358 + LOG.debug ("*** read %s %s %s" % (path, length, offset))
6.359 + self.file.seek (offset)
6.360 + return self.file.read (length)
6.361 +
6.362 + def readlink (self, path):
6.363 + LOG.debug ("*** readlink %s" % (path))
6.364 + return os.readlink (fixPath (path))
6.365 +
6.366 + def release (self, path, flags):
6.367 + LOG.debug ("*** release %s %s" % (path, oct (flags)))
6.368 + self.file.flush()
6.369 + os.fsync(self.file.fileno())
6.370 + self.file.close ()
6.371 +
6.372 + if (self.written == True):
6.373 + hashsum = calcMD5(fixPath(path))
6.374 + filesize = os.path.getsize(fixPath(path))
6.375 + sendFileLog(path, filesize, hashsum, "md5")
6.376 +
6.377 +
6.378 + def rename (self, oldPath, newPath):
6.379 + LOG.debug ("*** rename %s %s %s" % (oldPath, newPath, config.get("Main", "ReadOnly")))
6.380 + if (config.get("Main", "ReadOnly") == "true"):
6.381 + sendReadOnlyNotification()
6.382 + return -errno.EACCES
6.383 + os.rename (fixPath (oldPath), fixPath (newPath))
6.384 +
6.385 + def rmdir (self, path):
6.386 + LOG.debug ("*** rmdir %s %s" % (path, config.get("Main", "ReadOnly")))
6.387 + if (config.get("Main", "ReadOnly") == "true"):
6.388 + sendReadOnlyNotification()
6.389 + return -errno.EACCES
6.390 + os.rmdir (fixPath (path))
6.391 +
6.392 + def statfs (self):
6.393 + LOG.debug ("*** statfs")
6.394 + return os.statvfs(".")
6.395 +
6.396 + def symlink (self, targetPath, linkPath):
6.397 + LOG.debug ("*** symlink %s %s %s" % (targetPath, linkPath, config.get("Main", "ReadOnly")))
6.398 + if (config.get("Main", "ReadOnly") == "true"):
6.399 + sendReadOnlyNotification()
6.400 + return -errno.EACCES
6.401 + os.symlink (fixPath (targetPath), fixPath (linkPath))
6.402 +
6.403 + def truncate (self, path, length):
6.404 + LOG.debug ("*** truncate %s %s %s" % (path, length, config.get("Main", "ReadOnly")))
6.405 + if (config.get("Main", "ReadOnly") == "true"):
6.406 + sendReadOnlyNotification()
6.407 + return -errno.EACCES
6.408 + f = open (fixPath (path), "w+")
6.409 + f.truncate (length)
6.410 + f.close ()
6.411 +
6.412 + def unlink (self, path):
6.413 + LOG.debug ("*** unlink %s %s" % (path, config.get("Main", "ReadOnly")))
6.414 + if (config.get("Main", "ReadOnly") == "true"):
6.415 + sendReadOnlyNotification()
6.416 + return -errno.EACCES
6.417 + os.unlink (fixPath (path))
6.418 +
6.419 + def utime (self, path, times):
6.420 + LOG.debug ("*** utime %s %s" % (path, times))
6.421 + os.utime (fixPath (path), times)
6.422 +
6.423 + def write (self, path, buf, offset):
6.424 + #LOG.debug ("*** write %s %s %s %s" % (path, buf, offset, config.get("Main", "ReadOnly")))
6.425 + LOG.debug ("*** write %s %s %s %s" % (path, "filecontent", offset, config.get("Main", "ReadOnly")))
6.426 + if (config.get("Main", "ReadOnly") == "true"):
6.427 + self.file.close()
6.428 + sendReadOnlyNotification()
6.429 + return -errno.EACCES
6.430 + self.file.seek (offset)
6.431 + self.file.write (buf)
6.432 + self.written = True
6.433 + return len (buf)
6.434 +
6.435 + def access (self, path, mode):
6.436 + LOG.debug ("*** access %s %s" % (path, oct (mode)))
6.437 + if not os.access (fixPath (path), mode):
6.438 + return -errno.EACCES
6.439 +
6.440 + def create (self, path, flags, mode):
6.441 + LOG.debug ("*** create %s %s %s %s %s" % (fixPath (path), oct (flags), oct (mode), flag2mode (flags), config.get("Main", "ReadOnly")))
6.442 + if (config.get("Main", "ReadOnly") == "true"):
6.443 + sendReadOnlyNotification()
6.444 + return -errno.EACCES
6.445 +
6.446 + self.file = os.fdopen (os.open (fixPath (path), flags), flag2mode(flags))
6.447 + self.written = True
6.448 + self.fd = self.file.fileno ()
6.449 +
6.450 +
6.451 +if __name__ == "__main__":
6.452 + # Set api version
6.453 + fuse.fuse_python_api = (0, 2)
6.454 + fuse.feature_assert ('stateful_files', 'has_init')
6.455 +
6.456 + config = loadConfig ()
6.457 + initLog (config)
6.458 +
6.459 + #sendNotification("Info", "OsecFS started")
6.460 +
6.461 + # Import the Malware Scanner
6.462 + sys.path.append(config.get("Main", "ScannerPath"))
6.463 +
6.464 + MalwareModule = import_module(config.get("Main", "ScannerModuleName"))
6.465 + MalwareClass = getattr(MalwareModule, config.get("Main", "ScannerClassName"))
6.466 +
6.467 + MalwareScanner = MalwareClass (config.get("Main", "ScannerConfig"));
6.468 +
6.469 + osecfs = OsecFS (config.get ("Main", "Rootpath"))
6.470 + osecfs.flags = 0
6.471 + osecfs.multithreaded = 0
6.472 +
6.473 + fuse_args = [sys.argv[0], config.get ("Main", "Mountpoint")];
6.474 + osecfs.main (fuse_args)
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/osecfs-package Tue Nov 04 17:44:32 2014 +0100
7.3 @@ -0,0 +1,31 @@
7.4 +### Commented entries have reasonable defaults.
7.5 +### Uncomment to edit them.
7.6 +# Source: <source package name; defaults to package name>
7.7 +Section: misc
7.8 +Priority: optional
7.9 +# Homepage: <enter URL here; no default>
7.10 +Standards-Version: 3.9.2
7.11 +
7.12 +Package: osecfs
7.13 +Version: 0.0.25
7.14 +Maintainer: ft <ft@x-net.at>
7.15 +# Pre-Depends: <comma-separated list of packages>
7.16 +Depends: python,python-requests,python-fuse,python-clamav,python-pyclamav,clamav,python-urllib3,python-netifaces,python-netaddr
7.17 +# Recommends: <comma-separated list of packages>
7.18 +# Suggests: <comma-separated list of packages>
7.19 +# Provides: <comma-separated list of packages>
7.20 +# Replaces: <comma-separated list of packages>
7.21 +Architecture: all
7.22 +# Copyright: <copyright file; defaults to GPL2>
7.23 +# Changelog: <changelog file; defaults to a generic changelog>
7.24 +# Readme: <README.Debian file; defaults to a generic one>
7.25 +# Extra-Files: <comma-separated list of additional files for the doc directory>
7.26 +Files: osecfs /usr/bin/
7.27 + ikarusscanner/IkarusScanner.py /usr/bin/
7.28 + clamavscanner/ClamAVScanner.py /usr/bin/
7.29 + osecfs_usb.cfg /etc/osecfs/
7.30 + osecfs_downloads.cfg /etc/osecfs/
7.31 + ClamAVScanner.cfg /etc/osecfs/
7.32 + IkarusScanner.cfg /etc/osecfs/
7.33 +Description: Mirror Filesystem for Open Security
7.34 + An Mirror FS which makes virus scanning whitelistening and other things
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/osecfs-package.conf Tue Nov 04 17:44:32 2014 +0100
8.3 @@ -0,0 +1,2 @@
8.4 +# Original main-package.conf file.
8.5 +# Do not touch it!! It belongs to dpkg.
9.1 Binary file osecfs_0.0.10_all.deb has changed
10.1 Binary file osecfs_0.0.11_all.deb has changed
11.1 Binary file osecfs_0.0.12_all.deb has changed
12.1 Binary file osecfs_0.0.13_all.deb has changed
13.1 Binary file osecfs_0.0.14_all.deb has changed
14.1 Binary file osecfs_0.0.15_all.deb has changed
15.1 Binary file osecfs_0.0.16_all.deb has changed
16.1 Binary file osecfs_0.0.17_all.deb has changed
17.1 Binary file osecfs_0.0.18_all.deb has changed
18.1 Binary file osecfs_0.0.19_all.deb has changed
19.1 Binary file osecfs_0.0.1_all.deb has changed
20.1 Binary file osecfs_0.0.20_all.deb has changed
21.1 Binary file osecfs_0.0.21_all.deb has changed
22.1 Binary file osecfs_0.0.22_all.deb has changed
23.1 Binary file osecfs_0.0.23_all.deb has changed
24.1 Binary file osecfs_0.0.24_all.deb has changed
25.1 Binary file osecfs_0.0.25_all.deb has changed
26.1 Binary file osecfs_0.0.2_all.deb has changed
27.1 Binary file osecfs_0.0.3_all.deb has changed
28.1 Binary file osecfs_0.0.4_all.deb has changed
29.1 Binary file osecfs_0.0.5_all.deb has changed
30.1 Binary file osecfs_0.0.6_all.deb has changed
31.1 Binary file osecfs_0.0.7_all.deb has changed
32.1 Binary file osecfs_0.0.8_all.deb has changed
33.1 Binary file osecfs_0.0.9_all.deb has changed
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/osecfs_downloads.cfg Tue Nov 04 17:44:32 2014 +0100
34.3 @@ -0,0 +1,32 @@
34.4 +[Main]
34.5 +# make sure this file is writeable
34.6 +Logfile: /var/log/osecfs_downloads.log
34.7 +
34.8 +# DEBUG, INFO, WARNING, ERROR, CRITICAL
34.9 +LogLevel: debug
34.10 +
34.11 +# where the files really are on the filesystem
34.12 +Rootpath: /home/osecuser/Downloads
34.13 +
34.14 +
34.15 +
34.16 +
34.17 +# path to scanner class
34.18 +#ScannerPath: /usr/bin/ikarusscanner/
34.19 +
34.20 +# scanner module name
34.21 +#ScannerModuleName: IkarusScanner
34.22 +#ScannerClassName: IkarusScanner
34.23 +
34.24 +# config file for scanner (path will be in the constructor)
34.25 +#ScannerConfig: /etc/osecfs/IkarusScanner.cfg
34.26 +
34.27 +# path to scanner class
34.28 +ScannerPath: /usr/bin/clamavscanner/
34.29 +
34.30 +# scanner module name
34.31 +ScannerModuleName: ClamAVScanner
34.32 +ScannerClassName: ClamAVScanner
34.33 +
34.34 +# config file for scanner (path will be in the constructor)
34.35 +ScannerConfig: /etc/osecfs/ClamAVScanner.cfg
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/osecfs_usb.cfg Tue Nov 04 17:44:32 2014 +0100
35.3 @@ -0,0 +1,32 @@
35.4 +[Main]
35.5 +# make sure this file is writeable
35.6 +Logfile: /var/log/osecfs_usb.log
35.7 +
35.8 +# DEBUG, INFO, WARNING, ERROR, CRITICAL
35.9 +LogLevel: debug
35.10 +
35.11 +# where the files really are on the filesystem
35.12 +Rootpath: /media/usb0
35.13 +
35.14 +
35.15 +
35.16 +
35.17 +# path to scanner class
35.18 +#ScannerPath: /usr/bin/ikarusscanner/
35.19 +
35.20 +# scanner module name
35.21 +#ScannerModuleName: IkarusScanner
35.22 +#ScannerClassName: IkarusScanner
35.23 +
35.24 +# config file for scanner (path will be in the constructor)
35.25 +#ScannerConfig: /etc/osecfs/IkarusScanner.cfg
35.26 +
35.27 +# path to scanner class
35.28 +ScannerPath: /usr/bin/clamavscanner/
35.29 +
35.30 +# scanner module name
35.31 +ScannerModuleName: ClamAVScanner
35.32 +ScannerClassName: ClamAVScanner
35.33 +
35.34 +# config file for scanner (path will be in the constructor)
35.35 +ScannerConfig: /etc/osecfs/ClamAVScanner.cfg