giampaolo / pyftpdlib

Extremely fast and scalable Python FTP server library
MIT License
1.68k stars 263 forks source link

File operations on Windows with Python 3.13 give `Permission denied` #650

Closed wRAR closed 1 month ago

wRAR commented 1 month ago

Steps to reproduce:

  1. Take the server example from the tutorial and run it (I replaced '' with 127.0.0.1 for simplification but kept the rest).
  2. Run the builtin ftp.exe, issue open localhost 2121, log in with either of the users defined in the server code. Issue dir, so far it works.
  3. Issue get <any existing file>.

What happens:

Same with STOR or APPE (though it looks like it responds "550 File exists" for STOR, even if it doesn't exist).

giampaolo commented 1 month ago

That means you can't open that specific file for reading. It's a problem of Windows permissions about that file / directory. You should fix it at system level, either by changing permissions for that specific user or changing the user.

wRAR commented 1 month ago

That means you can't open that specific file for reading.

I can.

It's a problem of Windows permissions about that file / directory.

Nope.

Also, I now see how this could be seen as a stupid newbie question, especially as I forgot to specify that the same code works with the same files with Python 3.12 so I'm not surprised that it was quickly closed but please reconsider.

giampaolo commented 1 month ago

OK then please show your code and also the server logs (or traceback, if any).

wRAR commented 1 month ago

As I said the code is at https://pyftpdlib.readthedocs.io/en/latest/tutorial.html#a-base-ftp-server

The server logs:

INFO:pyftpdlib:concurrency model: async
INFO:pyftpdlib:masquerade (NAT) address: None
INFO:pyftpdlib:passive ports: None
DEBUG:pyftpdlib:poller: 'pyftpdlib.ioloop.Select'
DEBUG:pyftpdlib:authorizer: 'pyftpdlib.authorizers.DummyAuthorizer'
DEBUG:pyftpdlib:handler: 'pyftpdlib.handlers.type'
DEBUG:pyftpdlib:max connections: 256
DEBUG:pyftpdlib:max connections per ip: 5
DEBUG:pyftpdlib:timeout: 300
DEBUG:pyftpdlib:banner: 'pyftpdlib based FTP server ready.'
DEBUG:pyftpdlib:max login attempts: 3
INFO:pyftpdlib:>>> starting FTP server on :::2121, pid=2560 <<<
INFO:pyftpdlib:::1:51618-[] FTP session opened (connect)
DEBUG:pyftpdlib:::1:51618-[] -> 220 pyftpdlib based FTP server ready.
DEBUG:pyftpdlib:::1:51618-[] <- OPTS UTF8 ON
DEBUG:pyftpdlib:::1:51618-[] -> 530 Log in with USER and PASS first.
DEBUG:pyftpdlib:::1:51618-[] <- USER user
DEBUG:pyftpdlib:::1:51618-[] -> 331 Username ok, send password.
DEBUG:pyftpdlib:::1:51618-[user] <- PASS ******
DEBUG:pyftpdlib:::1:51618-[user] -> 230 Login successful.
INFO:pyftpdlib:::1:51618-[user] USER 'user' logged in.
DEBUG:pyftpdlib:::1:51618-[user] <- EPRT |2|::1|51619|
DEBUG:pyftpdlib:::1:51618-[user] -> 200 Active data connection established.
DEBUG:pyftpdlib:::1:51618-[user] <- RETR foo
DEBUG:pyftpdlib:::1:51618-[user] -> 550 Permission denied.
DEBUG:pyftpdlib:[debug] call: close() (<DTPHandler(id=1338375264240, addr='::1:51618', user='user')>)
giampaolo commented 1 month ago

I don't have a Windows box at the moment, but your error originates from here: https://github.com/giampaolo/pyftpdlib/blob/53f3f66a969b605491573659c011322e6fab1839/pyftpdlib/handlers.py#L2422-L2427 What fails is the open() call, that's why I confirm that my suspicion is that the file path or its directory doesn't have enough permissions for your user. Try to add a raise statement at line 2425 and you should see the full file path + traceback.

wRAR commented 1 month ago
  File "C:\Users\wRAR\AppData\Local\Programs\Python\Python313\Lib\site-packages\pyftpdlib\handlers.py", line 2427, in ftp_RETR
    fd = self.run_as_current_user(self.fs.open, file, 'rb')
  File "C:\Users\wRAR\AppData\Local\Programs\Python\Python313\Lib\site-packages\pyftpdlib\handlers.py", line 1971, in run_as_current_user
    return function(*args, **kwargs)
  File "C:\Users\wRAR\AppData\Local\Programs\Python\Python313\Lib\site-packages\pyftpdlib\filesystems.py", line 222, in open
    return open(filename, mode)
PermissionError: [Errno 13] Permission denied: 'C:\\Users\\wRAR\\Documents'

Looks like it tries to open a dir for reading.

I guess I can debug it from here later.

wRAR commented 1 month ago

pyftpdlib.filesystems.AbstractedFS("C:\\foo", None).ftpnorm("bar") returns "/bar" on 3.12 but "/" on 3.13, because os.path.isabs("/bar") is True on 3.12 but not on 3.13.

giampaolo commented 1 month ago

os.path.isabs("/bar") is True on 3.12 but not on 3.13.

Damn! This is huge in terms of backward compatibility breakage. It's also interesting that this is a cPython ticket from 17 years ago which was fixed very recently.

As for what it concerns pyftpdlib, I'm gonna enable CI tests for python 3.13 and see if they turn red. I hope this is already covered by the test suite. After that we should think about a fix. This definitively breaks everything on Windows.

giampaolo commented 1 month ago

I'm gonna enable CI tests for python 3.13 and see if they turn red.

They do (this is good):

giampaolo commented 1 month ago

This should now be fixed. Please confirm it worked if you have the chance.

wRAR commented 1 month ago

Thanks! I haven't tried manual tests but the Scrapy tests which failed on Windows+3.13 before don't fail with pyftpdlib master.

giampaolo commented 1 month ago

Since this was a critical issue, I've just released pyftpdlib 2.0.1.