Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

twistd FTP TAP server allow configuring user home folder from twistd CLI #12126

Open
vhdumann opened this issue Apr 8, 2024 · 3 comments
Open

Comments

@vhdumann
Copy link

vhdumann commented Apr 8, 2024

Describe the incorrect behavior you saw
I am not able to use twist -n ftp consistently for testing file uploads.
Downloading files works as anonymous. But with auth=memory or file I receive 550 or 530 errors.
Uploading does not work with anonymous, memory or file authentication.
When using auth unix the file upload did work.

Describe how to cause this behavior
I run the server for example with

  • twistd -n ftp --auth anonymous --userAnonymous=test -r file_root
    • file_root is a 777 dir
    • alternatively:
      • twistd -n ftp --auth memory:user:password -r file_root
      • twistd -n ftp --auth file:pass.dat -r file_root
        • content of pass.dat: user:password
      • twistd -n ftp --auth unix -r file_root
        • this worked

I try to upload with e.g.

  • curl -T example.txt ftp://test@localhost:2121/
  • curl -T example.txt ftp://user:password@localhost:2121/ or curl -T example.txt -u user ftp://localhost:2121
    • with memory auth option always: curl: (25) Failed FTP upload: 550 for valid or invalid credentials
    • with file auth option always: curl: (67) Access denied: 530 with valid or invalid credentials

What did you do to get it to happen?
Installed twisted (24.3.0) via pip (python 3.10)

2024-04-08T11:39:32+0000 [FTP (ProtocolWrapper),1,127.0.0.1] DTPFactory.setTimeout set to 10 seconds
2024-04-08T11:39:32+0000 [FTP (ProtocolWrapper),1,127.0.0.1] DTPFactory starting on 37007
2024-04-08T11:39:32+0000 [twisted.protocols.ftp.DTPFactory#info] Starting factory <twisted.protocols.ftp.DTPFactory object at 0x7fa49de19bd0>
2024-04-08T11:39:32+0000 [twisted.protocols.ftp.DTPFactory] DTPFactory.buildProtocol
2024-04-08T11:39:32+0000 [twisted.protocols.ftp.DTPFactory] cancelling DTP timeout
2024-04-08T11:39:32+0000 [FTP (ProtocolWrapper),1,127.0.0.1] cleanupDTP
2024-04-08T11:39:32+0000 [FTP (ProtocolWrapper),1,127.0.0.1] <<class 'twisted.internet.tcp.Port'> of <class 'twisted.protocols.ftp.DTPFactory'> on 37007>
2024-04-08T11:39:32+0000 [FTP (ProtocolWrapper),1,127.0.0.1] dtpFactory.stopFactory
2024-04-08T11:39:32+0000 [-] (TCP Port 37007 Closed)
2024-04-08T11:39:32+0000 [twisted.protocols.ftp.DTPFactory#info] Stopping factory <twisted.protocols.ftp.DTPFactory object at 0x7fa49de19bd0>
2024-04-08T11:39:32+0000 [-] dtpFactory.stopFactory

Describe the correct behavior you'd like to see

  1. Uploading works.
  2. Log output is helpful. (I see no output why the upload failed or 530 / 550 is returned)
  3. All auth options (including anonymous) work or the --help output is clear enough that I understand them if it is my fault

Testing environment
Linux seccdev 5.4.0-173-generic #191-Ubuntu SMP Fri Feb 2 13:55:07 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.6 LTS"

twistd (the Twisted daemon) 24.3.0
Copyright (c) 2001-2024 Twisted Matrix Laboratories.
See LICENSE for details.

attrs==23.2.0
Automat==22.10.0
constantly==23.10.4
hyperlink==21.0.0
idna==3.6
incremental==22.10.0
six==1.16.0
Twisted==24.3.0
typing_extensions==4.11.0
zope.interface==6.2

@vhdumann vhdumann added the bug label Apr 8, 2024
@vhdumann vhdumann changed the title twistd FTP server: uploading files twistd FTP server: can not upload files Apr 8, 2024
@adiroiban adiroiban added the ftp label Apr 8, 2024
@adiroiban
Copy link
Member

adiroiban commented Apr 8, 2024

Thanks for the report.

The default anonymous user is not allowed to upload files

see the source code

def openForWriting(self, path):
"""
Reject write attempts by anonymous users with
L{PermissionDeniedError}.
"""
return defer.fail(PermissionDeniedError("STOR not allowed"))

Is there any documentation for Twisted describing that the anonymous user has write access by default?


Regarding non-anonymous users, the current ftp TAP does not support custom home paths for non-anoymous users.

def makeService(config):
f = ftp.FTPFactory()
r = ftp.FTPRealm(config["root"])
p = portal.Portal(r, config.get("credCheckers", []))

The twistd root is passes as the anonymous root, and the non anonmous user home directory is is harcoded to the default /home/$USERNAME

Is there any documentation for Twisted FTP application suggesting that this is supported?


I would consider this a feature request,

The current options for FTP tap are here

class Options(usage.Options, strcred.AuthOptionMixin):
synopsis = """[options].
WARNING: This FTP server is probably INSECURE do not use it.
"""
optParameters = [
["port", "p", "2121", "set the port number"],
["root", "r", "/usr/local/ftp", "define the root of the ftp-site."],
["userAnonymous", "", "anonymous", "Name of the anonymous user."],
]
compData = usage.Completions(
optActions={"root": usage.CompleteDirs(descr="root of the ftp site")}

You can look into extending the code to support non-anonymous user home folder.

I am happy to review a PR for this.

I have updated the title of this issue to reflect the current issue.

FTP upload works... it just that you will need to store all the FTP user files inside a "/home/$USER/" directory

@adiroiban adiroiban changed the title twistd FTP server: can not upload files twistd FTP TAP server allow configuring user home folder from twistd CLI Apr 8, 2024
@vhdumann
Copy link
Author

vhdumann commented Apr 9, 2024

Thank you for the quick feedback, it explains a lot.

Is there any documentation for Twisted describing that the anonymous user has write access by default?

I may have had wrong expectations what the CLI tool was about. Background: I wanted a minimal FTP server solution to test a client. Without the need to setup real system users etc. And in my opinion the tool implied this by allowing to pass users and passwords as arguments and supporting anonymous access. I would expect that support of anon uploads is the more obvious use case for a test server and not supporting it would be the thing that has to be documented. Differentiating between anonymous and user downloads and uploads respectively probably took explicit implementation work. And I don't really see why. The help segment warns that the tool is insecure, great, I want to do insecure things for testing.

Is there any documentation for Twisted FTP application suggesting that this is supported?

The help output says "define the root of the ftp-site" which to me implies I can choose the default path for file transfers
Also even if I run twistd -n ftp --auth file:pass.dat, write <user>:<password> of my local system user into the pass.dat (I would expect to be able to define arbitrary credentials here) and then use this non-anonymous user to upload or download via curl I still receive 530 access denied without any feedback on the tool side.

@adiroiban
Copy link
Member

I have never used the Twsited Application framework and TAP file.
I don't think this was explicitly designed for testing usage.


FTP anonymous is kind of a legacy implementation of a public download site.
I think it is expected to have read-only for anonymous FTP

If you want to write, you can create an user.

For testing , you can have something like this

-r = ftp.FTPRealm(config["root"])
+r = ftp.FTPRealm(anonymousRoot=config["root"], userHome="/tmp")

Then you will need to create /tmp/USERNAMES folder

The help output says "define the root of the ftp-site" which to me implies I can choose the default path for file transfers

Thanks. True.
It should say. "Defines the root of the anonymos site."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants