diff -r d27473cf6a01 -r 23028352807f src/OsecFS.py --- a/src/OsecFS.py Wed Nov 27 15:37:26 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -#!/usr/bin/python - -from fuse import Fuse -import fuse - -import ConfigParser - -import sys - -import logging -import os -import errno - -# ToDo replace with ikarus -#import pyclamav -import subprocess - -import requests - - -MINOPTS = { "Main" : ["Logfile", "Mountpoint", "Rootpath", "LocalScanserverURL", "RemoteScanserverURL"]} - -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" -LOG = None -LOCAL_SCANSERVER_URL = "" -REMOTE_SCANSERVER_URL = "" -STATUS_CODE_OK = 200 -STATUS_CODE_INFECTED = 210 -STATUS_CODE_NOT_FOUND = 404 - -SYSTEM_FILE_COMMAND = "file" - - -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" % (sys.argv[0])) - exit (128) - -def loadConfig (): - print ("load config") - - if (len (sys.argv) < 2): - 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)) - - checkMinimumOptions (config) - - return config - -def initLog (config): - print ("init log") - - global LOG - logfile = config.get("Main", "Logfile") - - # ToDo move log level and maybe other things to config file - logging.basicConfig( - level = logging.DEBUG, - 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)] - - if flags | os.O_APPEND: - m = m.replace('w', 'a', 1) - - return m - -def scanFileIkarus (path, fileobject): - infected = False - LOG.debug ("Scan File: %s" % (path)) - - files = {'up_file': (path, fileobject)} - - try: - #TODO: change to remote server - r = requests.post(LOCAL_SCANSERVER_URL, files=files) - except requests.exceptions.ConnectionError: - #LOG.info("Remote scan server unreachable, using local scan server.") - - # TODO: - # Here the local scan server should be contacted. - # The requests package does not upload content in the second post request, - # so no fallback server can be used right now (bug?) - # I did not a find a solution yet, maybe another http package has to be used. - # Disabled for now. - - #try: - # r = requests.post(LOCAL_SCANSERVER_URL, files=files) - #except requests.exceptions.ConnectionError: - # return 2 - LOG.error ("Connection to scan server could not be established.") - return False - - if r.status_code == STATUS_CODE_OK: - infected = False - elif r.status_code == STATUS_CODE_INFECTED: - # Parse xml for info if desired - #contentXML = r.content - #root = ET.fromstring(contentXML) - #status = root[1][2].text - infected = True - else: - LOG.error ("Connection error to scan server.") - - if (infected == True): - LOG.error ("Virus found, denying access.") - else: - LOG.debug ("No virus found.") - - return infected - -def scanFileClamAV (path): - infected = False - - LOG.debug ("Scan File: %s" % (path)) - - # ToDo implement ikarus - 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 - -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.") - - # 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))) - os.chmod (fixPath (path), mode) - - def chown (self, path, uid, gid): - LOG.debug ("*** chown %s %s %s" % (path, uid, gid)) - os.chown (fixPath (path), uid, gid) - - def link (self, targetPath, linkPath): - LOG.debug ("*** link %s %s" % (targetPath, linkPath)) - os.link (fixPath (targetPath), fixPath (linkPath)) - - def mkdir (self, path, mode): - LOG.debug ("*** mkdir %s %s" % (path, oct(mode))) - os.mkdir (fixPath (path), mode) - - def mknod (self, path, mode, dev): - LOG.debug ("*** mknod %s %s %s" % (path, oct (mode), dev)) - 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.fd = self.file.fileno () - - infected = scanFileIkarus (rootPath(self.__rootpath, path), self.file) - #infected = scanFileClamAV (rootPath(self.__rootpath, path)) - if (infected == True): - self.file.close () - return -errno.EACCES - - whitelisted = whitelistFile (rootPath(self.__rootpath, path)) - if (whitelisted == False): - self.file.close () - 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.close () - - def rename (self, oldPath, newPath): - LOG.debug ("*** rename %s %s" % (oldPath, newPath)) - os.rename (fixPath (oldPath), fixPath (newPath)) - - def rmdir (self, path): - LOG.debug ("*** rmdir %s" % (path)) - os.rmdir (fixPath (path)) - - def statfs (self): - LOG.debug ("*** statfs") - return os.statvfs(".") - - def symlink (self, targetPath, linkPath): - LOG.debug ("*** symlink %s %s" % (targetPath, linkPath)) - os.symlink (fixPath (targetPath), fixPath (linkPath)) - - def truncate (self, path, length): - LOG.debug ("*** truncate %s %s" % (path, length)) - f = open (fixPath (path), "a") - f.truncate (length) - f.close () - - def unlink (self, path): - LOG.debug ("*** unlink %s" % (path)) - 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" % (path, buf, offset)) - self.file.seek (offset) - self.file.write (buf) - 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" % (fixPath (path), oct (flags), oct (mode), flag2mode (flags))) - self.file = os.fdopen (os.open (fixPath (path), flags, mode), flag2mode (flags)) - 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) - - LOCAL_SCANSERVER_URL = config.get("Main", "LocalScanserverURL") - REMOTE_SCANSERVER_URL = config.get("Main", "RemoteScanserverURL") - - osecfs = OsecFS (config.get ("Main", "Rootpath")) - osecfs.flags = 0 - osecfs.multithreaded = 0 - - # osecfs.parser.add_option (mountopt=config.get("Main", "Mountpoint"), - # metavar="PATH", - # default=config.get("Main", "Rootpath"), - # help="mirror filesystem from under PATH [default: %default]") - # osecfs.parse(values=osecfs, errex=1) - - fuse_args = [sys.argv[0], config.get ("Main", "Mountpoint")]; - osecfs.main (fuse_args)