Skip to content

Commit

Permalink
Added demo/tls_ftpd.py, a new script adding preliminary support for F…
Browse files Browse the repository at this point in the history
…TP over TLS (FTPS).
  • Loading branch information
giampaolo committed Dec 29, 2008
1 parent 81088b8 commit eaf4389
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 0 deletions.
32 changes: 32 additions & 0 deletions demo/keycert.pem
@@ -0,0 +1,32 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
iHkC6gGdBJhogs4=
-----END CERTIFICATE-----
126 changes: 126 additions & 0 deletions demo/tls_ftpd.py
@@ -0,0 +1,126 @@
#!/usr/bin/env python
# tls_ftpd.py

"""RFC-2228 asynchronous FTPS server."""

import ssl
import os
import asyncore

from pyftpdlib.ftpserver import *


CERTFILE = 'keycert.pem'

new_proto_cmds = {
# cmd : (perm, auth, arg, path, help)
'AUTH': (None, False, True, False, 'Syntax: AUTH <SP> TLS|SSL (set up secure control connection).'),
'PBSZ': (None, False, True, False, 'Syntax: PBSZ <SP> 0 (negotiate size of buffer for secure data transfer).'),
'PROT': (None, False, True, False, 'Syntax: PROT <SP> [C|P] (set up un/secure data channel).'),
}

from pyftpdlib.ftpserver import _CommandProperty
for cmd, properties in new_proto_cmds.iteritems():
proto_cmds[cmd] = _CommandProperty(*properties)
del cmd, properties, new_proto_cmds, _CommandProperty


class SSLConnection(object, asyncore.dispatcher):

def do_ssl_handshake(self):
try:
self.socket.do_handshake()
self.ssl_accepting = False
except ssl.SSLError, err:
if err.args[0] in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE):
return
raise

def handle_read_event(self):
if self.ssl_accepting:
self.do_ssl_handshake()
else:
asyncore.dispatcher.handle_read_event(self)

def handle_write_event(self):
if self.ssl_accepting:
self.do_ssl_handshake()
else:
asyncore.dispatcher.handle_write_event(self)

def send(self, data):
try:
return asyncore.dispatcher.send(self, data)
except ssl.SSLError, err:
if err.args[0] == ssl.SSL_ERROR_EOF:
return 0
raise

def recv(self, buffer_size):
try:
return asyncore.dispatcher.recv(self, buffer_size)
except ssl.SSLError, err:
if err.args[0] == ssl.SSL_ERROR_EOF:
self.handle_close()
return ''
raise


class TLS_DTPHandler(SSLConnection, DTPHandler):

do_ssl_handshake = SSLConnection.do_ssl_handshake
handle_read_event = SSLConnection.handle_read_event
handle_write_event = SSLConnection.handle_write_event
send = SSLConnection.send
recv = SSLConnection.recv

def __init__(self, sock_obj, cmd_channel):
DTPHandler.__init__(self, sock_obj, cmd_channel)
self.ssl_accepting = False
if self.cmd_channel.secure_data_channel:
self.socket = ssl.wrap_socket(self.socket, do_handshake_on_connect=0,
certfile=CERTFILE, server_side=True,
suppress_ragged_eofs=False)
self.ssl_accepting = True


class TLS_FTPHandler(SSLConnection, FTPHandler):

dtp_handler = TLS_DTPHandler

do_ssl_handshake = SSLConnection.do_ssl_handshake
handle_read_event = SSLConnection.handle_read_event
handle_write_event = SSLConnection.handle_write_event
send = SSLConnection.send
recv = SSLConnection.recv

def __init__(self, conn, server):
FTPHandler.__init__(self, conn, server)
self.ssl_accepting = False
self.secure_data_channel = False


def ftp_AUTH(self, line):
self.respond('234 AUTH TLS successful')
self.socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False,
certfile=CERTFILE, server_side=True,
do_handshake_on_connect=False)
self.ssl_accepting = True

def ftp_PBSZ(self, line):
self.respond('200 PBSZ=0 successful.')

def ftp_PROT(self, line):
self.respond('200 Protection set to Private')
self.secure_data_channel = True


if __name__ == '__main__':
authorizer = DummyAuthorizer()
authorizer.add_user('user', '12345', os.getcwd(), perm='elradfmw')
authorizer.add_anonymous(os.getcwd())
ftp_handler = TLS_FTPHandler
ftp_handler.authorizer = authorizer
address = ('', 21)
ftpd = FTPServer(address, ftp_handler)
ftpd.serve_forever()

0 comments on commit eaf4389

Please sign in to comment.