Du coup, je pars sur un script en Python3 avec quelque chose du genre :
'''
Scan en temps réel d'un ou plusieurs dossiers
Ce programme requiert le démon clamav
'''
# Je mets un alias à ClamdUnixSocket car il existe trois méthodes pour faire ça :
## ClamdUnixSocket qui permet d'accéder via une socket Unix
## ClamdNetworkSocket via une socket réseau TCP
## ClamdAgnostic qui teste les deux et qui utilise celui qui fonctionne
# J'utise ici la méthode avec la socket Unix parce que c'est celle qui est configurée par défaut dans debian à l'installation du démon clamav
from pyclamd import ClamdUnixSocket as ClamdSocket
from pyclamd.pyclamd import ConnectionError as ClamdConnectionError
from pyinotify import WatchManager, Notifier, IN_CLOSE_WRITE, IN_CREATE, IN_DELETE_SELF, IN_MOVED_TO
from os.path import isdir, isfile, islink, samefile, join
from os import walk, mkdir, remove as rm
from shutil import move as mv, Error as shError
def live_clamdscan (paths, quarantine = '/tmp/clamd-quarantine'):
def add_dir (path):
wd = wm.add_watch (path, IN_CLOSE_WRITE | IN_CREATE | IN_MOVED_TO | IN_DELETE_SELF, proc_fun = manage_event)
for i in walk (path):
f = i [0]
if not samefile (f, path):
manage_file (f)
for j in i [2]:
manage_file (join (f, j))
def del_dir (path):
wd = wm.get_wd (path)
wm.del_watch (wd)
def scan_file (path):
# TODO: analyser le fichier
try:
if not clamd.scan_file (path) is None:
try:
mv (path, quarantine)
except shError:
rm (path)
except FileNotFoundError:
pass
def manage_file (path):
if isdir (path) and not islink (path):
add_dir (path)
elif isfile (path):
scan_file (path)
def manage_event (e):
if e.mask & IN_DELETE_SELF == 0:
manage_file (e.pathname)
else:
del_dir (e.pathname)
try:
clamd = ClamdSocket ()
except ClamdConnectionError:
'''
Il se peut que le démon clamd ne soit pas disponible à ce moment.
On retourne False pour indiquer une erreur, mais c'est normalement un des trois seuls cas de retour de cette fonction.
'''
pass
return (False)
wm=WatchManager ()
notifier = Notifier (wm)
try:
mkdir (quarantine)
except (FileNotFoundError, OSError) as e:
'''
Le second cas, impossible de créer la quarantaine
'''
return (False)
except FileExistsError:
'''
Si la quarantaine existe déjà, on la recycle
'''
pass
for i in paths:
manage_file (i)
try:
notifier.loop ()
except KeyboardInterrupt:
'''
Voici le troisième cas de retour, celui-ci est causé par une interruption par signal INT.
On retourne True car c'est une fin qui n'émane par d'une erreur
'''
del notifier
del wm
del clamd
return (True)
Et je lance la fonction live_clamdscan ()
avec un tuple des chemins à surveiller en premier paramètre et le chemin de la quarantaine en second paramètre.
Ça requiert les paquets clamav-daemon
, clamav-freshclam
, python3-pyinotify
et python3-pyclamd
.