initial commit of osecfs-deb default tip
authorft
Tue, 04 Nov 2014 17:44:32 +0100
changeset 02342e6cefd65
initial commit of osecfs-deb
Apache License, Version 2.0.txt
ClamAVScanner.cfg
IkarusScanner.cfg
clamavscanner/ClamAVScanner.py
ikarusscanner/IkarusScanner.py
osecfs
osecfs-package
osecfs-package.conf
osecfs_0.0.10_all.deb
osecfs_0.0.11_all.deb
osecfs_0.0.12_all.deb
osecfs_0.0.13_all.deb
osecfs_0.0.14_all.deb
osecfs_0.0.15_all.deb
osecfs_0.0.16_all.deb
osecfs_0.0.17_all.deb
osecfs_0.0.18_all.deb
osecfs_0.0.19_all.deb
osecfs_0.0.1_all.deb
osecfs_0.0.20_all.deb
osecfs_0.0.21_all.deb
osecfs_0.0.22_all.deb
osecfs_0.0.23_all.deb
osecfs_0.0.24_all.deb
osecfs_0.0.25_all.deb
osecfs_0.0.2_all.deb
osecfs_0.0.3_all.deb
osecfs_0.0.4_all.deb
osecfs_0.0.5_all.deb
osecfs_0.0.6_all.deb
osecfs_0.0.7_all.deb
osecfs_0.0.8_all.deb
osecfs_0.0.9_all.deb
osecfs_downloads.cfg
osecfs_usb.cfg
     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