import asynchat, asyncore, socket import pwd, os, sys, logging, logging.handlers import mailbox, email 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 self.push("220 Mailserver terrorist.at. Nutzung ohne vorige Erlaubnis verboten!\n") def collect_incoming_data(self, data): if len(self.data) > 0: self.data += "\n" self.data += data self.server.logger.debug("Read: " + data.strip()) if self.data.__len__() > 16384: self.server.logger.error("too much data, shutdown") self.close_when_done() def push(self,data): self.server.logger.debug("Write: " + data) synchat.async_chat.push(self,data) def found_terminator(self): try: if self.read_data: if self.data.endswith(".") or self.data.endswith(".\r"): self.read_data = False self.push("250 Ok: queued as 12345\n") mail = email.message_from_string(self.data) key=self.server.maildir.add(mail) self.server.logger.info("New Mail: %s" % key) self.server.maildir.flush() self.data = "" else: pass elif self.data.startswith("EHLO") \ or self.data.startswith("HELO"): self.push("250 Mailserver terrorist.at. Nutzung ohne vorige Erlaubnis verboten!\n") self.data = "" elif self.data.startswith("DATA"): self.push("354 End data with .\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 = "" except Exception,e: self.server.logger.error(str(e)) 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 = mailbox.Maildir("Maildir", create=True) self.logger = logging.getLogger('MyLogger') self.logger.setLevel(logging.DEBUG) handler = logging.handlers.TimedRotatingFileHandler("log/smtp.log", "D", 1) self.logger.addHandler(handler) def handle_accept(self): conn, addr = self.accept() self.logger.info("New Client %s:%s" % conn.getpeername()) try: SMTPChannel(self, conn, addr) except Exception,e: self.logger.error(str(e)) 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: if os.fork() > 0: 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: pid = os.fork() if pid > 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 #""" s.logger.info("Startup; pid=%s" % os.getpid()) asyncore.loop()