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