1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
import asynchat, asyncore, socket
import pwd, os, sys
import email
from mailbox import Maildir,MaildirMessage
class SMTPChannel(asynchat.async_chat):
def __init__(self, server, sock, addr):
asynchat.async_chat.__init__(self, sock)
self.server = server
self.set_terminator("\n")
self.data = ""
self.read_data = False
def collect_incoming_data(self, data):
if len(self.data) > 0:
self.data += "\n"
self.data += data
if self.data.__len__() > 16384:
print "too much data, shutdown"
self.close_when_done()
def found_terminator(self):
print self.data
if self.read_data:
if self.data.endswith("\n."):
self.push("250 Ok: queued as 12345\n")
self.read_data = False
mail = email.message_from_string(self.data)
self.server.maildir.add(mail)
self.server.maildir.flush()
self.data = ""
elif self.data.startswith("EHLO") \
or self.data.startswith("HELO"):
self.push("HELO there\n")
self.data = ""
elif self.data.startswith("DATA"):
self.push("354 End data with <CR><LF>.<CR><LF>\n")
self.read_data = True
self.data=""
elif self.data.startswith("QUIT"):
self.data = ""
self.push("221 Bye\n")
self.close_when_done()
else:
self.push("250 OK\n")
self.data = ""
class SMTPServer(asyncore.dispatcher):
def __init__(self):
asyncore.dispatcher.__init__(self)
self.port = 25
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(("", self.port))
self.listen(5)
self.maildir = Maildir("Maildir", create=True)
def handle_accept(self):
conn, addr = self.accept()
SMTPChannel(self, conn, addr)
if __name__ == '__main__':
s = SMTPServer()
#user change
pwinfo = pwd.getpwnam('nobody')
os.setregid(pwinfo[3],pwinfo[3])
os.setreuid(pwinfo[2],pwinfo[2])
#"Robustly turn into a UNIX daemon, running in our_home_dir."
# First fork
try:
pid = os.fork()
if pid > 0:
print "PID: %s" % pid
sys.exit(0) # kill off parent
except OSError, e:
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
os.setsid()
os.chdir('/')
os.umask(0)
# Second fork
try:
if os.fork() > 0:
os._exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
os._exit(1)
si = open('/dev/null', 'r')
so = open('/dev/null', 'a+', 0)
se = open('/dev/null', 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# Set custom file descriptors so that they get proper buffering.
sys.stdout, sys.stderr = so, se
asyncore.loop()
|