Develop and Download Open Source Software

Browse Subversion Repository

Contents of /pwmail/trunk/pro/pwmailr/pwmailr.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations) (download) (as text)
Sun Jan 8 15:58:10 2012 UTC (12 years, 4 months ago) by ykimura
File MIME type: text/x-python
File size: 26490 byte(s)


1 #! /usr/bin/python2.6
2 # -*- coding: utf-8 -*-
3
4 # <pwmailr.py Receive e-mail filters And white list filter.>
5 # Copyright (C) <2012> <yasuyosi kimura>
6 #
7 # 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 3 of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
12
13
14 ### Revision 0.0 2012/01/08 20:03:00 Test version.
15 ### Vre 0.0
16
17
18 #import os
19 import sys
20 import time
21 import traceback
22 import Milter
23 #import StringIO
24 #import email
25 #from socket import AF_INET, AF_INET6
26 from Milter.dynip import is_dynip as dynip
27 from Milter.utils import parseaddr, parse_addr, parse_header
28 from Milter.dns import Session as dnsSession
29
30 import re
31
32 import smtplib
33 from email.MIMEText import MIMEText
34 from email.Header import Header
35 from email.Utils import formatdate
36
37
38 import logging
39 import logging.handlers
40 #import MySQLdb
41
42 socketname = "inet:1025@localhost"
43 ###socketname = "/var/spool/postfix/private/rpwmiltersock"
44 sockettimeout = 600
45
46 fqdn = re.compile(r'^[a-z0-9][-a-z0-9]*(\.[a-z0-9][-a-z0-9]*)*(\.[a-z]{2,10})$')
47 fqdnjp = re.compile(r'\.[a-z]{2,2}\.jp$|([a-z0-9][-a-z0-9]{2,63}\.[a-z]{2,10})$')
48 ## print fqdnjp.search('.or.jp')
49
50 ## %(levelno)s Numeric logging level for the message (DEBUG, INFO,
51 ## WARNING, ERROR, CRITICAL)
52 log_filename = "/var/log/pwmail/pwmailr.log"
53
54 ### log_level = logging.DEBUG
55 log_level = logging.INFO
56 ### log_level = logging.WARNING
57
58 my_logger = logging.getLogger("pwmailr")
59 my_logger.setLevel(log_level)
60 ### log_fh = logging.StreamHandler(sys.stdout)
61 log_fh = logging.handlers.RotatingFileHandler(log_filename, maxBytes=1024000, backupCount=10)
62 log_fh.setLevel(logging.DEBUG)
63 log_fm = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
64 log_fh.setFormatter(log_fm)
65 my_logger.addHandler(log_fh)
66
67
68 my_domainlist = ()
69 # def my_setdomainlist():
70 # db = MySQLdb.connect(user="postfixuser", passwd="oakiki", db="postfixadmin")
71 # cur = db.cursor()
72 # cur.execute("SELECT domain FROM domain")
73 # dm = cur.fetchall()
74 # d = ()
75 # for v in dm:
76 # p = (v[0],len(v[0]))
77 # d = d + (p,)
78 # return d
79
80 # my_domainlist = my_setdomainlist()
81
82 sendmail_port = 1026
83 to_pwadmin = "pwadmin@pwmail.jp"
84 ##to_pwadmin = "kimura@oakiki.jp"
85
86 class myMilter(Milter.Base):
87
88 def __init__(self): # A new instance with each new connection.
89 self.id = Milter.uniqueID() # Integer incremented with each call.
90 # self.Fname = None # sender in SMTP form
91
92 def msg_cnvt(self, s):
93 for enc1 in ('cp932','utf8'):
94 try:
95 u = unicode(s,enc1)
96 except UnicodeDecodeError: continue
97 break
98 return u
99
100 def msg_connect(self, rcpt_addr):
101 if not self.Cname:
102 Cname = u""
103 else:
104 Cname = self.msg_cnvt(self.Cname)
105 if not self.IP:
106 IP = u""
107 else:
108 IP = self.msg_cnvt(self.IP)
109 if not self.Hname:
110 Hname = u""
111 else:
112 Hname = self.msg_cnvt(self.Hname)
113 if not self.Fname:
114 Fname = u""
115 else:
116 Fname = self.msg_cnvt(self.Fname)
117 if not rcpt_addr:
118 wrcpt_addr = u""
119 else:
120 wrcpt_addr = self.msg_cnvt(rcpt_addr)
121 try:
122 return u"connect from %s at %s\nhelo: %s\nmail from: %s\nrcpt to: %s\n" % (Cname, IP, Hname, Fname, wrcpt_addr)
123 except:
124 self.log_warning("msg_connect:", traceback.format_exc())
125 return u""
126
127 def send_admin1(self, rcpt_addr, subject, ERlevel):
128 encoding = "ISO-2022-JP"
129
130 body = self.msg_connect(rcpt_addr) + u"X-PWmail: %s\n" % self.PWmsg
131 mf = parse_addr(rcpt_addr)
132 un = mf[0]
133 pos = un.find('+')
134 if pos != -1:
135 un = un[:pos]
136 from_addr = un + "+admin@" + mf[1]
137 to_addr = un + "+" + ERlevel + "@" + mf[1]
138
139 try:
140 msg = MIMEText(body.encode(encoding,'replace'), 'plain', encoding)
141 msg['Subject'] = Header(subject, encoding)
142 msg['From'] = from_addr
143 msg['To'] = to_addr
144 msg['Date'] = formatdate()
145 except:
146 self.log_warning('send_admin1 MIMEText:',traceback.format_exc())
147 return
148
149 # SMTP���������������������������������localhost:25
150 s = smtplib.SMTP('localhost',sendmail_port,'localhost')
151 try:
152 s.sendmail(from_addr, [to_pwadmin], msg.as_string())
153 except:
154 self.log_warning('send_admin1 sendmail:',traceback.format_exc())
155 s.quit()
156
157 def msg_Header(self, hd):
158 if not self.HFrom:
159 hfrom = u""
160 else:
161 hfrom = unicode(self.HFrom, 'utf8', 'replace')
162 if not self.Subject:
163 subject = u""
164 else:
165 subject = unicode(self.Subject, 'utf8', 'replace')
166 try:
167 return u"Header-From: %s\nHeader-Subject: %s\nHeader-Date: %s\n" % (hfrom, subject, hd)
168 except:
169 self.log_warning("msg_Header:", traceback.format_exc())
170 return u""
171
172 def send_admin2(self, rcpt_addr, subject, ERlevel):
173 encoding = "ISO-2022-JP"
174 if not self.HDate:
175 hdate = ""
176 else:
177 hdate = self.HDate
178
179 body = self.msg_connect(rcpt_addr) + self.msg_Header(hdate) + u"X-PWmail: %s\n" % (self.PWmsg)
180 mf = parse_addr(rcpt_addr)
181 un = mf[0]
182 pos = un.find('+')
183 if pos != -1:
184 un = un[:pos]
185 from_addr = un + "+admin@" + mf[1]
186 to_addr = un + "+" + ERlevel + "@" + mf[1]
187
188 try:
189 msg = MIMEText(body.encode(encoding,'replace'), 'plain', encoding)
190 msg['Subject'] = Header(subject, encoding)
191 msg['From'] = from_addr
192 msg['To'] = to_addr
193 msg['Date'] = hdate
194 except:
195 self.log_warning('send_admin2 MIMEText:',traceback.format_exc())
196 return
197
198 # SMTP���������������������������������localhost:25
199 s = smtplib.SMTP('localhost',sendmail_port,'localhost')
200 try:
201 s.sendmail(from_addr, [to_pwadmin], msg.as_string())
202 except:
203 self.log_warning('send_admin2 sendmail:',traceback.format_exc())
204 s.quit()
205
206 def send_admin3(self, rcpt_addr, subject, ERlevel):
207 encoding = "ISO-2022-JP"
208 if not self.HDate:
209 hdate = ""
210 else:
211 hdate = self.HDate
212
213 body = self.msg_connect(rcpt_addr) + self.msg_Header(hdate) + u"X-PWmail: %s\n" % (self.PWmsg)
214 mf = parse_addr(rcpt_addr)
215 un = mf[0]
216 pos = un.find('+')
217 if pos != -1:
218 un = un[:pos]
219 from_addr = un + "+admin@" + mf[1]
220 to_addr = un + "+" + ERlevel + "@" + mf[1]
221
222 try:
223 msg = MIMEText(body.encode(encoding,'replace'), 'plain', encoding)
224 msg['Subject'] = Header(subject, encoding)
225 msg['From'] = from_addr
226 msg['To'] = to_addr
227 msg['Date'] = hdate
228 except:
229 self.log_warning('send_admin3 MIMEText:',traceback.format_exc())
230 return
231
232 # SMTP���������������������������������localhost:25
233 s = smtplib.SMTP('localhost',sendmail_port,'localhost')
234 try:
235 s.sendmail(from_addr, [to_addr,to_pwadmin], msg.as_string())
236 except:
237 self.log_warning('send_admin3 sendmail:',traceback.format_exc())
238 s.quit()
239
240
241 # @Milter.noreply
242 def connect(self, IPname, family, hostaddr):
243 self.log("connect from %s at %s" % (IPname, hostaddr) )
244
245 # Ini Setup
246 if hostaddr and len(hostaddr) > 0:
247 self.IP = hostaddr[0]
248 else:
249 self.log_critical("REJECT: connect attacks")
250 self.setreply('550','5.7.1', 'Banned for connect attacks')
251 return Milter.REJECT
252
253 self.IP = hostaddr[0]
254 ## self.port = hostaddr[1]
255 self.Cname = IPname.lower() # Name from a reverse IP lookup
256 if fqdn.match(self.Cname):
257 self.Cfqdn = True
258 self.Cdynip = dynip(self.Cname, self.IP)
259 self.Cipok = self.DNSCheck(IPname, self.IP)
260 if (self.Cname != IPname) and (not self.Cdynip) and (not self.Cipok):
261 self.Cipok = self.DNSCheck(self.Cname, self.IP)
262 else:
263 self.Cfqdn = False
264 self.Cipok = None
265 self.Cdynip = None
266
267 self.Hname = None
268 self.Hipok = None
269 self.Hmyd = None
270 # self.Hfqdn = None # None or (not None):True
271
272 return Milter.CONTINUE
273
274
275 # @Milter.noreply
276 def hello(self, heloname):
277 self.log("HELO",heloname)
278
279 # Ini Setup
280 self.PWmsg = ""
281 if self.Cfqdn:
282 if self.Cdynip:
283 self.PWmsg = self.PWmsg + "Cdynip " # yellow (self.Cipok) True:OK False:Error
284 if self.Cipok == None:
285 self.PWmsg = self.PWmsg + "ngCipok " # error
286 elif self.Cipok == False:
287 self.PWmsg = self.PWmsg + "noCipok " # error (self.Cdynip) True:Error False:(self.Hipok,self.Fipok) True:OK
288 else:
289 self.PWmsg = self.PWmsg + "noCfqdn "
290
291 self.Hname = heloname.lower()
292 self.Hipok = None
293 self.Hmyd = None
294
295 if not fqdn.match(self.Hname):
296 self.Hfqdn = False
297 self.Hdynip = None
298 self.PWmsg = self.PWmsg + "noHfqdn " # error (self.Cipok,self.Fipok) True:OK False:Error
299 return Milter.CONTINUE
300
301 self.Hfqdn = True
302 self.Hmyd = self.my_domain_check(self.Hname)
303 if self.Hmyd:
304 self.PWmsg = self.PWmsg + "Hmyd " # error
305 return Milter.CONTINUE
306
307 self.Hdynip = dynip(self.Hname, self.IP)
308 if self.Hdynip:
309 self.PWmsg = self.PWmsg + "Hdynip " # yellow (self.Hipok) True:OK False:Error
310 if self.Cdynip:
311 if self.Cname == self.Hname:
312 self.Hipok = self.Cipok
313 if self.Hipok == None:
314 self.PWmsg = self.PWmsg + "ngHipok " # error
315 elif self.Hipok == False:
316 self.PWmsg = self.PWmsg + "noHipok " # error (self.Cipok,self.Fipok) True:OK False:Error
317 return Milter.CONTINUE
318
319 if self.Cipok:
320 if self.eq_domain_check(self.Cname, self.Hname): #type1
321 self.Hipok = True
322 return Milter.CONTINUE
323
324 Hdmain = self.Hname
325 pos = Hdmain.find('.')
326 Hdmain = Hdmain[pos+1:]
327 if fqdnjp.search(Hdmain):
328 if self.eq_domain_check(self.Cname, Hdmain): #type2
329 self.Hipok = True
330 return Milter.CONTINUE
331
332 self.Hipok = self.DNSCheck(heloname, self.IP)
333 if (self.Hname != heloname) and (not self.Hdynip) and (not self.Hipok):
334 self.Hipok = self.DNSCheck(self.Hname, self.IP)
335
336 if self.Hipok == None:
337 self.PWmsg = self.PWmsg + "ngHipok " # error
338 elif self.Hipok == False:
339 self.PWmsg = self.PWmsg + "noHipok " # error (self.Cipok,self.Fipok) True:OK False:Error
340
341 return Milter.CONTINUE
342
343
344 # @Milter.noreply
345 def envfrom(self, mailfrom, *str):
346 self.log("mail from:", mailfrom, *str)
347
348 # Ini Setup
349 self.Fname = mailfrom
350 self.Fad = ''
351 self.Fd = ''
352 self.Ffqdn = None
353 self.Fmyd = False
354 self.Fipok = None
355 self.Fdynip = None
356 self.Relay = False
357
358 self.Rname = [] # list of recipients
359 self.RnER = False
360
361 # if self.Hmyd:
362 # return Milter.CONTINUE
363
364 if self.Fname == '<>':
365 return Milter.CONTINUE
366
367 mb = parseaddr(self.Fname)
368 ### self.log_debug('parseaddr(mailfrom):%s:(%s, %s)' % (self.Fname,mb[0],mb[1]))
369 if (mb[1] == None) or (mb[1] == ''):
370 self.Ffqdn = False
371 self.PWmsg = self.PWmsg + "noFfqdn " # error
372 return Milter.CONTINUE
373
374 self.Fad = mb[1]
375 mf = parse_addr(mb[1])
376 ### self.log_debug("domain parse_addr(mb[1]):%s:%d" % (mb[1],len(mf)))
377 if len(mf) != 2:
378 self.Ffqdn = False
379 self.PWmsg = self.PWmsg + "noFfqdn " # error
380 return Milter.CONTINUE
381
382 self.Fd = mf[1].lower()
383 if not fqdn.match(self.Fd):
384 self.Ffqdn = False
385 self.PWmsg = self.PWmsg + "noFfqdn " # error
386 return Milter.CONTINUE
387
388 self.Ffqdn = True
389
390 self.Fmyd = self.my_domain_check(self.Fd)
391 if self.Fmyd:
392 self.PWmsg = self.PWmsg + "Fmyd " # error
393 return Milter.CONTINUE
394
395 self.Fdynip = dynip(self.Fd, self.IP)
396 if self.Fdynip:
397 self.PWmsg = self.PWmsg + "Fdynip " # error
398
399 self.Fipok = self.DNSCheck(self.Fd, self.IP)
400 if self.Fipok == None:
401 self.PWmsg = self.PWmsg + "ngFipok " # error
402 return Milter.CONTINUE
403
404 if (self.Fipok == False):
405 self.PWmsg = self.PWmsg + "noFipok " # OK
406 if (self.Hipok):
407 if not self.eq_domain_check(self.Hname, self.Fd):
408 self.Relay = True
409 self.PWmsg = self.PWmsg + "relay " # yellow
410 elif (self.Cipok):
411 if not self.eq_domain_check(self.Cname, self.Fd):
412 self.Relay = True
413 self.PWmsg = self.PWmsg + "relay " # yellow
414
415 return Milter.CONTINUE
416
417
418 # @Milter.noreply
419 def envrcpt(self, recipient, *str):
420 ## ������������������������������������������������������
421 self.log("rcpt to:", recipient, ":", *str)
422 self.Rname.append(recipient)
423
424 if recipient.find('+') != -1:
425 self.RnER = True
426 #######################Abort
427 self.setreply('550','5.1.1','<%s>: Recipient address rejected: User unknown.' % (recipient))
428 self.log_critical('550','(%s:%s) %s %s: Recipient address rejected: User unknown.' % (self.Hname,self.IP,self.Fname,recipient))
429 self.send_admin1(recipient, u"���������������������", "abort")
430 return Milter.REJECT
431
432 return Milter.CONTINUE
433
434
435 # @Milter.noreply
436 def data(self):
437 self.log_debug("data")
438
439 ## Abort ���������������
440 ###++++++++++++++++++++Error self.Fname == '<>' self.Ffqdn == None (postmaster) OK
441 if (not self.Hfqdn) and (not self.Cipok) and (not self.Fipok):
442 self.setreply('504','5.5.2','<%s>: Helo command rejected: need fully-qualified hostname.' % (self.Hname))
443 self.log_critical('504','(%s:%s) %s %s: Helo command rejected: need fully-qualified hostname.' % (self.Hname,self.IP,self.Fname,self.Rname))
444 return Milter.REJECT
445
446 ###++++++++++++++++++++Error self.Fname == '<>' self.Ffqdn == None (postmaster) OK
447 if (not self.Cipok) and (not self.Hipok) and (not self.Fipok):
448 self.setreply('550','5.7.1','(%s:%s): Helo command rejected: Host not found.' % (self.Hname,self.IP))
449 self.log_critical('550','(%s:%s) %s %s: Helo command rejected: Host not found.' % (self.Hname,self.IP,self.Fname,self.Rname))
450 return Milter.REJECT
451
452 ## ������������������������������������
453 #######################Abort
454 if self.Hmyd:
455 self.setreply('504','5.5.2','<%s>: Helo command rejected: Breach of Local Policy.' % (self.Hname))
456 self.log_critical('504','(%s:%s) %s %s: Helo command rejected: Breach of Local Policy.' % (self.Hname,self.IP,self.Fname,self.Rname))
457 for rad in self.Rname:
458 self.send_admin1(rad, u"���������������������������������������", "abort")
459 return Milter.REJECT
460
461 #######################Abort
462 if (self.Ffqdn == False) or (self.Fdynip):
463 self.setreply('504','5.5.2','%s: Sender address rejected: need fully-qualified address.' % (self.Fname))
464 self.log_critical('504','(%s:%s) %s %s: Sender address rejected: need fully-qualified address.' % (self.Hname,self.IP,self.Fname,self.Rname))
465 for rad in self.Rname:
466 self.send_admin1(rad, u"���������������������", "abort")
467 return Milter.REJECT
468
469 #######################Abort
470 if self.Fmyd:
471 self.setreply('504','5.5.2','%s: Sender address rejected: Breach of Local Policy.' % (self.Fname))
472 self.log_critical('504','(%s:%s) %s %s: Sender address rejected: Breach of Local Policy.' % (self.Hname,self.IP,self.Fname,self.Rname))
473 for rad in self.Rname:
474 self.send_admin1(rad, u"������������������������������", "abort")
475 return Milter.REJECT
476
477 ## ������������������������������������������������������������
478 #######################Abort self.Fname != '<>'
479 if (self.Ffqdn) and (self.Fipok == None):
480 self.setreply('550','5.7.1','%s: Sender address rejected: Breach of Domain.' % (self.Fname))
481 self.log_critical('550','(%s:%s) %s %s: Sender address rejected: Breach of Domain.' % (self.Hname,self.IP,self.Fname,self.Rname))
482 for rad in self.Rname:
483 self.send_admin1(rad, u"������������������������������", "abort")
484 return Milter.REJECT
485
486
487
488 # Ini Setup
489 self.FromAD = []
490 self.HFrom = None
491 self.HDate = None
492 self.Subject = None
493 self.HMid = None
494 self.HList = None
495
496 # if self.Relay:
497 # self.log_warning('relay mail helo(%s:%s) from:%s to:%s' % (self.Hname, self.IP, self.Fname, ' '.join([m for m in self.Rname])))
498
499 return Milter.CONTINUE
500
501
502 # @Milter.noreply
503 def header(self, name, hval):
504 ### self.log_debug("header:%s: %s" % (name,hval))
505
506 nbuf = name.lower()
507 if nbuf == "from":
508 ms = []
509 adbuf = hval.split(',')
510 for ad in adbuf:
511 ma = parseaddr(ad)
512 mn = parse_header(ma[0])
513 ms.append(mn + ' <' + ma[1] + '>')
514 self.FromAD.append((mn, ma[1]))
515 mf = ",".join(ms)
516 if not self.HFrom:
517 self.HFrom = mf
518 else:
519 self.HFrom = self.HFrom + ',' + mf
520 self.log_debug("Header-From-B:", hval)
521 self.log("Header-From:", mf)
522 elif nbuf == "date":
523 self.HDate = hval
524 elif nbuf == "subject":
525 self.Subject = parse_header(hval)
526 self.log_debug("Subject-B:", hval)
527 self.log("Subject:", self.Subject)
528 elif nbuf == "message-id":
529 self.log("Message-ID:", hval)
530 self.HMid = hval
531 elif nbuf.startswith("list-"):
532 self.HList = True
533
534 return Milter.CONTINUE
535
536
537 # @Milter.noreply
538 def eoh(self):
539 self.log_debug("eoh")
540
541 if not self.HDate:
542 self.PWmsg = self.PWmsg + "noHDate " # error
543 if not self.HMid:
544 self.PWmsg = self.PWmsg + "noHMid " # yellow (self.Cdynip,self.Hdynip,self.Relay) True:Error
545
546 #######################
547 self.HFfqdn = None
548
549 self.HFmyd = False
550 self.HFdynip = None
551 self.HFipok = None
552 # self.HFadER = None
553 self.HFdnok = None
554 self.HFadok = None
555 self.HFromAD = None
556
557 if len(self.FromAD) != 1:
558 self.HFadER = True
559 self.PWmsg = self.PWmsg + "HFadER "
560 else:
561 self.HFadER = False
562 ad = self.FromAD[0][1]
563 self.HFromAD = ad
564 ### ������������������������
565 if (ad[0] == "'") and (ad[-1] == "'"):
566 ad = ad[1:-1]
567 ### ������������������������
568 if (ad == None) or (ad == ''):
569 self.HFfqdn = False
570 self.PWmsg = self.PWmsg + "noHFfqdn "
571 else:
572 mf = parse_addr(ad)
573 if len(mf) != 2:
574 self.HFfqdn = False
575 self.PWmsg = self.PWmsg + "noHFfqdn "
576 else:
577 dn = mf[1].lower()
578 if not fqdn.match(dn):
579 self.HFfqdn = False
580 self.PWmsg = self.PWmsg + "noHFfqdn "
581 else:
582 self.HFfqdn = True
583 self.HFmyd = self.my_domain_check(dn)
584 if self.HFmyd:
585 self.PWmsg = self.PWmsg + "HFmyd "
586 else:
587 self.HFdynip = dynip(dn, self.IP)
588 if self.HFdynip:
589 self.PWmsg = self.PWmsg + "HFdynip "
590 self.HFipok = self.DNSCheck(dn, self.IP)
591 if self.HFipok == None:
592 self.PWmsg = self.PWmsg + "ngHFipok "
593 elif self.HFipok == False:
594 self.PWmsg = self.PWmsg + "noHFipok "
595 if self.Ffqdn:
596 if self.Fd == dn:
597 self.HFdnok = True
598 else:
599 self.HFdnok = False
600 self.PWmsg = self.PWmsg + "noHFdnok "
601 if self.Fad == ad:
602 self.HFadok = True
603 else:
604 self.HFadok = False
605 self.PWmsg = self.PWmsg + "noHFadok "
606
607 if self.HList:
608 self.PWmsg = self.PWmsg + "List "
609
610 if self.PWmsg != "":
611 self.log("X-PWmail:", self.PWmsg)
612
613
614 ## ������������������������������������������������������������
615 #######################Abort self.Fname != '<>'
616 ## if (self.Ffqdn) and (self.Fipok == None):
617 ## self.setreply('550','5.7.1','%s: Sender address rejected: Breach of Domain.' % (self.Fname))
618 ## self.log_critical('550','(%s:%s) %s %s: Sender address rejected: Breach of Domain.' % (self.Hname,self.IP,self.Fname,self.Rname))
619 ## for rad in self.Rname:
620 ## self.send_admin2(rad, u"������������������������������", "abort")
621 ## return Milter.REJECT
622
623
624 ###--------------------Abort
625 if not self.HDate:
626 self.setreply('550','5.7.1','Breach of Header-Date Policy.')
627 self.log_critical('550','Breach of Header-Date Policy.')
628 for rad in self.Rname:
629 self.send_admin2(rad, u"���������������������������", "abort")
630 return Milter.REJECT
631
632 ###--------------------Abort
633 if (self.HFadER) or (not self.HFfqdn) or (self.HFmyd) or (self.HFdynip):
634 self.setreply('550','5.7.1','%s: Breach of Header-From Local Policy.' % (','.join([m for d, m in self.FromAD])))
635 self.log_critical('550','(%s): Breach of Header-From Local Policy.' % (','.join([m for d, m in self.FromAD])))
636 for rad in self.Rname:
637 self.send_admin2(rad, u"������������������", "abort")
638 return Milter.REJECT
639
640 ###--------------------Abort
641 # if not self.HFfqdn:
642 # self.setreply('550','5.7.1','%s: Header-From address rejected: need fully-qualified address.' % (self.HFromAD))
643 # self.log_critical('550','%s: Header-From address rejected: need fully-qualified address.' % (self.HFromAD))
644 # for rad in self.Rname:
645 # self.send_admin2(rad, u"���������������������", "abort")
646 # return Milter.REJECT
647
648 ###--------------------Abort
649 if not self.HMid:
650 self.setreply('550','5.7.1','%s: Breach of Message-ID Local Policy.' % (','.join([m for d, m in self.FromAD])))
651 self.log_critical('550','(%s): Breach of Message-ID Local Policy.' % (','.join([m for d, m in self.FromAD])))
652 for rad in self.Rname:
653 self.send_admin2(rad, u"Message-ID���������", "abort")
654 return Milter.REJECT
655
656
657 ## ������������������������������������������������������black
658 # ���������������������������������������������������������self.send_admin���������������
659 # X-PWmail: Cdynip ngHipok noFipok relay noHFipok ���������������������
660 # X-PWmail: Cdynip noHfqdn noFipok relay noHFipok ���������������������
661
662 ###--------------------Abort
663 if (self.Cdynip) and ((self.Hipok == None) or (not self.Hfqdn)):
664 self.setreply('550','5.7.1','(%s:%s): Helo command rejected: Host not found.' % (self.Hname,self.IP))
665 self.log_critical('550','(%s:%s) %s %s: Helo command rejected: Host not found.' % (self.Hname,self.IP,self.Fname,self.Rname))
666 for rad in self.Rname:
667 self.send_admin3(rad, u"������������������������������������", "abort")
668 return Milter.REJECT
669
670 if (self.Cdynip) or (self.Hdynip) or ((self.Relay) and (self.HList)):
671 msg = u"������������"
672 if (self.Cdynip) or (self.Hdynip):
673 msg = msg + u"������������������������������"
674 if (self.Relay) and (self.HList):
675 msg = msg + u"���������������������������"
676
677 for rad in self.Rname:
678 self.send_admin3(rad, msg, "black")
679
680
681 return Milter.CONTINUE
682
683
684 def eom(self):
685 self.log_debug("eom")
686
687 self.addheader('X-PWfrom',self.Fname)
688
689 if self.PWmsg != "":
690 self.addheader('X-PWmail',self.PWmsg)
691
692 return Milter.CONTINUE
693
694 def abort(self):
695 self.log_debug("abort")
696 return Milter.CONTINUE
697
698 def close(self):
699 #
700 # End Setup
701 #
702 # always called, even when abort is called. Clean up
703 # any external resources here.
704 self.log("close")
705 return Milter.CONTINUE
706
707
708 ## === Support Functions ===
709
710 def my_domain_check(self,td):
711 tl = len(td)
712 for d, l in my_domainlist:
713 if tl == l:
714 if td == d:
715 return True
716 elif tl > l:
717 if td.endswith(d):
718 if td[tl - l -1] == '.':
719 return True
720 return False
721
722 def eq_domain_check(self, td, d):
723 tl = len(td)
724 l = len(d)
725 if tl == l:
726 if td == d:
727 return True
728 elif tl > l:
729 if td.endswith(d):
730 if td[tl - l -1] == '.':
731 return True
732 return False
733
734 def DNSCheck(self,name,ipad):
735 aok = False
736 rv = False
737 rm = 'A'
738 s = dnsSession()
739 ads = s.dns(name, 'A')
740 if len(ads) > 0:
741 aok = True
742 for a in ads:
743 if a == ipad:
744 rv = True
745 break
746 if rv == False:
747 rm = 'MX'
748 mxr = s.dns(name, 'MX')
749 l = len(mxr)
750 if l > 0:
751 for v,n in mxr:
752 ads = s.dns(n, 'A')
753 if len(ads) > 0:
754 for a in ads:
755 if a == ipad:
756 rv = True
757 elif not a:
758 rm = 'MA'
759 rv = None
760 else:
761 ads = s.dns(n, 'AAAA')
762 if len(ads) > 0:
763 for a in ads:
764 if not a:
765 rm = 'MAAAA'
766 rv = None
767 else:
768 rm = 'MA'
769 rv = None
770 else:
771 if aok == False:
772 rv = None
773 return rv
774
775 def log_debug(self, *msg):
776 my_logger.debug('[%d] %s',self.id,' '.join([str(m) for m in msg]))
777
778 def log(self,*msg):
779 my_logger.info('[%d] %s',self.id,' '.join([str(m) for m in msg]))
780
781 def log_warning(self, *msg):
782 my_logger.warning('[%d] %s',self.id,' '.join([str(m) for m in msg]))
783
784 def log_error(self, *msg):
785 my_logger.error('[%d] %s',self.id,' '.join([str(m) for m in msg]))
786
787 def log_critical(self, *msg):
788 my_logger.critical('[%d] %s',self.id,' '.join([str(m) for m in msg]))
789
790
791 ## ===
792
793 def main():
794 ## smtpd_milters = unix:private/pwmailsock
795 ## socketname = "inet:port@localhost"
796 ## sockettimeout = 600
797 my_logger.info("pwmailr startup")
798
799 global my_domainlist
800 s = sys.argv[1]
801 for v in s.split(','):
802 p = (v,len(v))
803 my_domainlist = my_domainlist + (p,)
804
805 my_logger.info("mydomain:" + str(my_domainlist))
806
807 # Register to have the Milter factory create instances of your class:
808 # protocol_flags = Milter.P_NR_CONN + Milter.P_NR_HELO + Milter.P_NR_MAIL + Milter.P_NR_RCPT
809 # protocol_flags += Milter.P_NR_DATA + Milter.P_NR_HDR + Milter.P_NR_EOH
810 # Milter.factory = Milter.enable_protocols(myMilter, protocol_flags)
811
812 Milter.factory = myMilter
813 flags = Milter.ADDHDRS
814 Milter.set_flags(flags) # tell Sendmail which features we use
815
816 Milter.runmilter("pwmailr",socketname,sockettimeout)
817 my_logger.info("pwmailr shutdown")
818
819 if __name__ == "__main__":
820 main()
821

Properties

Name Value
svn:executable *

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26