initial commit
authorft
Tue, 29 Oct 2013 15:13:44 +0100
changeset 0e840b60f3ea3
child 1 1f61fe50ab10
initial commit
config/OsecFS.cfg
src/OsecFS.py
     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)