Howto implement SFTP with Qt/QNetworkAccessManager (C++)

前端 未结 4 1525
南方客
南方客 2021-02-05 22:43

I\'m new to Qt and I would like to implement FTP and SFTP support for my software. As I googled I discovered that there doesn\'t exist a sftp library for Qt but it should be pos

4条回答
  •  离开以前
    2021-02-05 23:20

    I do this using libssh. Very straight forward. https://api.libssh.org/stable/libssh_tutor_sftp.html

    Don't forget to add your sftp server into known hosts in your system.

    ssh-keyscan -H mysftpserver.com >> ~/.ssh/known_hosts
    

    Example code:

    #include "sftpuploader.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int verify_knownhost(ssh_session session)
    {
        int state, hlen;
        unsigned char *hash = NULL;
        char *hexa;
        char buf[10];
    
        state = ssh_is_server_known(session);
    
        hlen = ssh_get_pubkey_hash(session, &hash);
        if (hlen < 0)
            return -1;
    
        switch (state)
        {
        case SSH_SERVER_KNOWN_OK:
            break; /* ok */
    
        case SSH_SERVER_KNOWN_CHANGED:
            fprintf(stderr, "Host key for server changed: it is now:\n");
            ssh_print_hexa("Public key hash", hash, hlen);
            fprintf(stderr, "For security reasons, connection will be stopped\n");
            free(hash);
            return -1;
    
        case SSH_SERVER_FOUND_OTHER:
            fprintf(stderr, "The host key for this server was not found but an other"
                            "type of key exists.\n");
            fprintf(stderr, "An attacker might change the default server key to"
                            "confuse your client into thinking the key does not exist\n");
            free(hash);
            return -1;
    
        case SSH_SERVER_FILE_NOT_FOUND:
            fprintf(stderr, "Could not find known host file.\n");
            fprintf(stderr, "If you accept the host key here, the file will be"
                            "automatically created.\n");
            /* fallback to SSH_SERVER_NOT_KNOWN behavior */
    
        case SSH_SERVER_NOT_KNOWN:
            hexa = ssh_get_hexa(hash, hlen);
            fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
            fprintf(stderr, "Public key hash: %s\n", hexa);
            free(hexa);
            if (fgets(buf, sizeof(buf), stdin) == NULL)
            {
                free(hash);
                return -1;
            }
            if (strncasecmp(buf, "yes", 3) != 0)
            {
                free(hash);
                return -1;
            }
            if (ssh_write_knownhost(session) < 0)
            {
                fprintf(stderr, "Error %s\n", strerror(errno));
                free(hash);
                return -1;
            }
            break;
    
        case SSH_SERVER_ERROR:
            fprintf(stderr, "Error %s", ssh_get_error(session));
            free(hash);
            return -1;
        }
    
        free(hash);
        return 0;
    }
    
    bool upload(const QString &localFile,
                              const QString &dest,
                              const QString &host,
                              const QString &username,
                              const QString &passwd)
    {
        bool retVal = false;
    
        QFileInfo info(localFile);
    
        m_localFilename = info.canonicalFilePath();
        m_remoteFilename = dest + "/" + info.fileName();
    
        int verbosity = SSH_LOG_PROTOCOL;
        int port = 22;
        int rc;
        sftp_session sftp;
        sftp_file file;
        int access_type;
        int nwritten;
        QByteArray dataToWrite;
        ssh_session my_ssh_session;
    
        QFile myfile(m_localFilename);
    
        if(!myfile.exists())
        {
            qDebug() << "SFTPUploader: File doesn't exist " << m_localFilename;
            return retVal;
        }
    
        my_ssh_session = ssh_new();
        if(my_ssh_session == NULL)
        {
            return retVal;
        }
    
        ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host.toUtf8());
        ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
        ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
    
        rc = ssh_connect(my_ssh_session);
        if (rc != SSH_OK)
        {
            qDebug() << "SFTPUploader: Error connecting to localhost: " << ssh_get_error(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
        else
        {
            qDebug() << "SFTPUploader: SSH connected";
        }
    
        // Verify the server's identity
        // For the source code of verify_knowhost(), check previous example
        if (verify_knownhost(my_ssh_session) < 0)
        {
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            qDebug() << "SFTPUploader: verify_knownhost failed";
            return retVal;
        }
    
        rc = ssh_userauth_password(my_ssh_session, username.toUtf8(), passwd.toUtf8());
        if (rc != SSH_AUTH_SUCCESS)
        {
            qDebug() << "SFTPUploader: Error authenticating with password: " << ssh_get_error(my_ssh_session);
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
        else
        {
            qDebug() << "SFTPUploader: Authentication sucess";
        }
    
        sftp = sftp_new(my_ssh_session);
        if (sftp == NULL)
        {
            qDebug() << "SFTPUploader: Error allocating SFTP session:" << ssh_get_error(my_ssh_session);
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
    
        rc = sftp_init(sftp);
        if (rc != SSH_OK)
        {
            qDebug() << "SFTPUploader: Error initializing SFTP session:", sftp_get_error(sftp);
            sftp_free(sftp);
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
    
        access_type = O_WRONLY | O_CREAT | O_TRUNC;
        file = sftp_open(sftp, dest.toUtf8(), access_type, S_IRWXU);
        if (file == NULL)
        {
            qDebug() << "SFTPUploader: Can't open file for writing:", ssh_get_error(my_ssh_session);
            sftp_free(sftp);
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
    
        if(myfile.open(QFile::ReadOnly))
        {
            dataToWrite = myfile.readAll();
        }
    
        nwritten = sftp_write(file, dataToWrite, dataToWrite.size());
        if (nwritten != dataToWrite.size())
        {
            qDebug() << "SFTPUploader: Can't write data to file: ", ssh_get_error(my_ssh_session);
            sftp_close(file);
            sftp_free(sftp);
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
    
        rc = sftp_close(file);
        if (rc != SSH_OK)
        {
            qDebug() << "SFTPUploader: Can't close the written file:" << ssh_get_error(my_ssh_session);
            sftp_free(sftp);
            ssh_disconnect(my_ssh_session);
            ssh_free(my_ssh_session);
            return retVal;
        }
        else
        {
            qDebug() << "SFTPUploader: Success";
            retVal = true;
        }
        return retVal;
    }
    
    

提交回复
热议问题