diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index 8b201fbf..0cd331f7 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -76,7 +76,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) { if (errorCode) - *errorCode = ErrorCode::SshSftpFailureError; + *errorCode = ErrorCode::SshScpFailureError; } return connData; diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index 8bfd5e75..f28ac539 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -159,7 +159,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon .arg(connData.clientPubKey, connData.pskKey, connData.clientIP); e = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath, - libssh::SftpOverwriteMode::SftpAppendToExisting); + libssh::ScpOverwriteMode::ScpAppendToExisting); if (e) { if (errorCode) diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp index 9a170a85..99ee5b11 100644 --- a/client/core/controllers/serverController.cpp +++ b/client/core/controllers/serverController.cpp @@ -118,7 +118,7 @@ ServerController::runContainerScript(const ServerCredentials &credentials, Docke ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path, - libssh::SftpOverwriteMode overwriteMode) + libssh::ScpOverwriteMode overwriteMode) { ErrorCode e = ErrorCode::NoError; QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16)); @@ -139,7 +139,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, if (e) return e; - if (overwriteMode == libssh::SftpOverwriteMode::SftpOverwriteExisting) { + if (overwriteMode == libssh::ScpOverwriteMode::ScpOverwriteExisting) { e = runScript(credentials, replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path), genVarsForScript(credentials, container)), @@ -147,7 +147,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, if (e) return e; - } else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) { + } else if (overwriteMode == libssh::ScpOverwriteMode::ScpAppendToExisting) { e = runScript(credentials, replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName), genVarsForScript(credentials, container)), @@ -199,7 +199,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container, } ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, - const QString &remotePath, libssh::SftpOverwriteMode overwriteMode) + const QString &remotePath, libssh::ScpOverwriteMode overwriteMode) { auto error = m_sshClient.connectToHost(credentials); if (error != ErrorCode::NoError) { @@ -211,7 +211,7 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential localFile.write(data); localFile.close(); - error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc"); + error = m_sshClient.scpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc"); if (error != ErrorCode::NoError) { return error; diff --git a/client/core/controllers/serverController.h b/client/core/controllers/serverController.h index 16569dbb..7caad366 100644 --- a/client/core/controllers/serverController.h +++ b/client/core/controllers/serverController.h @@ -38,7 +38,7 @@ public: ErrorCode uploadTextFileToContainer( DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path, - libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting); + libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting); QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr); @@ -80,7 +80,7 @@ private: ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container); ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, - libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting); + libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting); ErrorCode setupServerFirewall(const ServerCredentials &credentials); diff --git a/client/core/defs.h b/client/core/defs.h index 6d1f1a34..e6f3cece 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -46,25 +46,12 @@ namespace amnezia SshPrivateKeyFormatError = 304, SshTimeoutError = 305, - // Ssh sftp errors - SshSftpEofError = 400, - SshSftpNoSuchFileError = 401, - SshSftpPermissionDeniedError = 402, - SshSftpFailureError = 403, - SshSftpBadMessageError = 404, - SshSftpNoConnectionError = 405, - SshSftpConnectionLostError = 406, - SshSftpOpUnsupportedError = 407, - SshSftpInvalidHandleError = 408, - SshSftpNoSuchPathError = 409, - SshSftpFileAlreadyExistsError = 410, - SshSftpWriteProtectError = 411, - SshSftpNoMediaError = 412, + // Ssh scp errors + SshScpFailureError = 400, // Local errors OpenVpnConfigMissing = 500, OpenVpnManagementServerError = 501, - ConfigMissing = 502, // Distro errors OpenVpnExecutableMissing = 600, @@ -92,7 +79,15 @@ namespace amnezia // Api errors ApiConfigDownloadError = 1100, - ApiConfigAlreadyAdded = 1101 + ApiConfigAlreadyAdded = 1101, + + // QFile errors + OpenError = 1200, + ReadError = 1201, + PermissionsError = 1202, + UnspecifiedError = 1203, + FatalError = 1204, + AbortError = 1205 }; } // namespace amnezia diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index 48cba3c5..17ac5ab7 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -28,20 +28,8 @@ QString errorString(ErrorCode code) { case(SshPrivateKeyFormatError): errorMessage = QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types"); break; case(SshTimeoutError): errorMessage = QObject::tr("Timeout connecting to server"); break; - // Libssh sftp errors - case(SshSftpEofError): errorMessage = QObject::tr("Sftp error: End-of-file encountered"); break; - case(SshSftpNoSuchFileError): errorMessage = QObject::tr("Sftp error: File does not exist"); break; - case(SshSftpPermissionDeniedError): errorMessage = QObject::tr("Sftp error: Permission denied"); break; - case(SshSftpFailureError): errorMessage = QObject::tr("Sftp error: Generic failure"); break; - case(SshSftpBadMessageError): errorMessage = QObject::tr("Sftp error: Garbage received from server"); break; - case(SshSftpNoConnectionError): errorMessage = QObject::tr("Sftp error: No connection has been set up"); break; - case(SshSftpConnectionLostError): errorMessage = QObject::tr("Sftp error: There was a connection, but we lost it"); break; - case(SshSftpOpUnsupportedError): errorMessage = QObject::tr("Sftp error: Operation not supported by libssh yet"); break; - case(SshSftpInvalidHandleError): errorMessage = QObject::tr("Sftp error: Invalid file handle"); break; - case(SshSftpNoSuchPathError): errorMessage = QObject::tr("Sftp error: No such file or directory path exists"); break; - case(SshSftpFileAlreadyExistsError): errorMessage = QObject::tr("Sftp error: An attempt to create an already existing file or directory has been made"); break; - case(SshSftpWriteProtectError): errorMessage = QObject::tr("Sftp error: Write-protected filesystem"); break; - case(SshSftpNoMediaError): errorMessage = QObject::tr("Sftp error: No media was in remote drive"); break; + // Ssh scp errors + case(SshScpFailureError): errorMessage = QObject::tr("Scp error: Generic failure"); break; // Local errors case (OpenVpnConfigMissing): errorMessage = QObject::tr("OpenVPN config missing"); break; @@ -68,6 +56,14 @@ QString errorString(ErrorCode code) { case (ApiConfigDownloadError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break; case (ApiConfigAlreadyAdded): errorMessage = QObject::tr("This config has already been added to the application"); break; + // QFile errors + case(OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break; + case(ReadError): errorMessage = QObject::tr("QFile error: An error occurred when reading from the file"); break; + case(PermissionsError): errorMessage = QObject::tr("QFile error: The file could not be accessed"); break; + case(UnspecifiedError): errorMessage = QObject::tr("QFile error: An unspecified error occurred"); break; + case(FatalError): errorMessage = QObject::tr("QFile error: A fatal error occurred"); break; + case(AbortError): errorMessage = QObject::tr("QFile error: The operation was aborted"); break; + case(InternalError): default: errorMessage = QObject::tr("Internal error"); break; diff --git a/client/core/sshclient.cpp b/client/core/sshclient.cpp index 03670b30..01ef7627 100644 --- a/client/core/sshclient.cpp +++ b/client/core/sshclient.cpp @@ -10,16 +10,10 @@ const uint32_t S_IRWXU = 0644; #endif namespace libssh { - const QString libsshTimeoutError = "Timeout connecting to"; + constexpr auto libsshTimeoutError{"Timeout connecting to"}; std::function Client::m_passphraseCallback; - Client::Client(QObject *parent) : QObject(parent) - { } - - Client::~Client() - { } - int Client::callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata) { auto passphrase = m_passphraseCallback(); @@ -171,13 +165,13 @@ namespace libssh { return ErrorCode::NoError; }; - auto error = readOutput(false); - if (error != ErrorCode::NoError) { - return error; + auto errorCode = readOutput(false); + if (errorCode != ErrorCode::NoError) { + return errorCode; } - error = readOutput(true); - if (error != ErrorCode::NoError) { - return error; + errorCode = readOutput(true); + if (errorCode != ErrorCode::NoError) { + return errorCode; } } else { return closeChannel(); @@ -222,100 +216,79 @@ namespace libssh { return fromLibsshErrorCode(); } - ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const QString& localPath, const QString& remotePath, const QString &fileDesc) + ErrorCode Client::scpFileCopy(const ScpOverwriteMode overwriteMode, const QString& localPath, const QString& remotePath, const QString &fileDesc) { - m_sftpSession = sftp_new(m_session); + m_scpSession = ssh_scp_new(m_session, SSH_SCP_WRITE, remotePath.toStdString().c_str()); - if (m_sftpSession == nullptr) { - return closeSftpSession(); + if (m_scpSession == nullptr) { + return fromLibsshErrorCode(); } - int result = sftp_init(m_sftpSession); - - if (result != SSH_OK) { - return closeSftpSession(); + if (ssh_scp_init(m_scpSession) != SSH_OK) { + auto errorCode = fromLibsshErrorCode(); + closeScpSession(); + return errorCode; } QFutureWatcher watcher; - connect(&watcher, &QFutureWatcher::finished, this, &Client::sftpFileCopyFinished); - + connect(&watcher, &QFutureWatcher::finished, this, &Client::scpFileCopyFinished); QFuture future = QtConcurrent::run([this, overwriteMode, &localPath, &remotePath, &fileDesc]() { - int accessType = O_WRONLY | O_CREAT | overwriteMode; - sftp_file file; - const size_t bufferSize = 16384; - char buffer[bufferSize]; + const int accessType = O_WRONLY | O_CREAT | overwriteMode; + const int localFileSize = QFileInfo(localPath).size(); - file = sftp_open(m_sftpSession, remotePath.toStdString().c_str(), accessType, S_IRWXU); - - if (file == nullptr) { - return closeSftpSession(); + int result = ssh_scp_push_file(m_scpSession, remotePath.toStdString().c_str(), localFileSize, accessType); + if (result != SSH_OK) { + return fromLibsshErrorCode(); } - int localFileSize = QFileInfo(localPath).size(); - int chunksCount = localFileSize / (bufferSize); - QFile fin(localPath); if (fin.open(QIODevice::ReadOnly)) { - for (int currentChunkId = 0; currentChunkId < chunksCount; currentChunkId++) { - QByteArray chunk = fin.read(bufferSize); - if (chunk.size() != bufferSize) return ErrorCode::SshSftpEofError; + constexpr size_t bufferSize = 16384; + int transferred = 0; + int currentChunkSize = bufferSize; - int bytesWritten = sftp_write(file, chunk.data(), chunk.size()); + while (transferred < localFileSize) { - if (bytesWritten != chunk.size()) { - fin.close(); - sftp_close(file); - return closeSftpSession(); + // Last Chunk + if ((localFileSize - transferred) < bufferSize) { + currentChunkSize = localFileSize % bufferSize; } - } - int lastChunkSize = localFileSize % bufferSize; - - if (lastChunkSize != 0) { - QByteArray lastChunk = fin.read(lastChunkSize); - if (lastChunk.size() != lastChunkSize) return ErrorCode::SshSftpEofError; - - int bytesWritten = sftp_write(file, lastChunk.data(), lastChunkSize); - - if (bytesWritten != lastChunkSize) { - fin.close(); - sftp_close(file); - return closeSftpSession(); + QByteArray chunk = fin.read(currentChunkSize); + if (chunk.size() != currentChunkSize) { + return fromFileErrorCode(fin.error()); } + + result = ssh_scp_write(m_scpSession, chunk.data(), chunk.size()); + if (result != SSH_OK) { + return fromLibsshErrorCode(); + } + + transferred += currentChunkSize; } } else { - sftp_close(file); - return closeSftpSession(); + return fromFileErrorCode(fin.error()); } - fin.close(); - - int result = sftp_close(file); - if (result != SSH_OK) { - return closeSftpSession(); - } - - return closeSftpSession(); + return ErrorCode::NoError; }); watcher.setFuture(future); QEventLoop wait; - QObject::connect(this, &Client::sftpFileCopyFinished, &wait, &QEventLoop::quit); + QObject::connect(this, &Client::scpFileCopyFinished, &wait, &QEventLoop::quit); wait.exec(); + closeScpSession(); return watcher.result(); } - ErrorCode Client::closeSftpSession() + void Client::closeScpSession() { - auto errorCode = fromLibsshSftpErrorCode(sftp_get_error(m_sftpSession)); - if (m_sftpSession != nullptr) { - sftp_free(m_sftpSession); - m_sftpSession = nullptr; + if (m_scpSession != nullptr) { + ssh_scp_free(m_scpSession); + m_scpSession = nullptr; } - qCritical() << ssh_get_error(m_session); - return errorCode; } ErrorCode Client::fromLibsshErrorCode() @@ -337,24 +310,17 @@ namespace libssh { default: return ErrorCode::SshInternalError; } } - ErrorCode Client::fromLibsshSftpErrorCode(int errorCode) + + ErrorCode Client::fromFileErrorCode(QFileDevice::FileError fileError) { - switch (errorCode) { - case(SSH_FX_OK): return ErrorCode::NoError; - case(SSH_FX_EOF): return ErrorCode::SshSftpEofError; - case(SSH_FX_NO_SUCH_FILE): return ErrorCode::SshSftpNoSuchFileError; - case(SSH_FX_PERMISSION_DENIED): return ErrorCode::SshSftpPermissionDeniedError; - case(SSH_FX_FAILURE): return ErrorCode::SshSftpFailureError; - case(SSH_FX_BAD_MESSAGE): return ErrorCode::SshSftpBadMessageError; - case(SSH_FX_NO_CONNECTION): return ErrorCode::SshSftpNoConnectionError; - case(SSH_FX_CONNECTION_LOST): return ErrorCode::SshSftpConnectionLostError; - case(SSH_FX_OP_UNSUPPORTED): return ErrorCode::SshSftpOpUnsupportedError; - case(SSH_FX_INVALID_HANDLE): return ErrorCode::SshSftpInvalidHandleError; - case(SSH_FX_NO_SUCH_PATH): return ErrorCode::SshSftpNoSuchPathError; - case(SSH_FX_FILE_ALREADY_EXISTS): return ErrorCode::SshSftpFileAlreadyExistsError; - case(SSH_FX_WRITE_PROTECT): return ErrorCode::SshSftpWriteProtectError; - case(SSH_FX_NO_MEDIA): return ErrorCode::SshSftpNoMediaError; - default: return ErrorCode::SshSftpFailureError; + switch (fileError) { + case QFileDevice::NoError: return ErrorCode::NoError; + case QFileDevice::ReadError: return ErrorCode::ReadError; + case QFileDevice::OpenError: return ErrorCode::OpenError; + case QFileDevice::PermissionsError: return ErrorCode::PermissionsError; + case QFileDevice::FatalError: return ErrorCode::FatalError; + case QFileDevice::AbortError: return ErrorCode::AbortError; + default: return ErrorCode::UnspecifiedError; } } diff --git a/client/core/sshclient.h b/client/core/sshclient.h index 74c3b724..2ef26fb1 100644 --- a/client/core/sshclient.h +++ b/client/core/sshclient.h @@ -2,29 +2,29 @@ #define SSHCLIENT_H #include +#include #include #include -#include #include "defs.h" using namespace amnezia; namespace libssh { - enum SftpOverwriteMode { + enum ScpOverwriteMode { /*! Overwrite any existing files */ - SftpOverwriteExisting = O_TRUNC, + ScpOverwriteExisting = O_TRUNC, /*! Append new content if the file already exists */ - SftpAppendToExisting = O_APPEND + ScpAppendToExisting = O_APPEND }; class Client : public QObject { Q_OBJECT public: - Client(QObject *parent = nullptr); - ~Client(); + Client() = default; + ~Client() = default; ErrorCode connectToHost(const ServerCredentials &credentials); void disconnectFromHost(); @@ -32,26 +32,26 @@ namespace libssh { const std::function &cbReadStdOut, const std::function &cbReadStdErr); ErrorCode writeResponse(const QString &data); - ErrorCode sftpFileCopy(const SftpOverwriteMode overwriteMode, + ErrorCode scpFileCopy(const ScpOverwriteMode overwriteMode, const QString &localPath, const QString &remotePath, - const QString& fileDesc); + const QString &fileDesc); ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function &passphraseCallback); private: ErrorCode closeChannel(); - ErrorCode closeSftpSession(); + void closeScpSession(); ErrorCode fromLibsshErrorCode(); - ErrorCode fromLibsshSftpErrorCode(int errorCode); + ErrorCode fromFileErrorCode(QFileDevice::FileError fileError); static int callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata); ssh_session m_session = nullptr; ssh_channel m_channel = nullptr; - sftp_session m_sftpSession = nullptr; + ssh_scp m_scpSession = nullptr; static std::function m_passphraseCallback; signals: void writeToChannelFinished(); - void sftpFileCopyFinished(); + void scpFileCopyFinished(); }; }