Restored scan function using ClamAV as fallback for testing.
14 # ToDo replace with ikarus
21 MINOPTS = { "Main" : ["Logfile", "Mountpoint", "Rootpath", "LocalScanserverURL", "RemoteScanserverURL"]}
23 CONFIG_NOT_READABLE = "Configfile is not readable"
24 CONFIG_WRONG = "Something is wrong with the config"
25 CONFIG_MISSING = "Section: \"%s\" Option: \"%s\" in configfile is missing"
27 LOCAL_SCANSERVER_URL = ""
28 REMOTE_SCANSERVER_URL = ""
30 STATUS_CODE_INFECTED = 210
31 STATUS_CODE_NOT_FOUND = 404
33 SYSTEM_FILE_COMMAND = "file"
36 def checkMinimumOptions (config):
37 for section, options in MINOPTS.iteritems ():
38 for option in options:
39 if (config.has_option(section, option) == False):
40 print (CONFIG_MISSING % (section, option))
45 print ("%s configfile" % (sys.argv[0]))
51 if (len (sys.argv) < 2):
54 configfile = sys.argv[1]
55 config = ConfigParser.SafeConfigParser ()
57 if ((os.path.exists (configfile) == False) or (os.path.isfile (configfile) == False) or (os.access (configfile, os.R_OK) == False)):
58 print (CONFIG_NOT_READABLE)
62 config.read (sys.argv[1])
65 print ("Error: %s" % (e))
67 checkMinimumOptions (config)
75 logfile = config.get("Main", "Logfile")
77 # ToDo move log level and maybe other things to config file
79 level = logging.DEBUG,
80 format = "%(asctime)s %(name)-12s %(funcName)-15s %(levelname)-8s %(message)s",
81 datefmt = "%Y-%m-%d %H:%M:%S",
85 LOG = logging.getLogger("fuse_main")
91 def rootPath (rootpath, path):
92 return "%s%s" % (rootpath, path)
94 def flag2mode (flags):
95 md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
96 m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)]
98 if flags | os.O_APPEND:
99 m = m.replace('w', 'a', 1)
103 def scanFileIkarus (path, fileobject):
105 LOG.debug ("Scan File: %s" % (path))
107 files = {'up_file': (path, fileobject)}
110 #TODO: change to remote server
111 r = requests.post(LOCAL_SCANSERVER_URL, files=files)
112 except requests.exceptions.ConnectionError:
113 #LOG.info("Remote scan server unreachable, using local scan server.")
116 # Here the local scan server should be contacted.
117 # The requests package does not upload content in the second post request,
118 # so no fallback server can be used right now (bug?)
119 # I did not a find a solution yet, maybe another http package has to be used.
123 # r = requests.post(LOCAL_SCANSERVER_URL, files=files)
124 #except requests.exceptions.ConnectionError:
126 LOG.error ("Connection to scan server could not be established.")
129 if r.status_code == STATUS_CODE_OK:
131 elif r.status_code == STATUS_CODE_INFECTED:
132 # Parse xml for info if desired
133 #contentXML = r.content
134 #root = ET.fromstring(contentXML)
135 #status = root[1][2].text
138 LOG.error ("Connection error to scan server.")
140 if (infected == True):
141 LOG.error ("Virus found, denying access.")
143 LOG.debug ("No virus found.")
147 def scanFileClamAV (path):
150 LOG.debug ("Scan File: %s" % (path))
152 # ToDo implement ikarus
153 result = pyclamav.scanfile (path)
154 LOG.debug ("Result of file \"%s\": %s" % (path, result))
158 if (infected == True):
159 LOG.error ("Virus found, deny Access %s" % (result,))
163 def whitelistFile (path):
166 LOG.debug ("Execute \"%s\" command on \"%s\"" %(SYSTEM_FILE_COMMAND, path))
170 result = subprocess.check_output ([SYSTEM_FILE_COMMAND, path]);
171 # ToDo replace with real whitelist
173 except Exception as e:
174 LOG.error ("Call returns with an error!")
177 LOG.debug ("Type: %s" %(result))
186 def __init__(self, rootpath, *args, **kw):
187 self.__rootpath = rootpath
188 Fuse.__init__ (self, *args, **kw)
189 LOG.debug ("Init complete.")
191 # defines that our working directory will be the __rootpath
193 os.chdir (self.__rootpath)
195 def getattr(self, path):
196 LOG.debug ("*** getattr (%s)" % (fixPath (path)))
197 return os.lstat (fixPath (path));
199 def getdir(self, path):
200 LOG.debug ("*** getdir (%s)" % (path));
201 return os.listdir (fixPath (path))
203 def readdir(self, path, offset):
204 LOG.debug ("*** readdir (%s %s)" % (path, offset));
205 for e in os.listdir (fixPath (path)):
206 yield fuse.Direntry(e)
208 def chmod (self, path, mode):
209 LOG.debug ("*** chmod %s %s" % (path, oct(mode)))
210 os.chmod (fixPath (path), mode)
212 def chown (self, path, uid, gid):
213 LOG.debug ("*** chown %s %s %s" % (path, uid, gid))
214 os.chown (fixPath (path), uid, gid)
216 def link (self, targetPath, linkPath):
217 LOG.debug ("*** link %s %s" % (targetPath, linkPath))
218 os.link (fixPath (targetPath), fixPath (linkPath))
220 def mkdir (self, path, mode):
221 LOG.debug ("*** mkdir %s %s" % (path, oct(mode)))
222 os.mkdir (fixPath (path), mode)
224 def mknod (self, path, mode, dev):
225 LOG.debug ("*** mknod %s %s %s" % (path, oct (mode), dev))
226 os.mknod (fixPath (path), mode, dev)
228 # to implement virus scan
229 def open (self, path, flags):
230 LOG.debug ("*** open %s %s" % (path, oct (flags)))
231 self.file = os.fdopen (os.open (fixPath (path), flags), flag2mode (flags))
232 self.fd = self.file.fileno ()
234 infected = scanFileIkarus (rootPath(self.__rootpath, path), self.file)
235 #infected = scanFileClamAV (rootPath(self.__rootpath, path))
236 if (infected == True):
240 whitelisted = whitelistFile (rootPath(self.__rootpath, path))
241 if (whitelisted == False):
245 def read (self, path, length, offset):
246 LOG.debug ("*** read %s %s %s" % (path, length, offset))
247 self.file.seek (offset)
248 return self.file.read (length)
250 def readlink (self, path):
251 LOG.debug ("*** readlink %s" % (path))
252 return os.readlink (fixPath (path))
254 def release (self, path, flags):
255 LOG.debug ("*** release %s %s" % (path, oct (flags)))
258 def rename (self, oldPath, newPath):
259 LOG.debug ("*** rename %s %s" % (oldPath, newPath))
260 os.rename (fixPath (oldPath), fixPath (newPath))
262 def rmdir (self, path):
263 LOG.debug ("*** rmdir %s" % (path))
264 os.rmdir (fixPath (path))
267 LOG.debug ("*** statfs")
268 return os.statvfs(".")
270 def symlink (self, targetPath, linkPath):
271 LOG.debug ("*** symlink %s %s" % (targetPath, linkPath))
272 os.symlink (fixPath (targetPath), fixPath (linkPath))
274 def truncate (self, path, length):
275 LOG.debug ("*** truncate %s %s" % (path, length))
276 f = open (fixPath (path), "a")
280 def unlink (self, path):
281 LOG.debug ("*** unlink %s" % (path))
282 os.unlink (fixPath (path))
284 def utime (self, path, times):
285 LOG.debug ("*** utime %s %s" % (path, times))
286 os.utime (fixPath (path), times)
288 def write (self, path, buf, offset):
289 LOG.debug ("*** write %s %s %s" % (path, buf, offset))
290 self.file.seek (offset)
291 self.file.write (buf)
294 def access (self, path, mode):
295 LOG.debug ("*** access %s %s" % (path, oct (mode)))
296 if not os.access (fixPath (path), mode):
299 def create (self, path, flags, mode):
300 LOG.debug ("*** create %s %s %s %s" % (fixPath (path), oct (flags), oct (mode), flag2mode (flags)))
301 self.file = os.fdopen (os.open (fixPath (path), flags, mode), flag2mode (flags))
302 self.fd = self.file.fileno ()
305 if __name__ == "__main__":
307 fuse.fuse_python_api = (0, 2)
308 fuse.feature_assert ('stateful_files', 'has_init')
310 config = loadConfig ()
313 LOCAL_SCANSERVER_URL = config.get("Main", "LocalScanserverURL")
314 REMOTE_SCANSERVER_URL = config.get("Main", "RemoteScanserverURL")
316 osecfs = OsecFS (config.get ("Main", "Rootpath"))
318 osecfs.multithreaded = 0
320 # osecfs.parser.add_option (mountopt=config.get("Main", "Mountpoint"),
322 # default=config.get("Main", "Rootpath"),
323 # help="mirror filesystem from under PATH [default: %default]")
324 # osecfs.parse(values=osecfs, errex=1)
326 fuse_args = [sys.argv[0], config.get ("Main", "Mountpoint")];
327 osecfs.main (fuse_args)