''' fusefs.py - Fuse filesystem with antivirus control. (c) 2005-2016 Jan ONDREJ (SAL) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ''' import os,stat,errno from aglib import * __all__=['fusefs'] try: import fuse class SgFuse(fuse.FUSE): multithreaded=1 allow_other=True files={} def __init__(self, mountpoint, root_path): self.mountpoint=mountpoint self.base=root_path if debug.debug_level>8: self.debug=True def getattr(self, path): return os.lstat(self.base+path) def readlink(self, path): return os.readlink(self.base+path) def getdir(self, path): return [('.',0),('..',0)]+[(x,0) for x in os.listdir(self.base+path)] def unlink(self, path): return os.unlink(self.base+path) def rmdir(self, path): return os.rmdir(self.base+path) def symlink(self, path, path1): return os.symlink(self.base+path, path1) def rename(self, path, path1): return os.rename(self.base+path, self.base+path1) def link(self, path, path1): return os.link(self.base+path, self.base+path1) def chmod(self, path, mode): return os.chmod(self.base+path, mode) def chown(self, path, user, group): return os.chown(self.base+path, user, group) def truncate(self, path, size): f = open(self.base+path, "w+") return f.truncate(size) def mknod(self, path, mode, dev): if stat.S_ISREG(mode): open(self.base+path, "w") else: return -errno.EINVAL def mkdir(self, path, mode): return os.mkdir(self.base+path, mode) def utime(self, path, times): return os.utime(self.base+path, times) def open(self, path, flags): debug.echo(6,"open: %s, 0x%x" % (path,flags)) if flags & os.O_APPEND: python_flags='a' else: python_flags=['r','w','r+'][flags & 3] self.files[path]=open(self.base+path,python_flags) if ('r' in python_flags) or ('+' in python_flags): # reinit scanners for scnr in self.SCANNERS: scnr.reinit() mail.data=self.files[path].read() mail.xheader='' globals.reset() for scnr in self.SCANNERS: level, detected, virlist, scan_reply, err \ = do_scan(scnr,os.path.basename(path)) if is_infected(level,detected): debug.echo(1,"fusefs(): %s %s [%s,%0.2f]" \ % (path,detected,globals.found_by.name,level)) del self.files[path] return -errno.EPERM debug.echo(7,'open: %s, done' % path) return 0 def read(self, path, len, offset): debug.echo(6,"read: %s" % path) f=self.files[path] f.seek(offset) return f.read(len) def write(self, path, buf, offset): debug.echo(6,"write: %s" % path,self.files) f=self.files[path] f.seek(offset) f.write(buf) return len(buf) def release(self, path, flags): debug.echo(6,"close: %s" % path) self.files[path].close() del self.files[path] return 0 def fsync(self, path, isfsyncfile): debug.echo(6,"fsync: path=%s, isfsyncfile=%s" % (path, isfsyncfile)) return 0 except ImportError: class SgFuse: errorstring='''Importing of fuse module failed! You have configured fusefs() service and this service can't import fuse python module. Install python-fuse package.''' def __init__(self,*args,**kw): debug.echo(1,self.errorstring) raise ImportError(self.errorstring) class fusefs(service): ''' Fuse filesystem with antivirus checking. This service can be used to check filesystem access for viruses. Usage: fusefs(SCANNERS, mountpoint, root_path='/') Where: mountpoint is a string, which defines an directory, where files will be accessed. root_path is a path, which files will real files. Example: fusefs(SCANNERS, '/home', '/realhome') New in version 0.8.0. ''' name='fusefs()' def __init__(self,scanners,mountpoint,root_path='/'): self.server=SgFuse(mountpoint,root_path) self.server.SCANNERS=scanners self.MOUNTPOINT=mountpoint self.ROOT_PATH=root_path self.EXITING=False def start(self): if not os.path.isdir(self.MOUNTPOINT): raise IOError("No such directory: %s" % self.MOUNTPOINT) if not os.path.isdir(self.ROOT_PATH): raise IOError("No such directory: %s" % self.ROOT_PATH) self.test_scanners(self.server.SCANNERS) pid=self.fork() return [pid] def fork(self): if self.EXITING: return -1 if self.childs!=[]: return -1 p=os.fork() if p==0: signal.signal(signal.SIGHUP,self.sighup) signal.signal(signal.SIGTERM,self.sigterm) debug.echo(1,"%s: service started, waiting ... [%d]" \ % (self.name,os.getpid())) self.server.main() debug.echo(1,"%s: server stopped." % self.name) else: self.childs.append(p) return p def cleanup(self): debug.echo(5,'%s: umounting %s' \ % (self.name,self.MOUNTPOINT)) ret=os.system('umount %s' % self.MOUNTPOINT) if ret: debug.echo(1,'%s: umount return status: %d' % (self.name,ret))