#!/usr/bin/python3 ''' scand.py (c) 2006-2018 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 sys, os, socket, signal, atexit, traceback import avlib import aglib from etc import * def rmpid(): try: os.unlink(BINDTO) os.unlink(SCAND.PID_FILE) except: #debug.echo(1,"scand: %s" % sys.exc_info()[1]) pass def sigterm(sn,stack): global EXITING EXITING=True def sighup(sn,stack): # reopen logfile debug.reopen() def mainloop(s,scanner): while True: if EXITING: break try: conn,addr=s.accept() conn.settimeout(120) f=conn.makefile('rw') mail.__init__() while True: cmd=f.readline().strip('\r\n').split(" ",1) debug.echo(5,"scand: %s" % cmd) if cmd[0]=='MAIL_FROM': mail.sender=cmd[1] elif cmd[0]=='RCPT_TO': mail.recip.append(cmd[1]) elif cmd[0]=='SCANFILE': try: level, detected, virlist = scanner.scanfile([cmd[1]]) conn.sendall('%f %s\n' % (level,detected)) for line in virlist: conn.sendall(line) except: conn.sendall('ERROR %s\n' % sys.exc_info()[1]) break elif cmd[0]=='QUIT': conn.sendall('OK Bye\n') break else: conn.sendall('ERROR Illegal command!\n') break f.close() conn.shutdown(2) conn.close() except KeyboardInterrupt: break except SystemExit: break except socket.error as eces: if eces[0]==4: continue debug.echo(1,"scand: %s" % eces) debug.traceback(4,"scand") except: debug.echo(1,"scand: ERROR: %s" % sys.exc_info()[1]) debug.traceback(1,"scand") if __name__ == '__main__': EXITING=False SCAND=aglib.find_service(SRV,'scand()') BINDTO=CHROOT+SCAND.SOCK debug.set_level(DEBUG_LEVEL) debug.set_logfile(LOGFILE) try: pidfile=open(SCAND.PID_FILE,'w') except IOError as err: (ec,es) = err.args debug.echo(2,"WARNING: Can't open pidfile for writing: %s" % es) pidfile='' if ('--as-root' not in sys.argv): avlib.globals.setuidgid(USER,GROUP) avlib.safe.ROOT_PATH=CHROOT # simulate chroot access os.umask(0) s=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) try: s.bind(BINDTO) except socket.error as err: (ec,es) = err.args if ec==98: # Address already in use try: s.connect(BINDTO) s.sendall('QUIT\n') s.close() debug.echo(1,"scand: There is another daemon already running." " Exiting now ...") sys.exit(0) except socket.error: debug.echo(1,"scand: Unlinking dead socket file.") os.unlink(BINDTO) s=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) s.bind(BINDTO) else: raise s.listen(5) try: os.chown(BINDTO,avlib.globals.UID,avlib.globals.GID) except OSError as err: (ec,es) = err.args debug.echo(2,"WARNING: Can't change socket owner: %s" % es) if ('--nodaemon' in sys.argv) or (os.fork()==0): if pidfile: pidfile.write(str(os.getpid())) pidfile.close() os.close(0) # close stdin signal.signal(signal.SIGTERM, sigterm) signal.signal(signal.SIGHUP, sighup) signal.signal(signal.SIGUSR2, aglib.sigusr2) atexit.register(rmpid) debug.echo(1,"scand: daemon started ...") mainloop(s,SCAND.SCANNER) debug.echo(1,"scand: Exiting ...")