Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

forced indentation of smtp

Name: Anonymous 2007-10-25 10:06

Hey guys, I am the OP from http://dis.4chan.org/read/prog/1193225538/. It's quite shit, but here is what I ended up writing:

# vsss
# (very simple smtp server)
# revision 0.1

import socket, threading, urllib, os, random, datetime

HOSTNAME = ''
VALID_RECIPIENTS = [
    ('dis.4chan.org', ['prog', 'VIP']),
    ('example.com',   ['lol'])
    ]
MAIL_PATH = 'Z:\MAIL'
DEBUG = False

########################################

CRLF = "\r\n"

def gethostname():

    try:
        # this returns ip address of the requestor
        # i do it this way to help NAT'd servers find their external address
        ipuo = urllib.urlopen('http://zxcsh.com/ip/')
        ip = ipuo.read()
    except:
        try:
            # if that doesn't work, just get hostname in usual way
            hn = socket.gethostname()
        except:
            # and if that fails too, just make one up
            hn = 'vsss'
    else:
        try:
            # hostname using reverse dns
            hn = socket.gethostbyaddr(ip)[0]
        except:
            # or just the ip address if lookup fails
            hn = '[' + ip + ']'
    return hn


class SMTPServer(threading.Thread):

    def __init__(self, sock, addr, port):

        threading.Thread.__init__(self)
        self.sock = sock
        self.addr = addr
        self.port = port
        self.buffer = ''
        self.running = True
       
        self.remotehost = None
        self.returnpath = None
        self.recipients = []

        self.debug('new connection')

    def debug(self, message):
        if DEBUG:
            print self.addr+':'+str(self.port)+' '+message

    def run(self):

        # send greeting
        self.sendline(220, HOSTNAME+' ESMTP')

        # loop until quit
        while self.running:
            line = self.getline()
            if line == None:
                break;
            command = line.partition(' ')
            try:
                getattr(self, 'cmd_'+command[0].lower())(command[2])
            except AttributeError:
                self.resp_badcmd()

        # this checks if it was a clean exit or not
        if not self.running:
            self.sendline(221, '2.0.0 '+HOSTNAME+' Service closing transmission channel')

        self.sock.close()
        self.debug('connection closed')

    def getline(self):
        # keep filling buffer until it contains a crlf
        while CRLF not in self.buffer:
            recvbuf = self.sock.recv(4096)
            if recvbuf == '':
                return None
            self.buffer += recvbuf
        # then return everything up to the crlf, and keep the rest in the buffer
        crlfpart = self.buffer.partition(CRLF)
        self.buffer = crlfpart[2]
        self.debug('<<< '+crlfpart[0])
        return crlfpart[0]

    def sendline(self, status, message):
        if type(message) == str:
            message = [message]
        for line in message[:-1]:
            self.sendline2(str(status)+'-'+line)
        self.sendline2(str(status)+' '+message[-1])

    def sendline2(self, output):
        self.sock.send(output+CRLF)
        self.debug('>>> '+output)

    def resp_badcmd(self):
        self.sendline(502, '5.5.1 Syntax error, command unrecognized')

    def resp_ok(self):
        self.sendline(250, '2.0.0 OK')

    def resp_noremotehost(self):
        self.sendline(503, '5.5.1 Commands out of sequence, require HELO or EHLO')

    def resp_noreturnpath(self):
        self.sendline(503, '5.5.1 Commands out of sequence, require MAIL FROM')

    def resp_norecipients(self):
        self.sendline(503, '5.5.1 Commands out of sequence, require RCPT TO')

    def resp_badreturnpath(self):
        self.sendline(501, '5.5.4 Return path is invalid')

    def resp_badaddress(self):
        self.sendline(501, '5.5.4 Recipient address is invalid')

    def resp_baddomain(self):
        self.sendline(550, '5.7.1 Unable to relay')

    def resp_badrecipient(self):
        self.sendline(550, '5.7.1 Recipient address does not exist')

    def resp_dataerror(self):
        self.sendline(451, '4.3.0 Unknown error while accepting mail, try later')
       
    def cmd_helo(self, args):
        self.sendline(250, HOSTNAME+' says hello')
        self.remotehost = args.strip()

    def cmd_ehlo(self, args):
        self.sendline(250, [HOSTNAME+' says hello','8BITMIME','ENHANCEDSTATUSCODES'])
        self.remotehost = args.strip()

    def check_returnpath(self, returnpath):
        # (TODO: read the relevant RFCs and do this properly)
        if returnpath == '':
            return True
        atsplit = returnpath.split('@')
        if len(atsplit) == 2 and len(atsplit[0]) > 0 and len(atsplit[1]) > 0:
            return True
        return False

    def cmd_mail(self, args):
        if args[:5].lower() != 'from:':
            self.resp_badcmd()
        else:
            if self.remotehost == None:
                self.resp_noremotehost()
            else:
                args = args[5:].strip()
                if args == '':
                    self.resp_badreturnpath()
                    return
                # ignore any other args
                rp = args.partition(' ')[0]
                if rp[0] == '<':
                    if rp[-1] == '>':
                        rp = rp[1:-1]
                    else:
                        self.resp_badreturnpath()
                        return
                if self.check_returnpath(rp):
                    self.returnpath = rp
                    self.resp_ok()
                else:
                    self.resp_badreturnpath()

    def cmd_rcpt(self, args):
        if args[:3].lower() != 'to:':
            self.resp_badcmd()
        else:
            if self.remotehost == None:
                self.resp_noremotehost()
            elif self.returnpath == None:
                self.resp_noreturnpath()
            else:
                args = args[3:].strip()
                if args == '':
                    self.resp_badaddress()
                    return
                ra = args.partition(' ')[0]
                if ra[0] == '<':
                    if ra[-1] == '>':
                        ra = ra[1:-1]
                    else:
                        self.resp_badaddress()
                        return
                atsplit = ra.split('@')
                if not (len(atsplit) == 2 and len(atsplit[0])>0 and len(atsplit[1])>0):
                    self.resp_badaddress()
                    return
                matchvr = None
                for vr in VALID_RECIPIENTS:
                    if atsplit[1].lower() == vr[0].lower():
                        matchvr = vr
                if matchvr == None:
                    self.resp_baddomain()
                    return
                for recp in matchvr[1]:
                    if atsplit[0].lower() == recp:
                        self.recipients.append((matchvr[0],recp))
                        self.resp_ok()
                        return
                self.resp_badrecipient()

    def chdir_mkdir(self, dir):
        try:
            os.chdir(dir)
        except:
            os.mkdir(dir)
            os.chdir(dir)

    def random_string(self):
        s = ''
        for i in range(1,16):
            s += chr(random.randint(96,122))
        return s
   
    def cmd_data(self, args):
        if self.remotehost == None:
            self.resp_noremotehost()
        if self.returnpath == None:
            self.resp_noreturnpath()
        elif self.recipients == []:
            self.resp_norecipients()
        else:
            self.sendline(354, 'Start mail input; end with <CRLF>.<CRLF>')
            message = ''
            line = self.getline()
            while line != '.':
                if line[:1] == '.':
                    line = line[1:]
                message += line + CRLF
                line = self.getline()
            now = datetime.datetime.now()
            message = 'Received: from '+self.remotehost+' (['+self.addr+']) by '+HOSTNAME+'; '+now.strftime('%a, %d %b %Y %H:%M:%S +0000') + CRLF + message
            message = 'Return-path: <'+self.returnpath+'>' + CRLF + message
            filename = now.strftime('%Y%m%d%H%M%S-')+self.random_string()
            try:
                for recp in self.recipients:
                    os.chdir(MAIL_PATH)
                    self.chdir_mkdir(recp[0])
                    self.chdir_mkdir(recp[1])
                    mailfile = open(filename+'.eml', 'wb')
                    mailfile.write(message)
                    mailfile.close()
                    print "wrote mail "+filename+" for "+str(recp)
            except:
                                print "ERROR!"
                self.resp_dataerror()
            else:
                self.resp_ok()
            os.chdir(MAIL_PATH)
           
    def cmd_rset(self, args):
        self.returnpath = None
        self.recipients = []
        self.resp_ok()

    def cmd_noop(self, args):
        self.resp_ok()

    def cmd_quit(self, args):
        self.running = False


