From c0aa632e166f1637177238b26dda3ef46dbc2c93 Mon Sep 17 00:00:00 2001 From: Stuart Gathman <stuart@gathman.org> Date: Thu, 11 Jan 2007 04:31:26 +0000 Subject: [PATCH] Negative feedback for bad headers. Purge cache logs on startup. --- Milter/cache.py | 15 +++++++++--- Milter/plock.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ bms.py | 8 ++++++- 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 Milter/plock.py diff --git a/Milter/cache.py b/Milter/cache.py index 8f9c824..17b2765 100644 --- a/Milter/cache.py +++ b/Milter/cache.py @@ -10,6 +10,9 @@ # CBV results. # # $Log$ +# Revision 1.3 2007/01/08 23:20:54 customdesigned +# Get user feedback. +# # Revision 1.2 2007/01/05 23:33:55 customdesigned # Make blacklist an AddrCache # @@ -22,6 +25,7 @@ # This code is under the GNU General Public License. See COPYING for details. import time +from plock import PLock class AddrCache(object): time_format = '%Y%b%d %H:%M:%S %Z' @@ -39,6 +43,8 @@ class AddrCache(object): cache = {} self.cache = cache now = time.time() + lock = PLock(self.fname) + wfp = lock.lock() try: too_old = now - age*24*60*60 # max age in days for ln in open(self.fname): @@ -46,11 +52,14 @@ class AddrCache(object): rcpt,ts = ln.strip().split(None,1) l = time.strptime(ts,AddrCache.time_format) t = time.mktime(l) - if t > too_old: - cache[rcpt.lower()] = (t,None) + if t < too_old: continue + cache[rcpt.lower()] = (t,None) except: cache[ln.strip().lower()] = (now,None) - except IOError: pass + wfp.write(ln) + lock.commit(self.fname+'.old') + except IOError: + lock.unlock() def has_key(self,sender): "True if sender is cached and has not expired." diff --git a/Milter/plock.py b/Milter/plock.py new file mode 100644 index 0000000..d4df9b7 --- /dev/null +++ b/Milter/plock.py @@ -0,0 +1,62 @@ +# Author: Stuart D. Gathman <stuart@bmsi.com> +# Copyright 2001 Business Management Systems, Inc. +# This code is under the GNU General Public License. See COPYING for details. + +import os +from time import sleep + +class PLock(object): + "A simple /etc/passwd style lock,update,rename protocol for updating files." + def __init__(self,basename): + self.basename = basename + self.fp = None + + def lock(self,lockname=None): + "Start an update transaction. Return FILE to write new version." + self.unlock() + if not lockname: + lockname = self.basename + '.lock' + self.lockname = lockname + st = os.stat(self.basename) + u = os.umask(0002) + try: + fd = os.open(lockname,os.O_WRONLY+os.O_CREAT+os.O_EXCL,st.st_mode|0660) + finally: + os.umask(u) + self.fp = os.fdopen(fd,'w') + try: + os.chown(self.lockname,-1,st.st_gid) + except: + self.unlock() + raise + return self.fp + + def wlock(self,lockname=None): + "Wait until lock is free, then start an update transaction." + while True: + try: + return self.lock(lockname) + except OSError: + sleep(2) + + def commit(self,backname=None): + "Commit update transaction with optional backup file." + if not self.fp: + raise IOError,"File not locked" + self.fp.close() + self.fp = None + if backname: + try: + os.remove(backname) + except OSError: pass + os.link(self.basename,backname) + os.rename(self.lockname,self.basename) + + def unlock(self): + "Cancel update transaction." + if self.fp: + try: + self.fp.close() + except: pass + self.fp = None + os.remove(self.lockname) diff --git a/bms.py b/bms.py index 4032c5d..5b63069 100644 --- a/bms.py +++ b/bms.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # A simple milter that has grown quite a bit. # $Log$ +# Revision 1.84 2007/01/10 04:44:25 customdesigned +# Documentation updates. +# # Revision 1.83 2007/01/08 23:20:54 customdesigned # Get user feedback. # @@ -1017,7 +1020,10 @@ class bmsMilter(Milter.Milter): val = parse_header(hval) if not self.internal_connection and not (self.blacklist or self.whitelist): rc = self.check_header(name,val) - if rc != Milter.CONTINUE: return rc + if rc != Milter.CONTINUE: + if gossip and self.umis: + gossip_node.feedback(self.umis,1) + return rc elif self.whitelist_sender and lname == 'subject': # check for AutoReplys vl = val.lower() -- GitLab