Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt, implementing an SFTP client



  • I'm working on a All-In-One Mobile Smart Card Terminal ACR890, this comes with a Qt SDK:

        Qt Creator 3.0.1
        Based on Qt 5.2.1 (GCC 4.8.2, 32 bit)
        Built on Apr 9 2014 at 09:14:10
    

    The development platform is:

        Ubuntu 14.04.6 LTS, Trusty Tahr
    

    I'm at the tail end of the project now, the only bit remaining is to implement an SFTP client so that software updates can be downloaded.

    I've create the GUI bits that allow the user to set-up the SFTP connection details, the only bit remaining is to connect to the SFTP server using the entered details.

    I've searched around and found links to:

    https://github.com/lvklabs/QSsh

    Which I downloaded, but the example will not build:

    cannot find -lbotan-2
    collect2: ld returned 1 exit status

    I then did a bit more searching and found a post on here, however since this is such an old project I thought it would be worth asking if there is anymore recent support for SFTP that I should take a look at for Qt?

    I think another possible problem is that the target device is ARM based, not i386. I installed both libssh and libssh2 and both of these only have i386 libraries.

    Also, I'd like to implement a multicolumn file view list to show the contents of the SFTP folder. Suggestions on this also welcome.


  • Qt Champions 2019

    @splatten said in Qt, implementing an SFTP client:

    I think another possible problem is that the target device is ARM based, not i386.

    This is not a problem.

    "I installed both libssh and libssh2 and both of these only have i386 libraries." - on your host machine I guess? You have to install them on your target device.

    "cannot find -lbotan-2" - you need to install that lib in your sysroot.



  • @jsulm, thank you. As the development laptop is i386, how can I install the arm version of libssh so I can build it on the laptop then deploy to the target device?


  • Qt Champions 2019

    @splatten You have an SDK for your device, right? Maybe it provides the possibility to install additional packages?
    If not you can build these libs for your device using the SDK.



  • @jsulm, I build on the laptop then deploy to the target, is the source available for libssh or libssh2 ?


  • Qt Champions 2019

    @splatten said in Qt, implementing an SFTP client:

    is the source available for libssh or libssh2

    yes, OpenSSH is open source



  • @jsulm , thank you, I downloaded open ssh source and will take a look now.



  • Slightly different approach....using QProcess

    I plan to launch sftp and pass it the information for user name, address and port. Is there a way to grab the output from the console so I can look for the text "Password:" ?



  • @splatten
    You are (presumably) using some third-party sftp.exe client? This is what I had to do in another (non-Qt) product. You should not have to parse output for things like host, port, username & password prompting. Look at the documentation for the sftp.exe you intend to use, there should/is likely to be command-line, or possibly take-from-file, for these?



  • @JonB , the sftp I'm using in present in the linux distribution on the device.



  • @splatten
    OK, well I don't know about that! What about man sftp (host, port, user at least on command line)? On, say, Ubuntu I see:

     The final usage format allows for automated sessions using the -b option.
    In such cases, it is necessary to configure non-interactive authentica‐
    tion to obviate the need to enter a password at connection time (see
    sshd(8) and ssh-keygen(1) for details).
    

    Anyway, you use QProcess methods like https://doc.qt.io/qt-5/qprocess.html#readAllStandardOutput or (better) https://doc.qt.io/qt-5/qprocess.html#readyReadStandardOutput signal to read from/write to the subprocess. You'll want to deal with all of stdin, stdout, & stderr, plus error signals, for proper control of your sub-process.



  • Here is my sample code:

    QProcess* pProc = new QProcess(this);
    QString strHost = clsMainWnd::strGetHostName()
           ,strPort = clsMainWnd::strGetPort()
           ,strUsername = clsMainWnd::strGetUsername();
    QStringList slstCmdArgs;
    slstCmdArgs << (strUsername + QString("@") + strHost)
                << (QString("-P") + strPort);
    pProc->start("sftp", slstCmdArgs);
    while( pProc->waitForStarted() != true ) {
    }
    QByteArray bytaryIn = pProc->readAllStandardOutput();
    qDebug() << bytaryIn;
    

    I've grabbed the content of slstCmdArgs and tried it in a terminal and it works, but in code I never see anything in "bytaryIn".

    An example of what the code above does:

        sftp User@HostName -P22
    

    What I am expecting to see is:

        User@HostName's password:
    

    [Edit] I've now re-written this code to:

    QString strHost = clsMainWnd::strGetHostName()
           ,strPort = clsMainWnd::strGetPort()
           ,strUsername = clsMainWnd::strGetUsername();
    QStringList slstCmdArgs;
    slstCmdArgs << (strUsername + QString("@") + strHost)
                << (QString("-P") + strPort);
    mpSFTP = new QProcess(this);
    connect(mpSFTP, SIGNAL(readyReadStandardOutput())
                   ,this, SLOT(readSFTPoutput()));
    mpSFTP->start("sftp", slstCmdArgs);

  • Qt Champions 2019

    @splatten said in Qt, implementing an SFTP client:

    QByteArray bytaryIn = pProc->readAllStandardOutput();

    Don't do it like this - you don't know whether there is already anything to read. Use https://doc.qt.io/qt-5/qprocess.html#readyReadStandardOutput signal instead.



  • @jsulm, having re-written the code, my slot never gets called, meaning the signal can't be emitted.



  • @splatten
    Which is why I said to use https://doc.qt.io/qt-5/qprocess.html#readyReadStandardOutput for better/proper behaviour....

    There is a wrinkle you may have to face. It is possible that your command-line sftp executable will not prompt for password if it detects that the user is not in an interactive terminal (stdin). E.g. its code may quite possibly have

    if (isatty(0))
        prompt_for_password();
    else
       // do not prompt for password
    

    That will be problematic if it is the case. You could try in a terminal sftp < /dev/null or sftp < file: if that does not still prompt for password you have a (potential) problem....



  • @JonB , would this help:

        mpSFTP->setProcessChannelMode(QProcess::MergedChannels);


  • @splatten
    Help what, in what way? If the sftp requires a terminal stdin for password prompt, then no, if, say, you have a purely interactive Qt application. You can try it. But the first thing to test is whether your sftp behaves differently if its stdin is not attached to a terminal?



  • Now the slot gets called and in my slot I have:

        qDebug() << "readAllStandardOutput:";
        qDebug() << mpSFTP->readAllStandardOutput();
        qDebug() << "readChannel:";
        qDebug() << mpSFTP->readChannel();
    

    In the output I see:

        readAllStandardOutput:
        "ssh_askpass: exec(/usr/local/libexec/ssh-askpass): No such file or directory
        "
        readChannel:
        0

  • Qt Champions 2019

    @splatten What happens if you execute exact same command manually in a terminal?
    Also connect a slot to the error signal from QProcess and check whether you get any errors.



  • @jsulm , When I execute "sftp" with the command line arguments, it works without any issues.



  • @splatten
    As I have said before, so last time now:

    ssh_askpass: exec(/usr/local/libexec/ssh-askpass): No such file or directory

    This is because your sftp is not willing/able to access stdin to get a password. Try what I said about seeing how your sftp behaves with input/output redirected when run from a terminal. I will not comment again, and leave it to you.



  • ssh_askpass is not available on this linux distribution.



  • @splatten
    Yes, so you can't use it.



  • @JonB, I've tried everything you have suggested so far and not been able to make any progress due to either incorrect syntax or missing commands.



  • @splatten
    I am suggesting your sftp client will not work to prompt for a password if you do not run it from a terminal. It will not work when you try redirection from a parent process like Qt.

    The man page for my sftp under Ubuntu at least is pretty explicit about requiring either an "interactive" session for authentication, or must use ssh facilities for non-password authentication. Does your system have man sftp for you to read through?


Log in to reply