1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/config/OsecFS.cfg Tue Oct 29 15:13:44 2013 +0100
1.3 @@ -0,0 +1,9 @@
1.4 +[Main]
1.5 +# make sure this file is writeable
1.6 +Logfile: /var/log/fuse_test.log
1.7 +
1.8 +# the place that the user will see (you can't access virusfiles here)
1.9 +Mountpoint: /tmp/virtual_fuse
1.10 +
1.11 +# where the files really are on the filesystem
1.12 +Rootpath: /tmp/root_fuse
1.13 \ No newline at end of file
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/src/OsecFS.py Tue Oct 29 15:13:44 2013 +0100
2.3 @@ -0,0 +1,273 @@
2.4 +#!/usr/bin/python
2.5 +
2.6 +from fuse import Fuse
2.7 +import fuse
2.8 +
2.9 +import ConfigParser
2.10 +
2.11 +import sys
2.12 +
2.13 +import logging
2.14 +import os
2.15 +import errno
2.16 +
2.17 +# ToDo replace with ikarus
2.18 +import pyclamav
2.19 +import subprocess
2.20 +
2.21 +MINOPTS = { "Main" : ["Logfile", "Mountpoint", "Rootpath"]}
2.22 +
2.23 +CONFIG_NOT_READABLE = "Configfile is not readable"
2.24 +CONFIG_WRONG = "Something is wrong with the config"
2.25 +CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing"
2.26 +LOG = None
2.27 +
2.28 +SYSTEM_FILE_COMMAND = "file"
2.29 +
2.30 +
2.31 +def checkMinimumOptions (config):
2.32 + for section, options in MINOPTS.iteritems ():
2.33 + for option in options:
2.34 + if (config.has_option(section, option) == False):
2.35 + print (CONFIG_MISSING % (section, option))
2.36 + exit (129)
2.37 +
2.38 +def printUsage ():
2.39 + print ("Usage:")
2.40 + print ("%s configfile" % (sys.argv[0]))
2.41 + exit (128)
2.42 +
2.43 +def loadConfig ():
2.44 + print ("load config")
2.45 +
2.46 + if (len (sys.argv) < 2):
2.47 + printUsage ()
2.48 +
2.49 + configfile = sys.argv[1]
2.50 + config = ConfigParser.SafeConfigParser ()
2.51 +
2.52 + if ((os.path.exists (configfile) == False) or (os.path.isfile (configfile) == False) or (os.access (configfile, os.R_OK) == False)):
2.53 + print (CONFIG_NOT_READABLE)
2.54 + printUsage ()
2.55 +
2.56 + try:
2.57 + config.read (sys.argv[1])
2.58 + except Exception, e:
2.59 + print (CONFIG_WRONG)
2.60 + print ("Error: %s" % (e))
2.61 +
2.62 + checkMinimumOptions (config)
2.63 +
2.64 + return config
2.65 +
2.66 +def initLog (config):
2.67 + print ("init log")
2.68 +
2.69 + global LOG
2.70 + logfile = config.get("Main", "Logfile")
2.71 +
2.72 + # ToDo move log level and maybe other things to config file
2.73 + logging.basicConfig(
2.74 + level = logging.DEBUG,
2.75 + format = "%(asctime)s %(name)-12s %(funcName)-15s %(levelname)-8s %(message)s",
2.76 + datefmt = "%Y-%m-%d %H:%M:%S",
2.77 + filename = logfile,
2.78 + filemode = "a+",
2.79 + )
2.80 + LOG = logging.getLogger("fuse_main")
2.81 +
2.82 +
2.83 +def fixPath (path):
2.84 + return ".%s" % (path)
2.85 +
2.86 +def rootPath (rootpath, path):
2.87 + return "%s%s" % (rootpath, path)
2.88 +
2.89 +def flag2mode (flags):
2.90 + md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
2.91 + m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)]
2.92 +
2.93 + if flags | os.O_APPEND:
2.94 + m = m.replace('w', 'a', 1)
2.95 +
2.96 + return m
2.97 +
2.98 +
2.99 +
2.100 +def scanFile (path):
2.101 + infected = False
2.102 +
2.103 + LOG.debug ("Scan File: %s" % (path))
2.104 +
2.105 + # ToDo implement ikarus
2.106 + result = pyclamav.scanfile (path)
2.107 + LOG.debug ("Result of file \"%s\": %s" % (path, result))
2.108 + if (result[0] != 0):
2.109 + infected = True
2.110 +
2.111 + if (infected == True):
2.112 + LOG.error ("Virus found deny Access %s" % (result,))
2.113 +
2.114 + return infected
2.115 +
2.116 +def whitelistFile (path):
2.117 + whitelisted = False;
2.118 +
2.119 + LOG.debug ("Execute \"%s\" command on \"%s\"" %(SYSTEM_FILE_COMMAND, path))
2.120 +
2.121 + result = None
2.122 + try:
2.123 + result = subprocess.check_output ([SYSTEM_FILE_COMMAND, path]);
2.124 + # ToDo replace with real whitelist
2.125 + whitelisted = True
2.126 + except Exception as e:
2.127 + LOG.error ("Call returns with an error!")
2.128 + LOG.error (e)
2.129 +
2.130 + LOG.debug ("Type: %s" %(result))
2.131 +
2.132 + return whitelisted
2.133 +
2.134 +class OsecFS (Fuse):
2.135 +
2.136 + __rootpath = None
2.137 +
2.138 + # default fuse init
2.139 + def __init__(self, rootpath, *args, **kw):
2.140 + self.__rootpath = rootpath
2.141 + Fuse.__init__ (self, *args, **kw)
2.142 + LOG.debug ("Init complete.")
2.143 +
2.144 + # defines that our working directory will be the __rootpath
2.145 + def fsinit(self):
2.146 + os.chdir (self.__rootpath)
2.147 +
2.148 + def getattr(self, path):
2.149 + LOG.debug ("*** getattr (%s)" % (fixPath (path)))
2.150 + return os.lstat (fixPath (path));
2.151 +
2.152 + def getdir(self, path):
2.153 + LOG.debug ("*** getdir (%s)" % (path));
2.154 + return os.listdir (fixPath (path))
2.155 +
2.156 + def readdir(self, path, offset):
2.157 + LOG.debug ("*** readdir (%s %s)" % (path, offset));
2.158 + for e in os.listdir (fixPath (path)):
2.159 + yield fuse.Direntry(e)
2.160 +
2.161 + def chmod (self, path, mode):
2.162 + LOG.debug ("*** chmod %s %s" % (path, oct(mode)))
2.163 + os.chmod (fixPath (path), mode)
2.164 +
2.165 + def chown (self, path, uid, gid):
2.166 + LOG.debug ("*** chown %s %s %s" % (path, uid, gid))
2.167 + os.chown (fixPath (path), uid, gid)
2.168 +
2.169 + def link (self, targetPath, linkPath):
2.170 + LOG.debug ("*** link %s %s" % (targetPath, linkPath))
2.171 + os.link (fixPath (targetPath), fixPath (linkPath))
2.172 +
2.173 + def mkdir (self, path, mode):
2.174 + LOG.debug ("*** mkdir %s %s" % (path, oct(mode)))
2.175 + os.mkdir (fixPath (path), mode)
2.176 +
2.177 + def mknod (self, path, mode, dev):
2.178 + LOG.debug ("*** mknod %s %s %s" % (path, oct (mode), dev))
2.179 + os.mknod (fixPath (path), mode, dev)
2.180 +
2.181 + # to implement virus scan
2.182 + def open (self, path, flags):
2.183 + LOG.debug ("*** open %s %s" % (path, oct (flags)))
2.184 + self.file = os.fdopen (os.open (fixPath (path), flags), flag2mode (flags))
2.185 + self.fd = self.file.fileno ()
2.186 +
2.187 + infected = scanFile (rootPath(self.__rootpath, path))
2.188 + if (infected == True):
2.189 + self.file.close ()
2.190 + return -errno.EACCES
2.191 +
2.192 + whitelisted = whitelistFile (rootPath(self.__rootpath, path))
2.193 + if (whitelisted == False):
2.194 + self.file.close ()
2.195 + return -errno.EACCES
2.196 +
2.197 + def read (self, path, length, offset):
2.198 + LOG.debug ("*** read %s %s %s" % (path, length, offset))
2.199 + self.file.seek (offset)
2.200 + return self.file.read (length)
2.201 +
2.202 + def readlink (self, path):
2.203 + LOG.debug ("*** readlink %s" % (path))
2.204 + return os.readlink (fixPath (path))
2.205 +
2.206 + def release (self, path, flags):
2.207 + LOG.debug ("*** release %s %s" % (path, oct (flags)))
2.208 + self.file.close ()
2.209 +
2.210 + def rename (self, oldPath, newPath):
2.211 + LOG.debug ("*** rename %s %s" % (oldPath, newPath))
2.212 + os.rename (fixPath (oldPath), fixPath (newPath))
2.213 +
2.214 + def rmdir (self, path):
2.215 + LOG.debug ("*** rmdir %s" % (path))
2.216 + os.rmdir (fixPath (path))
2.217 +
2.218 + def statfs (self):
2.219 + LOG.debug ("*** statfs")
2.220 + return os.statvfs(".")
2.221 +
2.222 + def symlink (self, targetPath, linkPath):
2.223 + LOG.debug ("*** symlink %s %s" % (targetPath, linkPath))
2.224 + os.symlink (fixPath (targetPath), fixPath (linkPath))
2.225 +
2.226 + def truncate (self, path, length):
2.227 + LOG.debug ("*** truncate %s %s" % (path, length))
2.228 + f = open (fixPath (path), "a")
2.229 + f.truncate (length)
2.230 + f.close ()
2.231 +
2.232 + def unlink (self, path):
2.233 + LOG.debug ("*** unlink %s" % (path))
2.234 + os.unlink (fixPath (path))
2.235 +
2.236 + def utime (self, path, times):
2.237 + LOG.debug ("*** utime %s %s" % (path, times))
2.238 + os.utime (fixPath (path), times)
2.239 +
2.240 + def write (self, path, buf, offset):
2.241 + LOG.debug ("*** write %s %s %s" % (path, buf, offset))
2.242 + self.file.seek (offset)
2.243 + self.file.write (buf)
2.244 + return len (buf)
2.245 +
2.246 + def access (self, path, mode):
2.247 + LOG.debug ("*** access %s %s" % (path, oct (mode)))
2.248 + if not os.access (fixPath (path), mode):
2.249 + return -errno.EACCES
2.250 +
2.251 + def create (self, path, flags, mode):
2.252 + LOG.debug ("*** create %s %s %s %s" % (fixPath (path), oct (flags), oct (mode), flag2mode (flags)))
2.253 + self.file = os.fdopen (os.open (fixPath (path), flags, mode), flag2mode (flags))
2.254 + self.fd = self.file.fileno ()
2.255 +
2.256 +
2.257 +if __name__ == "__main__":
2.258 + # Set api version
2.259 + fuse.fuse_python_api = (0, 2)
2.260 + fuse.feature_assert ('stateful_files', 'has_init')
2.261 +
2.262 + config = loadConfig ()
2.263 + initLog (config)
2.264 +
2.265 + osecfs = OsecFS (config.get ("Main", "Rootpath"))
2.266 + osecfs.flags = 0
2.267 + osecfs.multithreaded = 0
2.268 +
2.269 + # osecfs.parser.add_option (mountopt=config.get("Main", "Mountpoint"),
2.270 + # metavar="PATH",
2.271 + # default=config.get("Main", "Rootpath"),
2.272 + # help="mirror filesystem from under PATH [default: %default]")
2.273 + # osecfs.parse(values=osecfs, errex=1)
2.274 +
2.275 + fuse_args = [sys.argv[0], config.get ("Main", "Mountpoint")];
2.276 + osecfs.main (fuse_args)