Skip to content
Snippets Groups Projects
Commit 073f87dc authored by Stuart Gathman's avatar Stuart Gathman
Browse files

Handle perverse MFROM quoting.

parent 7ab5ddf0
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python #!/usr/bin/env python
# A simple milter that has grown quite a bit. # A simple milter that has grown quite a bit.
# $Log$ # $Log$
# Revision 1.24 2005/08/18 03:36:54 customdesigned
# Don't innoculate with SCREENED mail.
#
# Revision 1.23 2005/08/17 19:35:27 customdesigned # Revision 1.23 2005/08/17 19:35:27 customdesigned
# Send DSN before adding message to quarantine. # Send DSN before adding message to quarantine.
# #
...@@ -334,7 +337,7 @@ time_format = '%Y%b%d %H:%M:%S %Z' ...@@ -334,7 +337,7 @@ time_format = '%Y%b%d %H:%M:%S %Z'
timeout = 600 timeout = 600
cbv_cache = {} cbv_cache = {}
try: try:
too_old = time.time() - 30*24*60*60 # 30 days too_old = time.time() - 7*24*60*60 # 7 days
for ln in open('send_dsn.log'): for ln in open('send_dsn.log'):
try: try:
rcpt,ts = ln.strip().split(None,1) rcpt,ts = ln.strip().split(None,1)
...@@ -515,7 +518,22 @@ def read_config(list): ...@@ -515,7 +518,22 @@ def read_config(list):
#print srs_domain #print srs_domain
def parse_addr(t): def parse_addr(t):
"""Split email into user,domain.
>>> parse_addr('user@example.com')
['user', 'example.com']
>>> parse_addr('"user@example.com"')
['"user@example.com"']
>>> parse_addr('"user@bar"@example.com')
['"user@bar"','example.com']
>>> parse_addr('foo')
['foo']
"""
if t.startswith('<') and t.endswith('>'): t = t[1:-1] if t.startswith('<') and t.endswith('>'): t = t[1:-1]
if t.startswith('"'):
if t.endswith('"'): return [t[1:-1]]
pos = t.find('"@')
if pos > 0: return [t[1:pos],t[pos+2:]]
return t.split('@') return t.split('@')
def parse_header(val): def parse_header(val):
...@@ -733,7 +751,7 @@ class bmsMilter(Milter.Milter): ...@@ -733,7 +751,7 @@ class bmsMilter(Milter.Milter):
'SPF fail: see http://openspf.com/why.html?sender=%s&ip=%s' % (q.s,q.i)) 'SPF fail: see http://openspf.com/why.html?sender=%s&ip=%s' % (q.s,q.i))
res,code,txt = q.check() res,code,txt = q.check()
q.result = res q.result = res
if res == 'unknown' and q.perm_error: if res == 'unknown' and q.perm_error and q.perm_error.ext:
self.cbv_needed = q # report SPF syntax error to sender self.cbv_needed = q # report SPF syntax error to sender
res,code,txt = q.perm_error.ext # extended (lax processing) result res,code,txt = q.perm_error.ext # extended (lax processing) result
txt = 'EXT: ' + txt txt = 'EXT: ' + txt
...@@ -999,7 +1017,21 @@ class bmsMilter(Milter.Milter): ...@@ -999,7 +1017,21 @@ class bmsMilter(Milter.Milter):
self.fp.write("%s: %s\n" % (name,val)) # add new headers to buffer self.fp.write("%s: %s\n" % (name,val)) # add new headers to buffer
self.fp.write("\n") # terminate headers self.fp.write("\n") # terminate headers
self.fp.seek(0) self.fp.seek(0)
# log when neither sender nor from domains matches mail from domain
mf_domain = self.canon_from.split('@')[-1]
msg = rfc822.Message(self.fp)
for rn,hf in msg.getaddrlist('from')+msg.getaddrlist('sender'):
t = parse_addr(hf)
if len(t) == 2 and t[1].lower() == mf_domain:
break
else:
self.log("NOTE: MFROM domain doesn't match From or Sender");
for f in msg.getallmatchingheaders('from') \
+ msg.getallmatchingheaders('sender'):
self.log(f)
del msg
# copy headers to a temp file for scanning the body # copy headers to a temp file for scanning the body
self.fp.seek(0)
headers = self.fp.getvalue() headers = self.fp.getvalue()
self.fp.close() self.fp.close()
fd,fname = tempfile.mkstemp(".defang") fd,fname = tempfile.mkstemp(".defang")
......
import unittest import unittest
import doctest
import Milter import Milter
import bms import bms
import mime import mime
...@@ -22,7 +23,7 @@ class TestMilter(bms.bmsMilter): ...@@ -22,7 +23,7 @@ class TestMilter(bms.bmsMilter):
def getsymval(self,name): def getsymval(self,name):
if name == 'j': return 'test.milter.org' if name == 'j': return 'test.milter.org'
return bms.bmsMilter.getsymval(self,name) return ''
def replacebody(self,chunk): def replacebody(self,chunk):
if self._body: if self._body:
...@@ -284,7 +285,10 @@ class BMSMilterTestCase(unittest.TestCase): ...@@ -284,7 +285,10 @@ class BMSMilterTestCase(unittest.TestCase):
# self.failUnless(rc == Milter.REJECT) # self.failUnless(rc == Milter.REJECT)
# milter.close(); # milter.close();
def suite(): return unittest.makeSuite(BMSMilterTestCase,'test') def suite():
s = unittest.makeSuite(BMSMilterTestCase,'test')
s.addTest(doctest.DocTestSuite(bms))
return s
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 1: if len(sys.argv) > 1:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment