embeddedmz / ftpclient-cpp

C++ client for making FTP requests
MIT License
204 stars 65 forks source link

How to use a SFTP mode on FTPClient #12

Closed ayhamal closed 3 years ago

ayhamal commented 4 years ago

Hi, I interested to use this build on my project, but I have problems to connect using sftp to my server.

I tried:

FTPClient.InitSession("xxx.xx.xx.xx:xx, 22, "username", "password");

But on console I have an error 1 indicating protocol not supported.

It works good using FTP protocol, but you know it's not recommend to use.

Please help, Thanks

embeddedmz commented 4 years ago

Hi @ayhamal Try this : FTPClient.InitSession("xxx.xx.xx.xx:xx, 22, "username", "password", CFTPClient::FTP_PROTOCOL::SFTP);

The 5th parameter is used to set the protocol type (FTP, SFTP (SSH) or FTPS/ES (TLS). The 6th can be used to enable/disable log messsages.

Hope that helps !

ayhamal commented 4 years ago

Hi @embeddedmz I try that but not working.

I'm using this commands:

FTPClient.InitSession("xxx.xx.xx.xx:xx", 22, "username", "password", CFTPClient::FTP_PROTOCOL::SFTP);

Next I use:

FTPClient.List("/", srtList);

And on console have the results:

Operation 'InitSession' status: 1

[FTPClient][Error] Unable to connect to remote folder / (Error = 1 | Unsupported protocol).

Please help, Thanks

embeddedmz commented 4 years ago

Can you remove the :xx from the hostname and retry ?

ayhamal commented 4 years ago

Of course, I did it and I have the same result.

embeddedmz commented 4 years ago

@ayhamal Can you compile with this preprocessor macro: DEBUG_CURL, and use this method : static void SetCurlTraceLogDirectory(const std::string &strPath); to specify a directory where debug logs will be stored. They will give you an information on why things are not working properly. Can you post the content please.

Also, don't forget to set a preprocessor macro WINDOWS if you are compiling on Windows and without CMake and Visual Studio.

On what operating system are you working ? how libcurl is installed on your machine ? Did you try to connect to your server with FileZilla for example ?

embeddedmz commented 4 years ago

In the readme, there's a procedure to install libcurl on Windows. On Windows, you can also use "vcpkg" to install libcurl and it will be directly accessible in Visual Studio without an effort.

On Linux, ensure that curl and its library are installed with SSH support (google is your friend).

nicraMarcin commented 3 years ago

I have similar issue with sftp.

FTPClient.InitSession("127.0.0.1", 22, "user", "pass", embeddedmz::CFTPClient::FTP_PROTOCOL::SFTP);

std::string stringList;
FTPClient.List("/", stringList);
std::cout << stringList <<std::endl;
FTPClient.CleanupSession();

and error:

[FTPClient][Error] Unable to connect to remote folder / (Error = 2 | Failed initialization).
embeddedmz commented 3 years ago

@nicraMarcin I can see you're connecting to a local server (maybe it's not a real SFTP server), personnally, IIRC, I never succeeded in creating an SFTP server (unlike FTPS/ES). But if you try with a real SFTP server, there's no reason the class won't work (already achieved that in the past but maybe something changed). Above, there's instructions to enable additional debug messages to understand what's going on.

nicraMarcin commented 3 years ago

Yes, I try with real server and noticed, that given port isn't put into connection, if I change it I see that still want to connect with port 22

FTPClient.InitSession("my.sftp.com", 6022, "user", "pass", embeddedmz::CFTPClient::FTP_PROTOCOL::SFTP);

I have to change hostname with port my.sftp.com:6022 and now it try to connect with proper port, but I get login denied

[FTPClient][Error] Unable to connect to remote folder / (Error = 67 | Login denied).

With the same credentials I connect with FileZilla and works so this is no login/pass issue

nicraMarcin commented 3 years ago

@embeddedmz Hi, do you have any suggestions with sftp?

embeddedmz commented 3 years ago

@nicraMarcin try this example from curl website : https://curl.se/libcurl/c/sftpget.html and tell me if it's working with your server.

nicraMarcin commented 3 years ago

It doesn't work

{
    CURL *curl;
    CURLcode res;
    struct FtpFile ftpfile = {
            "/tmp/script.sh", /* name to store the file as if successful */
            NULL
    };

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if(curl) {
        /*
         * You better replace the URL with one that works!
         */
        curl_easy_setopt(curl, CURLOPT_URL,
                         "sftp://user:password@host.com/tmp/script.sh");
        curl_easy_setopt(curl, CURLOPT_PORT, 60022);
        /* Define our callback to get called when there's data to be written */
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
        /* Set a pointer to our struct to pass to the callback */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);

And console writes:

*   Trying 2001::254a:60022...
* TCP_NODELAY set
* Connected to host.com (2001::254a) port 60022 (#0)
* User: user
* Authentication using SSH public key file
* Closing connection 0
curl told us 67

from console it works

$ curl -v --insecure sftp://user:passowrd@host.com:60022
*   Trying 2001::254a:60022...
* TCP_NODELAY set
* Connected to vps.nicram.net (200::254a) port 60022 (#0)
* User: user
* Authentication using SSH public key file
* Completed password authentication
* Authentication complete
[...] // here prints files list
nicraMarcin commented 3 years ago
curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1L);
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://user:password@host.com/deploy.sh");
    curl_easy_setopt(curl, CURLOPT_PORT, 60022);
    curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);

and console

*   Trying 2001::254a:60022...
* TCP_NODELAY set
* Connected to host.com (2001::254a) port 60022 (#0)
* User: user
* Authentication using SSH public key file
* Completed password authentication
* Authentication complete
* Connection #0 to host host.com left intact
embeddedmz commented 3 years ago

Hi @ayhamal and @nicraMarcin, I fixed the issue I will commit the fix and give you some insights (the SSH agent must be disabled in libcurl and the SSL verifications must be disabled) before the end of the day. Sorry, if this took so long, I didn't have time to debug/investigate.

embeddedmz commented 3 years ago

The whole story :

I launched a download unit test with a local SFTP server using RebexTinySftpServer (https://www.rebex.net/tiny-sftp-server/ - I didn't find a public SFTP server) and libcurl told me that the protocol is not supported (SSH probably).

So as I'm using VCPKG actually and CMake to generate the Visual Studio solution (Look at README), I installed another libcurl package to fix that issue :

.\vcpkg instal curl[ssh]:x64-windows

So, first of all, ensure that your libcurl version is compiled with SSH support.

Then, if your not using a CA file, turn on insecure mode to disable peer/host verification (In the readme, you will find an example).

If you want to launch SFTP unit tests, here's a configuration file (You can use CMake/VCPKG for that purpose, look at the README file) :

[tests] ftp=no sftp=yes http-proxy=no

...

[sftp] host=127.0.0.1 port=22 username=tester password=password remote_file=file.png ; put a file name file.png in the root of the SFTP server (use filezilla or the file explorer) remote_file_sha1sum=sha1_sum_of_file_png ; you can use this command under windows : certutil -hashfile file.png SHA256 remote_upload_folder=/upload/ ; create this empty folder on the root of the SFTP server remote_download_folder= ; download with a wildcarded URL doesn't work with SFTP

Best regards.

erenkeskin commented 7 months ago

Hello,

I couldn't use SFTP on my application. Examples are not clear. I'm trying everything you did but never. I got only this error

OS Version: Ubuntu 23.04 GCC: version 8.3.1 libcurl-7.79

[FTPClient][Error] Unable to upload file test_upload.txt (Error = 1 | Unsupported protocol).

I tried to all combinations of SettingsFlag or inSecure things, but now working. This is my code.

` C++ try { // For SFTP std::unique_ptr SFTP; SFTP.reset(new embeddedmz::CFTPClient(PRINT_LOG)); SFTP->InitSession("192.168.xx.xx", 22, "aaa", "ccc", embeddedmz::CFTPClient::FTP_PROTOCOL::SFTP, embeddedmz::CFTPClient::SettingsFlag::ENABLE_SSH_AGENT); SFTP->SetInsecure(true);

SFTP->SetProgressFnCallback(SFTP.get(), &TestUPProgressCallback);

std::ostringstream ssTimestamp;
TimeStampTest(ssTimestamp);

std::ofstream ofTestUpload("test_upload.txt");

ofTestUpload << "Unit Test TestUploadFile executed on " + ssTimestamp.str() + "\n" +
                "This file is uploaded via FTPClient-C++ API.\n" +
                "If this file exists, that means that the unit test is passed.\n";
ofTestUpload.close();
SFTP->UploadFile("test_upload.txt", "/test_upload.txt", true);
std::cout << std::endl;

std::cout << std::endl;

SFTP->CleanupSession();
SFTP.reset();

} catch (const std::runtime_error& e) { std::cerr << e.what() << '\n'; } `

erenkeskin commented 7 months ago

My libcurl info option is default

with_libssh2=False

Is it cause?

embeddedmz commented 7 months ago

My libcurl info option is default

with_libssh2=False

Is it cause?

Yes, you need a libcurl version with SSH builtin, you can install it with apt or if you have built curl on your own, you will have to configure the build script.

erenkeskin commented 7 months ago

Thank you. It's work.