''' filters.py - some filters which you can use in procmail... (c) 2003-2006,2019 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. ''' from aglib import * import sys __all__ = ['sgfilterd'] class sgfilterd(service): ''' A service to filter data sent by sgfilter command. This service can be used to filter an email through sagator. Some headers should be added to filtered email. A client for this service is the sgfilter script. See man sgfilter for more information. Usage: sgfilterd(scanners,host='127.0.0.1',port=27,prefork=2) Where: scanners is an array of scanners (see README.scanners for more info) host is a hostname to bind port is a tcp port to bind prefork is a number, which defines preforked process count. Set this parameter to actual processor count + 1 or leave it's default (2). Example: sgfilterd(SCANNERS) Input protocol description: MAIL FROM: sender_email\r RCPT TO: recipient_email\r DATA length\r ... Where: sender_email is sender's email address recipient_email is recipient's email address. You can send more RCPT TO: lines. length is whole data length in bytes (including control characters, as newlines, ...) Output protocol description: XXX L.LL VIRNAME ... ^D Where: XXX is three digit status, one from these: 250 - clean 251 - not clean, but sending forced 451 - an internal error occured during scanning 550 - reject 551 - drop L.LL is an floating number of virus/spam level status VIRNAME is an short description (like virus name, 'SPAM' string or other one line short description ... is modified email message (if some scanners are defined to modify scanned message) ^D is an EOF character, after message the communication is closed New in version 0.7.0. ''' name='sgfilterd()' reg_data=re.compile('^DATA ([0-9]+)\r?$',re.I) def __init__(self,scanners,host='127.0.0.1',port=27,prefork=2): self.SCANNERS=scanners self.BINDTO=(host,port) self.LISTEN=prefork*3 self.MIN_CHILDS=prefork self.EXITING=False def accept(self,connects=0): conn,addr=self.s.accept() socket_settimeout(conn,120) # reinit scanners for scnr in self.SCANNERS: scnr.reinit() globals.reset() mail.__init__() self.time2=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time())) if self.time2!=self.time1: self.time1,self.timec=self.time2,1 globals.gen_id(self.time2,self.timec) debug.echo(1,"Connection from: "+addr[0]+" at "+\ time.strftime("%c",time.localtime())) debug.echo(1,"Process id: %s" % globals.id) self.f=conn.makefile('rw') while True: line=self.f.readline() if not line: break debug.echo(5,line.rstrip()) rcptto=smtp.reg_rcptto.search(line) if rcptto: try: rcpt_email=parseaddr(tostr(rcptto.group(1)))[1] mail.recip.append(rcpt_email) except: rcpt_email=rcptto.group(1) continue mailfrom=smtp.reg_mailfrom.search(line) if mailfrom: try: mail.sender=parseaddr(tostr(mailfrom.group(1)))[1] except: mail.sender=mailfrom.group(1) data=self.reg_data.search(line) if data: count=int(data.group(1)) mail.df.write(self.f.read(count)) mail.close() debug.echo(3,"%s: BODY DONE, size: %d" % (self.name,len(mail.data))) v,level,virname=checkvir(self.SCANNERS) if v==S_OK: conn.sendall('250 %f CLEAN\r\n' % level) elif v==S_FORCE_SEND: conn.sendall('251 %f CLEAN\r\n' % level) elif v==S_REJECT: conn.sendall('550 %f %s\r\n' % (level,virname)) elif v==S_DROP: conn.sendall('551 %f %s\r\n' % (level,virname)) else: # S_TEMPFAIL conn.sendall('451 %f %s\r\n' % (level,virname)) break conn.sendall(mail.xheader) conn.sendall(mail.data) conn.sendall('\r\n') break conn.shutdown(socket.SHUT_RDWR) debug.echo(1,"Closing connection.") conn.close()