Authorizer und Passive Datenverbindung implementiert

This commit is contained in:
trollhase 2013-08-22 04:51:51 +02:00
parent 54e1e9b5c8
commit c1a08ba821

View file

@ -1,6 +1,56 @@
import SocketServer import SocketServer
import threading
import socket
from random import randint
class DataConnection:
def run(self, dchandler):
pass
class PassiveDataConnection(DataConnection):
def __init__(self, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind(("",port))
threading.Thread(target=self.waitForConnection).start()
def waitForConnection(self):
self.socket.listen(1)
self.connection, _ = self.socket.accept()
def run(self, dchandler):
threading.Thread(target=self.runHandler, args=(dchandler,) ).start()
def runHandler(self, dchandler):
dchandler.handle(self.connection)
self.connection.close()
class ActiveDataConnection(DataConnection):
def __init__(self, host, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect( (host,port) )
def run(self, dchandler):
threading.Thread(target=self.runHandler, args=(dchandler,)).start()
def runHandler(self, dchandler):
dchandler.handle(self.socket)
self.socket.close()
class FailAuthorizer:
'''Default authorizer. Denys all logins'''
def authorize(self, username, password, handler):
return False
class AnonymousAuthorizer:
def authorize(self, username, password, handler):
if username in ["ftp","anonymous"]:
return True
else:
return False
class FTPMessage: class FTPMessage:
'''Parses and creates FTP Messages'''
def __init__(self,cmd,parameter): def __init__(self,cmd,parameter):
self.cmd = cmd self.cmd = cmd
self.parameter = parameter self.parameter = parameter
@ -22,50 +72,102 @@ class FTPMessage:
param = line[pos+1:] param = line[pos+1:]
return FTPMessage(cmd.upper(),param) return FTPMessage(cmd.upper(),param)
class GeneralState: class QuitMessage(FTPMessage):
@staticmethod '''Message sent to client when client wants to disconnect'''
def handle(self, message): def __init__(self):
FTPMessage.__init__(self,"221","Goodbye.")
class InvalidCommandMessage(FTPMessage):
'''Message sent to client when server received message it didn't understand'''
def __init__(self,cmd):
FTPMessage.__init__(self,"500","%s not understood" % cmd)
class PasswordRequiredMessage(FTPMessage):
'''Message sent to client when it specified a username'''
def __init__(self,user):
FTPMessage.__init__(self,"331","Password required for %s" % user)
class AuthorizationSuccessfulMessage(FTPMessage):
'''Message sent to client when authorization was successful'''
def __init__(self):
FTPMessage.__init__(self,"230","Welcome user.")
class AuthorizationFailedMessage(FTPMessage):
'''Message sent to client when authorization failed'''
def __init__(self):
FTPMessage.__init__(self,"530","Login incorrect.")
class WelcomeMessage(FTPMessage):
'''Message sent to client after client has connected'''
def __init__(self):
FTPMessage.__init__(self,"220","FTP Server ready")
class EnteringPassiveModeMessage(FTPMessage):
def __init__(self,addrtuple):
FTPMessage.__init__(self,"227","Entering Passive Mode %s." % addrtuple)
# Data Connection Handler
class HeloHandler:
def handle(self, socket):
socket.send("Hello World")
# State classes
class State:
def process(self, handler, message):
pass
class MainState(State):
def process(self, handler, message):
if message.cmd == "QUIT": if message.cmd == "QUIT":
self.debug("Client wants to quit") handler.send( QuitMessage() )
self.send(FTPMessage("221","Goodbye.")) handler.running = False
self.handler.running = False
else: else:
self.debug("Unknown command %s" % message.cmd) handler.send( InvalidCommandMessage(message.cmd) )
self.send(FTPMessage("500", "%s not understood" % message.cmd ))
class UserState: class NonAuthorizedState(MainState):
@staticmethod def process(self, handler, message):
def handle(self, message):
if message.cmd == "USER": if message.cmd == "USER":
self.debug("Initiating login for user %s" % message.parameter) handler.user = message.parameter
self.send(FTPMessage("331","Password required for %s" % message.parameter)) handler.state = AuthorizingState()
self.state = PassState handler.send( PasswordRequiredMessage(handler.user) )
else: else:
GeneralState.handle(self, message) MainState.process(self, handler, message)
class PassState: class AuthorizingState(MainState):
@staticmethod def process(self, handler, message):
def handle(self, message):
if message.cmd == "PASS": if message.cmd == "PASS":
self.debug("Denying access with password %s" % message.parameter) password = message.parameter
self.send(FTPMessage("530","Login incorrect.")) if handler.authorizer.authorize(handler.user, password, handler):
self.state = UserState handler.debug("User login %s successful" % handler.user)
handler.state = AuthorizedState()
handler.send( AuthorizationSuccessfulMessage() )
else:
handler.debug("User login %s failed" % handler.user)
handler.state = NonAuthorizedState()
handler.send( AuthorizationFailedMessage() )
else: else:
GeneralState.handle(self, message) MainState.process(self, handler, message)
class FTPMessageHandler: class AuthorizedState(MainState):
def __init__(self, handler): def addrtuple(self, ip, port):
self.state = UserState b = ip.split(".")
self.handler = handler b.append( str( (port >> 8) & 0xFF ) )
b.append( str( port & 0xFF ) )
return "(" + ",".join(b)+ ")"
def send(self,data): def process(self, handler, message):
return self.handler.request.send( str(data) ) if message.cmd == "PASV":
port = handler.createPassiveDataConnection()
def debug(self,text): handler.debug("Created passive data connection")
self.handler.debug(text) handler.send( EnteringPassiveModeMessage( self.addrtuple("127.0.0.1",port) ) )
elif message.cmd == "HELO":
def handle(self, message): handler.debug("Running Helo on data connection")
self.state.handle(self, message) if handler.runDataConnection(HeloHandler()):
handler.debug("successful")
else:
handler.debug("failed")
else:
MainState.process(self, handler, message)
class LineReader: class LineReader:
def __init__(self): def __init__(self):
@ -88,12 +190,33 @@ class FTPHandler(SocketServer.BaseRequestHandler):
def debug(self, text): def debug(self, text):
print ("[%s] " % self.client_address[0]) + text print ("[%s] " % self.client_address[0]) + text
def send(self, message):
self.request.send( str(message) )
def createPassiveDataConnection(self):
port = randint(60000,63000)
self.connection = PassiveDataConnection(port)
return port
def createActiveDataConnection(self,port):
self.connection = ActiveDataConnection(self.client_address[0],port)
def runDataConnection(self, dchandler):
if self.connection is None:
return False
else:
self.connection.run(dchandler)
self.connection = None
return True
def handle(self): def handle(self):
self.messagehandler = FTPMessageHandler(self) self.connection = None
self.state = NonAuthorizedState()
self.debug("Client connected"); self.debug("Client connected");
self.request.send(FTPMessage("220","FTP Server ready").generate()) self.send( WelcomeMessage() )
linereader = LineReader() linereader = LineReader()
@ -108,10 +231,13 @@ class FTPHandler(SocketServer.BaseRequestHandler):
for line in linereader.get_lines(): for line in linereader.get_lines():
message = FTPMessage.parse(line) message = FTPMessage.parse(line)
self.messagehandler.handle(message) self.state.process(self,message)
self.debug("Client disconnected") self.debug("Client disconnected")
server = SocketServer.ThreadingTCPServer(("",1234),FTPHandler) handler = FTPHandler
handler.authorizer = AnonymousAuthorizer()
server = SocketServer.ThreadingTCPServer(("",1234),handler)
server.serve_forever() server.serve_forever()