classification
Title: FTP_TLS errors when use certain subcommands
Type: behavior Stage: test needed
Components: SSL, Windows Versions: Python 3.7, Python 3.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: christian.heimes Nosy List: christian.heimes, jonathan-lp, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2017-10-08 17:08 by jonathan-lp, last changed 2017-10-13 17:50 by terry.reedy.

Messages (3)
msg303914 - (view) Author: Jonathan (jonathan-lp) Date: 2017-10-08 17:08
Using Python 3.6.3.

The below issue only happens with FTP_TLS. It works fine via a plain FTP connection.

I am connecting to an FTP to using `ftplib` via FTP_TLS.

	ftps = ftplib.FTP_TLS('example.com', timeout=5)

	# TLS is more secure than SSL
	ftps.ssl_version = ssl.PROTOCOL_TLS

	# login before securing control channel
	ftps.login('username@example.com', 'password')

	# switch to secure data connection
	ftps.prot_p()

	# Explicitly set Passive mode
	ftps.set_pasv(True)

This all works. I can send `ftps.mkd('mydir')` (make directory) and `ftps.cwd('mydir')` (change working dir), and both work fine.

But if I send **any** of these (they're all basically synonyms as far as I can tell):

			ftps.dir()
			ftps.nlst()
			ftps.retrlines('LIST')
			ftps.retrlines('MLSD')

Then I get back an exception (below also includes all ftplib debug info as well; generally matches up with what FileZilla shows too):

	*cmd* 'AUTH TLS'
	*put* 'AUTH TLS\r\n'
	*get* '234 AUTH TLS OK.\n'
	*resp* '234 AUTH TLS OK.'
	*cmd* 'USER username@example.com'
	*put* 'USER username@example.com\r\n'
	*get* '331 User username@example.com OK. Password required\n'
	*resp* '331 User username@example.com OK. Password required'
	*cmd* 'PASS ******************************'
	*put* 'PASS ******************************\r\n'
	*get* '230 OK. Current restricted directory is /\n'
	*resp* '230 OK. Current restricted directory is /'
	*cmd* 'PBSZ 0'
	*put* 'PBSZ 0\r\n'
	*get* '200 PBSZ=0\n'
	*resp* '200 PBSZ=0'
	*cmd* 'PROT P'
	*put* 'PROT P\r\n'
	*get* '200 Data protection level set to "private"\n'
	*resp* '200 Data protection level set to "private"'
	*cmd* 'MKD mydir'
	*put* 'MKD mydir\r\n'
	*get* '257 "mydir" : The directory was successfully created\n'
	*resp* '257 "mydir" : The directory was successfully created'
	*cmd* 'CWD mydir'
	*put* 'CWD mydir\r\n'
	*get* '250 OK. Current directory is /mydir\n'
	*resp* '250 OK. Current directory is /mydir'
	*cmd* 'TYPE A'
	*put* 'TYPE A\r\n'
	*get* '200 TYPE is now ASCII\n'
	*resp* '200 TYPE is now ASCII'
	*cmd* 'PASV'
	*put* 'PASV\r\n'
	*get* '227 Entering Passive Mode (8,8,8,8,8,8)\n'
	*resp* '227 Entering Passive Mode (8,8,8,8,8,8)'
	*cmd* 'MLSD'
	*put* 'MLSD\r\n'
	*get* '150 Accepted data connection\n'
	*resp* '150 Accepted data connection'
	Traceback (most recent call last):
	  File "c:\my_script.py", line 384, in run_ftps
		ftps.retrlines('MLSD')
	  File "c:\libs\Python36\lib\ftplib.py", line 485, in retrlines
		conn.unwrap()
	  File "C:\libs\Python36\lib\ssl.py", line 1051, in unwrap
		s = self._sslobj.unwrap()
	  File "C:\libs\Python36\lib\ssl.py", line 698, in unwrap
		return self._sslobj.shutdown()
	OSError: [Errno 0] Error

The same FTP command (LIST) works fine via filezilla.

The closest thing I can find with googling is this: https://bugs.python.org/msg253161 - and I'm not sure if it's related or relevant.

Short version: What does "OSError: [Errno 0] Error" actually mean, and how do I list my directory contents?
msg303979 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2017-10-09 15:52
"OSError: [Errno 0] Error" typically means that OpenSSL failed due to a Windows error, but we assumed it failed due to a POSIX error and so read the wrong error number (errno instead of GetLastError()).

It's worth testing with Python 3.7.0a1, since we made some changes to OpenSSL integration (as well as updating it to a significantly newer version) that may impact this scenario.
msg304166 - (view) Author: Jonathan (jonathan-lp) Date: 2017-10-11 17:32
Just tested this with Python 3.7.0a1. I'm afraid it makes no difference. Exact same error:

*cmd* 'LIST'
*put* 'LIST\r\n'
*get* '150 Accepted data connection\n'
*resp* '150 Accepted data connection'
Traceback (most recent call last):
  File "c:\backup_script.py", line 385, in run_ftps
    ftps.dir()
  File "c:\Python37\lib\ftplib.py", line 575, in dir
    self.retrlines(cmd, func)
  File "c:\Python37\lib\ftplib.py", line 485, in retrlines
    conn.unwrap()
  File "c:\Python37\lib\ssl.py", line 1059, in unwrap
    s = self._sslobj.unwrap()
  File "c:\Python37\lib\ssl.py", line 706, in unwrap
    return self._sslobj.shutdown()
OSError: [Errno 0] Error
History
Date User Action Args
2017-10-13 17:50:31terry.reedysettitle: FTP_TLS errors when -> FTP_TLS errors when use certain subcommands
stage: test needed
type: behavior
versions: + Python 3.7
2017-10-11 17:32:01jonathan-lpsetmessages: + msg304166
2017-10-09 15:52:41steve.dowersetnosy: + christian.heimes
messages: + msg303979

assignee: christian.heimes
components: + SSL
2017-10-08 17:12:30ned.deilysetnosy: + paul.moore, tim.golden, zach.ware, steve.dower
components: + Windows
2017-10-08 17:08:41jonathan-lpcreate