Index: Lib/ftplib.py =================================================================== --- Lib/ftplib.py (revisione 60910) +++ Lib/ftplib.py (copia locale) @@ -33,6 +33,7 @@ # Modified by Jack to work on the mac. # Modified by Siebren to support docstrings and PASV. # Modified by Phil Schwartz to add storbinary and storlines callbacks. +# Modified by Giampaolo Rodola' to add TLS/SSL support. # import os @@ -576,6 +577,92 @@ self.file = self.sock = None +try: + import ssl +except ImportError: + pass +else: + class FTP_TLS(FTP): + """A FTP subclass which adds TLS support to FTP as described + in RFC-4217. + + Connect as usual to port 21 leaving control and data channels + implicitly unprotected. + Securing control and data channels requires user to explicitly + ask for it by using auth_tls() and prot_p() methods. + + Usage example: + >>> from ftplib import FTP_TLS + >>> ftps = FTP_TLS('ftp.python.org') + >>> ftps.auth_tls() # switch to secure control connection + '234 Using authentication type TLS' + >>> ftps.login() # login anonimously + '230 Guest login ok, access restrictions apply.' + >>> ftps.prot_p() # switch to secure data connection + '200 Protection level set to P' + >>> ftps.retrlines('LIST') # list directory content securely + total 9 + drwxr-xr-x 8 root wheel 1024 Jan 3 1994 . + drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .. + drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin + drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc + d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming + drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib + drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub + drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr + -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg + '226 Transfer complete.' + >>> ftps.quit() + '221 Goodbye.' + >>> + """ + + def __init__(self, host='', user='', passwd='', acct='', keyfile=None, + certfile=None, timeout=None): + FTP.__init__(self, host=host, user=user, passwd=passwd, acct=acct, + timeout=timeout) + self.keyfile = keyfile + self.certfile = certfile + self.prot_private = False + + def auth_tls(self): + """Set up secure control connection by using TLS.""" + resp = self.voidcmd('AUTH SSL') + self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile) + self.file = self.sock.makefile(mode='rb') + return resp + + def prot_p(self): + """Set up secure data connection.""" + # PROT defines whether or not the data channel is to be protected. + # Though RFC-2228 defines four possible protection levels, + # RFC-4217 only recommends two, Clear and Private. + # Clear (PROT C) means that no security is to be used on the + # data-channel, Private (PROT P) means that the data-channel + # should be protected by TLS. + # PBSZ command MUST still be issued, but must have a parameter of + # '0' to indicate that no buffering is taking place and the data + # connection should not be encapsulated. + self.voidcmd('PBSZ 0') + resp = self.voidcmd('PROT P') + self.prot_private = True + return resp + + def prot_c(self): + """Set up clear text data channel.""" + resp = self.voidcmd('PROT C') + self.prot_private = False + return resp + + def ntransfercmd(self, cmd, rest=None): + conn, size = FTP.ntransfercmd(self, cmd, rest) + if self.prot_private: + conn = ssl.wrap_socket(conn, self.keyfile, self.certfile) + return conn, size + + __all__.append("FTP_TLS") + + _150_re = None def parse150(resp):