########################################

print 'vsss - very simple smtp server'
print

# generate hostname, if required
if HOSTNAME == '':
    HOSTNAME = gethostname()
print 'hostname is '+HOSTNAME

# listen on port 25
srvsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srvsock.bind(('', 25))
srvsock.listen(5)

# create thread for each connection
while True:
    (clisock, addrport) = srvsock.accept()
    srvthrd = SMTPServer(clisock, addrport[0], addrport[1])
    srvthrd.start()        

# this is not reached (yet)
srvsock.close()

Name: Anonymous 2007-10-30 16:19

How the fuck does this happen?

os.mkdir(dir) succeeds but the os.chdir(dir) immediately following it fails, even though the directory must exist as mkdir just completed without raising an exception!

ERROR while writing 20071030201458-dumzkcpmaxdchdt for ('yahoo.com.tw', 'yeh2200')
Exception in thread Thread-627:
Traceback (most recent call last):
  File "C:\Program Files\Python\lib\threading.py", line 460, in __bootstrap
    self.run()
  File "N:\vsss.py", line 77, in run
    getattr(self, 'cmd_'+command[0].lower())(command[2])
  File "N:\vsss.py", line 277, in cmd_data
    self.chdir_mkdir(self.escape_filename(recp[1]))
  File "N:\vsss.py", line 236, in chdir_mkdir
    os.chdir(dir)
WindowsError: [Error 2] The system cannot find the file specified: 'yeh2200'


This spam-hammer is bringing out loads of other bugs too, but this is the most bizarre. It happens every other minute or so.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List