aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/ssh')
-rw-r--r--src/libs/ssh/opensshkeyfilereader.cpp201
-rw-r--r--src/libs/ssh/opensshkeyfilereader_p.h73
-rw-r--r--src/libs/ssh/sftpchannel.cpp976
-rw-r--r--src/libs/ssh/sftpchannel.h103
-rw-r--r--src/libs/ssh/sftpchannel_p.h124
-rw-r--r--src/libs/ssh/sftpdefs.h28
-rw-r--r--src/libs/ssh/sftpfilesystemmodel.cpp70
-rw-r--r--src/libs/ssh/sftpfilesystemmodel.h2
-rw-r--r--src/libs/ssh/sftpincomingpacket.cpp217
-rw-r--r--src/libs/ssh/sftpincomingpacket_p.h104
-rw-r--r--src/libs/ssh/sftpoperation.cpp220
-rw-r--r--src/libs/ssh/sftpoperation_p.h244
-rw-r--r--src/libs/ssh/sftpoutgoingpacket.cpp220
-rw-r--r--src/libs/ssh/sftpoutgoingpacket_p.h84
-rw-r--r--src/libs/ssh/sftppacket.cpp49
-rw-r--r--src/libs/ssh/sftppacket_p.h109
-rw-r--r--src/libs/ssh/sftpsession.cpp332
-rw-r--r--src/libs/ssh/sftpsession.h (renamed from src/libs/ssh/sshtcpipforwardserver.h)64
-rw-r--r--src/libs/ssh/sftptransfer.cpp185
-rw-r--r--src/libs/ssh/sftptransfer.h (renamed from src/libs/ssh/sshx11inforetriever_p.h)39
-rw-r--r--src/libs/ssh/ssh.pro119
-rw-r--r--src/libs/ssh/ssh.qbs101
-rw-r--r--src/libs/ssh/ssh_dependencies.pri1
-rw-r--r--src/libs/ssh/ssh_global.h5
-rw-r--r--src/libs/ssh/sshagent.cpp314
-rw-r--r--src/libs/ssh/sshagent_p.h125
-rw-r--r--src/libs/ssh/sshbotanconversions_p.h138
-rw-r--r--src/libs/ssh/sshcapabilities.cpp170
-rw-r--r--src/libs/ssh/sshcapabilities_p.h83
-rw-r--r--src/libs/ssh/sshchannel.cpp269
-rw-r--r--src/libs/ssh/sshchannel_p.h117
-rw-r--r--src/libs/ssh/sshchannelmanager.cpp407
-rw-r--r--src/libs/ssh/sshchannelmanager_p.h109
-rw-r--r--src/libs/ssh/sshconnection.cpp1116
-rw-r--r--src/libs/ssh/sshconnection.h88
-rw-r--r--src/libs/ssh/sshconnection_p.h194
-rw-r--r--src/libs/ssh/sshconnectionmanager.cpp24
-rw-r--r--src/libs/ssh/sshcryptofacility.cpp453
-rw-r--r--src/libs/ssh/sshcryptofacility_p.h144
-rw-r--r--src/libs/ssh/sshdirecttcpiptunnel.cpp122
-rw-r--r--src/libs/ssh/sshdirecttcpiptunnel.h79
-rw-r--r--src/libs/ssh/sshdirecttcpiptunnel_p.h59
-rw-r--r--src/libs/ssh/ssherrors.h41
-rw-r--r--src/libs/ssh/sshexception_p.h87
-rw-r--r--src/libs/ssh/sshforwardedtcpiptunnel.cpp100
-rw-r--r--src/libs/ssh/sshforwardedtcpiptunnel.h70
-rw-r--r--src/libs/ssh/sshforwardedtcpiptunnel_p.h44
-rw-r--r--src/libs/ssh/sshhostkeydatabase.cpp118
-rw-r--r--src/libs/ssh/sshincomingpacket.cpp604
-rw-r--r--src/libs/ssh/sshincomingpacket_p.h244
-rw-r--r--src/libs/ssh/sshkeycreationdialog.cpp87
-rw-r--r--src/libs/ssh/sshkeycreationdialog.h5
-rw-r--r--src/libs/ssh/sshkeyexchange.cpp285
-rw-r--r--src/libs/ssh/sshkeyexchange_p.h95
-rw-r--r--src/libs/ssh/sshkeygenerator.cpp236
-rw-r--r--src/libs/ssh/sshkeygenerator.h75
-rw-r--r--src/libs/ssh/sshkeypasswordretriever.cpp55
-rw-r--r--src/libs/ssh/sshoutgoingpacket.cpp415
-rw-r--r--src/libs/ssh/sshoutgoingpacket_p.h117
-rw-r--r--src/libs/ssh/sshpacket.cpp153
-rw-r--r--src/libs/ssh/sshpacket_p.h147
-rw-r--r--src/libs/ssh/sshpacketparser.cpp154
-rw-r--r--src/libs/ssh/sshpacketparser_p.h75
-rw-r--r--src/libs/ssh/sshprocess.cpp (renamed from src/libs/ssh/sshx11displayinfo_p.h)48
-rw-r--r--src/libs/ssh/sshprocess_p.h (renamed from src/libs/ssh/sshkeypasswordretriever_p.h)14
-rw-r--r--src/libs/ssh/sshpseudoterminal.h110
-rw-r--r--src/libs/ssh/sshremoteprocess.cpp385
-rw-r--r--src/libs/ssh/sshremoteprocess.h79
-rw-r--r--src/libs/ssh/sshremoteprocess_p.h110
-rw-r--r--src/libs/ssh/sshremoteprocessrunner.cpp88
-rw-r--r--src/libs/ssh/sshremoteprocessrunner.h14
-rw-r--r--src/libs/ssh/sshsendfacility.cpp283
-rw-r--r--src/libs/ssh/sshsendfacility_p.h112
-rw-r--r--src/libs/ssh/sshsettings.cpp159
-rw-r--r--src/libs/ssh/sshsettings.h (renamed from src/libs/ssh/sshhostkeydatabase.h)48
-rw-r--r--src/libs/ssh/sshtcpipforwardserver.cpp136
-rw-r--r--src/libs/ssh/sshtcpipforwardserver_p.h54
-rw-r--r--src/libs/ssh/sshtcpiptunnel.cpp123
-rw-r--r--src/libs/ssh/sshtcpiptunnel_p.h82
-rw-r--r--src/libs/ssh/sshx11channel.cpp220
-rw-r--r--src/libs/ssh/sshx11channel_p.h73
-rw-r--r--src/libs/ssh/sshx11inforetriever.cpp153
82 files changed, 1307 insertions, 11872 deletions
diff --git a/src/libs/ssh/opensshkeyfilereader.cpp b/src/libs/ssh/opensshkeyfilereader.cpp
deleted file mode 100644
index 1a5cb2ece6..0000000000
--- a/src/libs/ssh/opensshkeyfilereader.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "opensshkeyfilereader_p.h"
-
-#include "sshcapabilities_p.h"
-#include "ssherrors.h"
-#include "sshexception_p.h"
-#include "sshlogging_p.h"
-#include "sshpacketparser_p.h"
-#include "ssh_global.h"
-
-#include <botan/dl_group.h>
-#include <botan/dsa.h>
-#include <botan/ecdsa.h>
-#include <botan/rsa.h>
-
-namespace QSsh {
-namespace Internal {
-
-using namespace Botan;
-
-bool OpenSshKeyFileReader::parseKey(const QByteArray &privKeyFileContents)
-{
- static const QByteArray magicPrefix = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
- static const QByteArray magicSuffix = "-----END OPENSSH PRIVATE KEY-----\n";
- if (!privKeyFileContents.startsWith(magicPrefix)) {
- qCDebug(sshLog) << "not an OpenSSH key file: prefix does not match";
- return false;
- }
- if (!privKeyFileContents.endsWith(magicSuffix))
- throwException(SSH_TR("Unexpected end-of-file marker."));
- const QByteArray payload = QByteArray::fromBase64
- (privKeyFileContents.mid(magicPrefix.size(), privKeyFileContents.size()
- - magicPrefix.size() - magicSuffix.size()));
- doParse(payload);
- return true;
-}
-
-std::unique_ptr<Private_Key> OpenSshKeyFileReader::privateKey() const
-{
- if (m_keyType == SshCapabilities::PubKeyRsa) {
- QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 5, nullptr);
- const BigInt &e = m_parameters.at(0);
- const BigInt &n = m_parameters.at(1);
- const BigInt &p = m_parameters.at(2);
- const BigInt &q = m_parameters.at(3);
- const BigInt &d = m_parameters.at(4);
- return std::make_unique<RSA_PrivateKey>(p, q, e, d, n);
- } else if (m_keyType == SshCapabilities::PubKeyDss) {
- QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 5, nullptr);
- const BigInt &p = m_parameters.at(0);
- const BigInt &q = m_parameters.at(1);
- const BigInt &g = m_parameters.at(2);
- const BigInt &x = m_parameters.at(4);
- return std::make_unique<DSA_PrivateKey>(m_rng, DL_Group(p, q, g), x);
- } else if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
- QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 1, nullptr);
- const BigInt &value = m_parameters.first();
- const EC_Group group(SshCapabilities::oid(m_keyType));
- return std::make_unique<ECDSA_PrivateKey>(m_rng, group, value);
- }
- QSSH_ASSERT_AND_RETURN_VALUE(false, nullptr);
-}
-
-QList<BigInt> OpenSshKeyFileReader::publicParameters() const
-{
- if (m_keyType == SshCapabilities::PubKeyRsa)
- return m_parameters.mid(0, 2);
- if (m_keyType == SshCapabilities::PubKeyDss)
- return m_parameters.mid(0, 4);
- if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix))
- return QList<BigInt>();
- QSSH_ASSERT_AND_RETURN_VALUE(false, QList<BigInt>());
-}
-
-void OpenSshKeyFileReader::doParse(const QByteArray &payload)
-{
- // See PROTOCOL.key in OpenSSH sources.
- static const QByteArray magicString = "openssh-key-v1";
- if (!payload.startsWith(magicString))
- throwException(SSH_TR("Unexpected magic string."));
- try {
- quint32 offset = magicString.size() + 1; // null byte
- m_cipherName = SshPacketParser::asString(payload, &offset);
- qCDebug(sshLog) << "cipher:" << m_cipherName;
- m_kdf = SshPacketParser::asString(payload, &offset);
- qCDebug(sshLog) << "kdf:" << m_kdf;
- parseKdfOptions(SshPacketParser::asString(payload, &offset));
- const quint32 keyCount = SshPacketParser::asUint32(payload, &offset);
- if (keyCount != 1) {
- qCWarning(sshLog) << "more than one key found in OpenSSH private key file, ignoring "
- "all but the first one";
- }
- for (quint32 i = 0; i < keyCount; ++i) // Skip the public key blob(s).
- SshPacketParser::asString(payload, &offset);
- m_privateKeyList = SshPacketParser::asString(payload, &offset);
- decryptPrivateKeyList();
- parsePrivateKeyList();
- } catch (const SshPacketParseException &) {
- throwException(SSH_TR("Parse error."));
- } catch (const Exception &e) {
- throwException(QLatin1String(e.what()));
- }
-}
-
-void OpenSshKeyFileReader::parseKdfOptions(const QByteArray &kdfOptions)
-{
- if (m_cipherName == "none")
- return;
- quint32 offset = 0;
- m_salt = SshPacketParser::asString(kdfOptions, &offset);
- if (m_salt.size() != 16)
- throwException(SSH_TR("Invalid salt size %1.").arg(m_salt.size()));
- m_rounds = SshPacketParser::asUint32(kdfOptions, &offset);
- qCDebug(sshLog) << "salt:" << m_salt.toHex();
- qCDebug(sshLog) << "rounds:" << m_rounds;
-}
-
-void OpenSshKeyFileReader::decryptPrivateKeyList()
-{
- if (m_cipherName == "none")
- return;
- if (m_kdf != "bcrypt") {
- throwException(SSH_TR("Unexpected key derivation function '%1'.")
- .arg(QLatin1String(m_kdf)));
- }
-
- // OpenSSH uses a proprietary algorithm for the key derivation. We'd basically have to
- // copy the code.
- // TODO: If the lower-level operations (hashing primitives, blowfish stuff) can be taken
- // over by Botan, that might be feasible. Investigate.
- throwException(SSH_TR("Encrypted keys are currently not supported in this format."));
-}
-
-void OpenSshKeyFileReader::parsePrivateKeyList()
-{
- quint32 offset = 0;
- const quint32 checkInt1 = SshPacketParser::asUint32(m_privateKeyList, &offset);
- const quint32 checkInt2 = SshPacketParser::asUint32(m_privateKeyList, &offset);
- if (checkInt1 != checkInt2)
- throwException(SSH_TR("Verification failed."));
- m_keyType = SshPacketParser::asString(m_privateKeyList, &offset);
- qCDebug(sshLog) << "key type:" << m_keyType;
- if (m_keyType == SshCapabilities::PubKeyRsa) {
- const BigInt n = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt e = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt d = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- SshPacketParser::asBigInt(m_privateKeyList, &offset); // iqmp
- const BigInt p = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt q = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- m_parameters = QList<BigInt>{e, n, p, q, d};
- } else if (m_keyType == SshCapabilities::PubKeyDss) {
- const BigInt p = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt q = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt g = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt y = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- const BigInt x = SshPacketParser::asBigInt(m_privateKeyList, &offset);
- m_parameters = QList<BigInt>{p, q, g, y, x};
- } else if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
- SshPacketParser::asString(m_privateKeyList, &offset); // name
- SshPacketParser::asString(m_privateKeyList, &offset); // pubkey representation
- m_parameters = {SshPacketParser::asBigInt(m_privateKeyList, &offset)};
- } else {
- throwException(SSH_TR("Private key type '%1' is not supported.")
- .arg(QString::fromLatin1(m_keyType)));
- }
- const QByteArray comment = SshPacketParser::asString(m_privateKeyList, &offset);
- qCDebug(sshLog) << "comment:" << comment;
-}
-
-void OpenSshKeyFileReader::throwException(const QString &reason)
-{
- throw SshClientException(SshKeyFileError,
- SSH_TR("Processing OpenSSH private key file failed: %1").arg(reason));
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/opensshkeyfilereader_p.h b/src/libs/ssh/opensshkeyfilereader_p.h
deleted file mode 100644
index 0ea0eb5c92..0000000000
--- a/src/libs/ssh/opensshkeyfilereader_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QByteArray>
-#include <QList>
-
-#include <botan/bigint.h>
-
-#include <memory>
-
-namespace Botan {
-class Private_Key;
-class RandomNumberGenerator;
-}
-
-namespace QSsh {
-namespace Internal {
-
-class OpenSshKeyFileReader
-{
-public:
- OpenSshKeyFileReader(Botan::RandomNumberGenerator &rng) : m_rng(rng) {}
-
- bool parseKey(const QByteArray &privKeyFileContents);
- QByteArray keyType() const { return m_keyType; }
- std::unique_ptr<Botan::Private_Key> privateKey() const;
- QList<Botan::BigInt> allParameters() const { return m_parameters; }
- QList<Botan::BigInt> publicParameters() const;
-
-private:
- void doParse(const QByteArray &payload);
- void parseKdfOptions(const QByteArray &kdfOptions);
- void decryptPrivateKeyList();
- void parsePrivateKeyList();
- [[noreturn]] void throwException(const QString &reason);
-
- Botan::RandomNumberGenerator &m_rng;
- QByteArray m_keyType;
- QList<Botan::BigInt> m_parameters;
- QByteArray m_cipherName;
- QByteArray m_kdf;
- QByteArray m_salt;
- quint32 m_rounds;
- QByteArray m_privateKeyList;
-};
-
-} // namespace Internal
-} // namespace QSsh
-
diff --git a/src/libs/ssh/sftpchannel.cpp b/src/libs/ssh/sftpchannel.cpp
deleted file mode 100644
index 59c6ea66ec..0000000000
--- a/src/libs/ssh/sftpchannel.cpp
+++ /dev/null
@@ -1,976 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sftpchannel.h"
-#include "sftpchannel_p.h"
-
-#include "sshexception_p.h"
-#include "sshincomingpacket_p.h"
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-
-#include <QDir>
-#include <QFile>
-
-/*!
- \class QSsh::SftpChannel
-
- \brief The SftpChannel class provides SFTP operations.
-
- Objects are created via SshConnection::createSftpChannel().
- The channel needs to be initialized with
- a call to initialize() and is closed via closeChannel(). After closing
- a channel, no more operations are possible. It cannot be re-opened
- using initialize(); use SshConnection::createSftpChannel() if you need
- a new one.
-
- After the initialized() signal has been emitted, operations can be started.
- All SFTP operations are asynchronous (non-blocking) and can be in-flight
- simultaneously (though callers must ensure that concurrently running jobs
- are independent of each other, e.g. they must not write to the same file).
- Operations are identified by their job id, which is returned by
- the respective member function. If the function can right away detect that
- the operation cannot succeed, it returns SftpInvalidJob. If an error occurs
- later, the finished() signal is emitted for the respective job with a
- non-empty error string.
-
- Note that directory names must not have a trailing slash.
-*/
-
-namespace QSsh {
-namespace Internal {
-namespace {
- const quint32 ProtocolVersion = 3;
-
- QString errorMessage(const QString &serverMessage,
- const QString &alternativeMessage)
- {
- return serverMessage.isEmpty() ? alternativeMessage : serverMessage;
- }
-
- QString errorMessage(const SftpStatusResponse &response,
- const QString &alternativeMessage)
- {
- return response.status == SSH_FX_OK ? QString()
- : errorMessage(response.errorString, alternativeMessage);
- }
-} // anonymous namespace
-} // namespace Internal
-
-SftpChannel::SftpChannel(quint32 channelId,
- Internal::SshSendFacility &sendFacility)
- : d(new Internal::SftpChannelPrivate(channelId, sendFacility, this))
-{
- connect(d, &Internal::SftpChannelPrivate::initialized,
- this, &SftpChannel::initialized, Qt::QueuedConnection);
- connect(d, &Internal::SftpChannelPrivate::channelError,
- this, &SftpChannel::channelError, Qt::QueuedConnection);
- connect(d, &Internal::SftpChannelPrivate::dataAvailable,
- this, &SftpChannel::dataAvailable, Qt::QueuedConnection);
- connect(d, &Internal::SftpChannelPrivate::fileInfoAvailable,
- this, &SftpChannel::fileInfoAvailable, Qt::QueuedConnection);
- connect(d, &Internal::SftpChannelPrivate::finished,
- this, &SftpChannel::finished, Qt::QueuedConnection);
- connect(d, &Internal::SftpChannelPrivate::closed,
- this, &SftpChannel::closed, Qt::QueuedConnection);
-}
-
-SftpChannel::State SftpChannel::state() const
-{
- switch (d->channelState()) {
- case Internal::AbstractSshChannel::Inactive:
- return Uninitialized;
- case Internal::AbstractSshChannel::SessionRequested:
- return Initializing;
- case Internal::AbstractSshChannel::CloseRequested:
- return Closing;
- case Internal::AbstractSshChannel::Closed:
- return Closed;
- case Internal::AbstractSshChannel::SessionEstablished:
- return d->m_sftpState == Internal::SftpChannelPrivate::Initialized
- ? Initialized : Initializing;
- default:
- Q_ASSERT(!"Oh no, we forgot to handle a channel state!");
- return Closed; // For the compiler.
- }
-}
-
-void SftpChannel::initialize()
-{
- d->requestSessionStart();
- d->m_sftpState = Internal::SftpChannelPrivate::SubsystemRequested;
-}
-
-void SftpChannel::closeChannel()
-{
- d->closeChannel();
-}
-
-SftpJobId SftpChannel::statFile(const QString &path)
-{
- return d->createJob(Internal::SftpStatFile::Ptr(
- new Internal::SftpStatFile(++d->m_nextJobId, path)));
-}
-
-SftpJobId SftpChannel::listDirectory(const QString &path)
-{
- return d->createJob(Internal::SftpListDir::Ptr(
- new Internal::SftpListDir(++d->m_nextJobId, path)));
-}
-
-SftpJobId SftpChannel::createDirectory(const QString &path)
-{
- return d->createJob(Internal::SftpMakeDir::Ptr(
- new Internal::SftpMakeDir(++d->m_nextJobId, path)));
-}
-
-SftpJobId SftpChannel::removeDirectory(const QString &path)
-{
- return d->createJob(Internal::SftpRmDir::Ptr(
- new Internal::SftpRmDir(++d->m_nextJobId, path)));
-}
-
-SftpJobId SftpChannel::removeFile(const QString &path)
-{
- return d->createJob(Internal::SftpRm::Ptr(
- new Internal::SftpRm(++d->m_nextJobId, path)));
-}
-
-SftpJobId SftpChannel::renameFileOrDirectory(const QString &oldPath,
- const QString &newPath)
-{
- return d->createJob(Internal::SftpRename::Ptr(
- new Internal::SftpRename(++d->m_nextJobId, oldPath, newPath)));
-}
-
-SftpJobId SftpChannel::createLink(const QString &filePath, const QString &target)
-{
- return d->createJob(Internal::SftpCreateLink::Ptr(
- new Internal::SftpCreateLink(++d->m_nextJobId, filePath, target)));
-}
-
-SftpJobId SftpChannel::createFile(const QString &path, SftpOverwriteMode mode)
-{
- return d->createJob(Internal::SftpCreateFile::Ptr(
- new Internal::SftpCreateFile(++d->m_nextJobId, path, mode)));
-}
-
-SftpJobId SftpChannel::uploadFile(const QString &localFilePath,
- const QString &remoteFilePath, SftpOverwriteMode mode)
-{
- QSharedPointer<QFile> localFile(new QFile(localFilePath));
- if (!localFile->open(QIODevice::ReadOnly))
- return SftpInvalidJob;
- return d->createJob(Internal::SftpUploadFile::Ptr(
- new Internal::SftpUploadFile(++d->m_nextJobId, remoteFilePath, localFile, mode)));
-}
-
-SftpJobId SftpChannel::downloadFile(const QString &remoteFilePath,
- const QString &localFilePath, SftpOverwriteMode mode)
-{
- QSharedPointer<QFile> localFile(new QFile(localFilePath));
- if (mode == SftpSkipExisting && localFile->exists())
- return SftpInvalidJob;
- QIODevice::OpenMode openMode = QIODevice::WriteOnly;
- if (mode == SftpOverwriteExisting)
- openMode |= QIODevice::Truncate;
- else if (mode == SftpAppendToExisting)
- openMode |= QIODevice::Append;
- if (!localFile->open(openMode))
- return SftpInvalidJob;
- return d->createJob(Internal::SftpDownload::Ptr(
- new Internal::SftpDownload(++d->m_nextJobId, remoteFilePath, localFile)));
-}
-
-SftpJobId SftpChannel::uploadDir(const QString &localDirPath,
- const QString &remoteParentDirPath)
-{
- if (state() != Initialized)
- return SftpInvalidJob;
- const QDir localDir(localDirPath);
- if (!localDir.exists() || !localDir.isReadable())
- return SftpInvalidJob;
- const Internal::SftpUploadDir::Ptr uploadDirOp(
- new Internal::SftpUploadDir(++d->m_nextJobId));
- const QString remoteDirPath
- = remoteParentDirPath + QLatin1Char('/') + localDir.dirName();
- const Internal::SftpMakeDir::Ptr mkdirOp(
- new Internal::SftpMakeDir(++d->m_nextJobId, remoteDirPath, uploadDirOp));
- uploadDirOp->mkdirsInProgress.insert(mkdirOp,
- Internal::SftpUploadDir::Dir(localDirPath, remoteDirPath));
- d->createJob(mkdirOp);
- return uploadDirOp->jobId;
-}
-
-SftpChannel::~SftpChannel()
-{
- delete d;
-}
-
-
-namespace Internal {
-
-SftpChannelPrivate::SftpChannelPrivate(quint32 channelId,
- SshSendFacility &sendFacility, SftpChannel *sftp)
- : AbstractSshChannel(channelId, sendFacility),
- m_nextJobId(0), m_sftpState(Inactive), m_sftp(sftp)
-{
-}
-
-SftpJobId SftpChannelPrivate::createJob(const AbstractSftpOperation::Ptr &job)
-{
- if (m_sftp->state() != SftpChannel::Initialized)
- return SftpInvalidJob;
- m_jobs.insert(job->jobId, job);
- sendData(job->initialPacket(m_outgoingPacket).rawData());
- return job->jobId;
-}
-
-void SftpChannelPrivate::handleChannelSuccess()
-{
- if (channelState() == CloseRequested)
- return;
- qCDebug(sshLog, "sftp subsystem initialized");
- sendData(m_outgoingPacket.generateInit(ProtocolVersion).rawData());
- m_sftpState = InitSent;
-}
-
-void SftpChannelPrivate::handleChannelFailure()
-{
- if (channelState() == CloseRequested)
- return;
-
- if (m_sftpState != SubsystemRequested) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_FAILURE packet.");
- }
- emit channelError(tr("Server could not start SFTP subsystem."));
- closeChannel();
-}
-
-void SftpChannelPrivate::handleChannelDataInternal(const QByteArray &data)
-{
- if (channelState() == CloseRequested)
- return;
-
- m_incomingData += data;
- m_incomingPacket.consumeData(m_incomingData);
- while (m_incomingPacket.isComplete()) {
- handleCurrentPacket();
- m_incomingPacket.clear();
- m_incomingPacket.consumeData(m_incomingData);
- }
-}
-
-void SftpChannelPrivate::handleChannelExtendedDataInternal(quint32 type,
- const QByteArray &data)
-{
- qCWarning(sshLog, "Unexpected extended data '%s' of type %d on SFTP channel.",
- data.data(), type);
-}
-
-void SftpChannelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus)
-{
- qCDebug(sshLog, "Remote SFTP service exited with exit code %d", exitStatus.exitStatus);
-
- if (channelState() == CloseRequested || channelState() == Closed)
- return;
-
- emit channelError(tr("The SFTP server finished unexpectedly with exit code %1.")
- .arg(exitStatus.exitStatus));
-
- // Note: According to the specs, the server must close the channel after this happens,
- // but OpenSSH doesn't do that, so we need to initiate the closing procedure ourselves.
- closeChannel();
-}
-
-void SftpChannelPrivate::handleExitSignal(const SshChannelExitSignal &signal)
-{
- emit channelError(tr("The SFTP server crashed: %1.").arg(signal.error));
- closeChannel(); // See above.
-}
-
-void SftpChannelPrivate::handleCurrentPacket()
-{
- qCDebug(sshLog, "Handling SFTP packet of type %d", m_incomingPacket.type());
- switch (m_incomingPacket.type()) {
- case SSH_FXP_VERSION:
- handleServerVersion();
- break;
- case SSH_FXP_HANDLE:
- handleHandle();
- break;
- case SSH_FXP_NAME:
- handleName();
- break;
- case SSH_FXP_STATUS:
- handleStatus();
- break;
- case SSH_FXP_DATA:
- handleReadData();
- break;
- case SSH_FXP_ATTRS:
- handleAttrs();
- break;
- default:
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected packet.",
- tr("Unexpected packet of type %1.").arg(m_incomingPacket.type()));
- }
-}
-
-void SftpChannelPrivate::handleServerVersion()
-{
- checkChannelActive();
- if (m_sftpState != InitSent) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_VERSION packet.");
- }
-
- qCDebug(sshLog, "sftp init received");
- const quint32 serverVersion = m_incomingPacket.extractServerVersion();
- if (serverVersion != ProtocolVersion) {
- emit channelError(tr("Protocol version mismatch: Expected %1, got %2")
- .arg(serverVersion).arg(ProtocolVersion));
- closeChannel();
- } else {
- m_sftpState = Initialized;
- emit initialized();
- }
-}
-
-void SftpChannelPrivate::handleHandle()
-{
- const SftpHandleResponse &response = m_incomingPacket.asHandleResponse();
- JobMap::Iterator it = lookupJob(response.requestId);
- const QSharedPointer<AbstractSftpOperationWithHandle> job
- = it.value().dynamicCast<AbstractSftpOperationWithHandle>();
- if (job.isNull()) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_HANDLE packet.");
- }
- if (job->state != AbstractSftpOperationWithHandle::OpenRequested) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_HANDLE packet.");
- }
- job->remoteHandle = response.handle;
- job->state = AbstractSftpOperationWithHandle::Open;
-
- switch (it.value()->type()) {
- case AbstractSftpOperation::ListDir:
- handleLsHandle(it);
- break;
- case AbstractSftpOperation::CreateFile:
- handleCreateFileHandle(it);
- break;
- case AbstractSftpOperation::Download:
- handleGetHandle(it);
- break;
- case AbstractSftpOperation::UploadFile:
- handlePutHandle(it);
- break;
- default:
- Q_ASSERT(!"Oh no, I forgot to handle an SFTP operation type!");
- }
-}
-
-void SftpChannelPrivate::handleLsHandle(const JobMap::Iterator &it)
-{
- SftpListDir::Ptr op = it.value().staticCast<SftpListDir>();
- sendData(m_outgoingPacket.generateReadDir(op->remoteHandle,
- op->jobId).rawData());
-}
-
-void SftpChannelPrivate::handleCreateFileHandle(const JobMap::Iterator &it)
-{
- SftpCreateFile::Ptr op = it.value().staticCast<SftpCreateFile>();
- sendData(m_outgoingPacket.generateCloseHandle(op->remoteHandle,
- op->jobId).rawData());
-}
-
-void SftpChannelPrivate::handleGetHandle(const JobMap::Iterator &it)
-{
- SftpDownload::Ptr op = it.value().staticCast<SftpDownload>();
- sendData(m_outgoingPacket.generateFstat(op->remoteHandle,
- op->jobId).rawData());
- op->statRequested = true;
-}
-
-void SftpChannelPrivate::handlePutHandle(const JobMap::Iterator &it)
-{
- SftpUploadFile::Ptr op = it.value().staticCast<SftpUploadFile>();
- if (op->parentJob && op->parentJob->hasError)
- sendTransferCloseHandle(op, it.key());
-
- // OpenSSH does not implement the RFC's append functionality, so we
- // have to emulate it.
- if (op->mode == SftpAppendToExisting) {
- sendData(m_outgoingPacket.generateFstat(op->remoteHandle,
- op->jobId).rawData());
- op->statRequested = true;
- } else {
- spawnWriteRequests(it);
- }
-}
-
-void SftpChannelPrivate::handleStatus()
-{
- const SftpStatusResponse &response = m_incomingPacket.asStatusResponse();
- qCDebug(sshLog, "%s: status = %d", Q_FUNC_INFO, response.status);
- JobMap::Iterator it = lookupJob(response.requestId);
- switch (it.value()->type()) {
- case AbstractSftpOperation::ListDir:
- handleLsStatus(it, response);
- break;
- case AbstractSftpOperation::Download:
- handleGetStatus(it, response);
- break;
- case AbstractSftpOperation::UploadFile:
- handlePutStatus(it, response);
- break;
- case AbstractSftpOperation::MakeDir:
- handleMkdirStatus(it, response);
- break;
- case AbstractSftpOperation::StatFile:
- case AbstractSftpOperation::RmDir:
- case AbstractSftpOperation::Rm:
- case AbstractSftpOperation::Rename:
- case AbstractSftpOperation::CreateFile:
- case AbstractSftpOperation::CreateLink:
- handleStatusGeneric(it, response);
- break;
- }
-}
-
-void SftpChannelPrivate::handleStatusGeneric(const JobMap::Iterator &it,
- const SftpStatusResponse &response)
-{
- AbstractSftpOperation::Ptr op = it.value();
- const QString error = errorMessage(response, tr("Unknown error."));
- emit finished(op->jobId, error);
- m_jobs.erase(it);
-}
-
-void SftpChannelPrivate::handleMkdirStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response)
-{
- SftpMakeDir::Ptr op = it.value().staticCast<SftpMakeDir>();
- QSharedPointer<SftpUploadDir> parentJob = op->parentJob;
- if (parentJob == SftpUploadDir::Ptr()) {
- handleStatusGeneric(it, response);
- return;
- }
- if (parentJob->hasError) {
- m_jobs.erase(it);
- return;
- }
-
- typedef QMap<SftpMakeDir::Ptr, SftpUploadDir::Dir>::Iterator DirIt;
- DirIt dirIt = parentJob->mkdirsInProgress.find(op);
- Q_ASSERT(dirIt != parentJob->mkdirsInProgress.end());
- const QString &remoteDir = dirIt.value().remoteDir;
- if (response.status == SSH_FX_OK) {
- emit dataAvailable(parentJob->jobId,
- tr("Created remote directory \"%1\".").arg(remoteDir));
- } else if (response.status == SSH_FX_FAILURE) {
- emit dataAvailable(parentJob->jobId,
- tr("Remote directory \"%1\" already exists.").arg(remoteDir));
- } else {
- parentJob->setError();
- emit finished(parentJob->jobId,
- tr("Error creating directory \"%1\": %2")
- .arg(remoteDir, response.errorString));
- m_jobs.erase(it);
- return;
- }
-
- QDir localDir(dirIt.value().localDir);
- const QFileInfoList &dirInfos
- = localDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
- foreach (const QFileInfo &dirInfo, dirInfos) {
- const QString remoteSubDir = remoteDir + QLatin1Char('/') + dirInfo.fileName();
- const SftpMakeDir::Ptr mkdirOp(
- new SftpMakeDir(++m_nextJobId, remoteSubDir, parentJob));
- parentJob->mkdirsInProgress.insert(mkdirOp,
- SftpUploadDir::Dir(dirInfo.absoluteFilePath(), remoteSubDir));
- createJob(mkdirOp);
- }
-
- const QFileInfoList &fileInfos = localDir.entryInfoList(QDir::Files);
- foreach (const QFileInfo &fileInfo, fileInfos) {
- QSharedPointer<QFile> localFile(new QFile(fileInfo.absoluteFilePath()));
- if (!localFile->open(QIODevice::ReadOnly)) {
- parentJob->setError();
- emit finished(parentJob->jobId,
- tr("Could not open local file \"%1\": %2")
- .arg(fileInfo.absoluteFilePath(), localFile->errorString()));
- m_jobs.erase(it);
- return;
- }
-
- const QString remoteFilePath = remoteDir + QLatin1Char('/') + fileInfo.fileName();
- SftpUploadFile::Ptr uploadFileOp(new SftpUploadFile(++m_nextJobId,
- remoteFilePath, localFile, SftpOverwriteExisting, parentJob));
- createJob(uploadFileOp);
- parentJob->uploadsInProgress.append(uploadFileOp);
- }
-
- parentJob->mkdirsInProgress.erase(dirIt);
- if (parentJob->mkdirsInProgress.isEmpty()
- && parentJob->uploadsInProgress.isEmpty())
- emit finished(parentJob->jobId);
- m_jobs.erase(it);
-}
-
-void SftpChannelPrivate::handleLsStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response)
-{
- SftpListDir::Ptr op = it.value().staticCast<SftpListDir>();
- switch (op->state) {
- case SftpListDir::OpenRequested:
- emit finished(op->jobId, errorMessage(response.errorString,
- tr("Remote directory could not be opened for reading.")));
- m_jobs.erase(it);
- break;
- case SftpListDir::Open:
- if (response.status != SSH_FX_EOF)
- reportRequestError(op, errorMessage(response.errorString,
- tr("Failed to list remote directory contents.")));
- op->state = SftpListDir::CloseRequested;
- sendData(m_outgoingPacket.generateCloseHandle(op->remoteHandle,
- op->jobId).rawData());
- break;
- case SftpListDir::CloseRequested:
- if (!op->hasError) {
- const QString error = errorMessage(response,
- tr("Failed to close remote directory."));
- emit finished(op->jobId, error);
- }
- m_jobs.erase(it);
- break;
- default:
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_STATUS packet.");
- }
-}
-
-void SftpChannelPrivate::handleGetStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response)
-{
- SftpDownload::Ptr op = it.value().staticCast<SftpDownload>();
- switch (op->state) {
- case SftpDownload::OpenRequested:
- emit finished(op->jobId,
- errorMessage(response.errorString,
- tr("Failed to open remote file for reading.")));
- m_jobs.erase(it);
- break;
- case SftpDownload::Open:
- if (op->statRequested) {
- reportRequestError(op, errorMessage(response.errorString,
- tr("Failed to retrieve information on the remote file ('stat' failed).")));
- sendTransferCloseHandle(op, response.requestId);
- } else {
- if ((response.status != SSH_FX_EOF || response.requestId != op->eofId)
- && !op->hasError)
- reportRequestError(op, errorMessage(response.errorString,
- tr("Failed to read remote file.")));
- finishTransferRequest(it);
- }
- break;
- case SftpDownload::CloseRequested:
- Q_ASSERT(op->inFlightCount == 1);
- if (!op->hasError) {
- if (response.status == SSH_FX_OK)
- emit finished(op->jobId);
- else
- reportRequestError(op, errorMessage(response.errorString,
- tr("Failed to close remote file.")));
- }
- removeTransferRequest(it);
- break;
- default:
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_STATUS packet.");
- }
-}
-
-void SftpChannelPrivate::handlePutStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response)
-{
- SftpUploadFile::Ptr job = it.value().staticCast<SftpUploadFile>();
- switch (job->state) {
- case SftpUploadFile::OpenRequested: {
- bool emitError = false;
- if (job->parentJob) {
- if (!job->parentJob->hasError) {
- job->parentJob->setError();
- emitError = true;
- }
- } else {
- emitError = true;
- }
-
- if (emitError) {
- emit finished(job->jobId,
- errorMessage(response.errorString,
- tr("Failed to open remote file for writing.")));
- }
- m_jobs.erase(it);
- break;
- }
- case SftpUploadFile::Open:
- if (job->hasError || (job->parentJob && job->parentJob->hasError)) {
- job->hasError = true;
- finishTransferRequest(it);
- return;
- }
-
- if (response.status == SSH_FX_OK) {
- sendWriteRequest(it);
- } else {
- if (job->parentJob)
- job->parentJob->setError();
- reportRequestError(job, errorMessage(response.errorString,
- tr("Failed to write remote file.")));
- finishTransferRequest(it);
- }
- break;
- case SftpUploadFile::CloseRequested:
- Q_ASSERT(job->inFlightCount == 1);
- if (job->hasError || (job->parentJob && job->parentJob->hasError)) {
- m_jobs.erase(it);
- return;
- }
-
- if (response.status == SSH_FX_OK) {
- if (job->parentJob) {
- job->parentJob->uploadsInProgress.removeOne(job);
- if (job->parentJob->mkdirsInProgress.isEmpty()
- && job->parentJob->uploadsInProgress.isEmpty())
- emit finished(job->parentJob->jobId);
- } else {
- emit finished(job->jobId);
- }
- } else {
- const QString error = errorMessage(response.errorString,
- tr("Failed to close remote file."));
- if (job->parentJob) {
- job->parentJob->setError();
- emit finished(job->parentJob->jobId, error);
- } else {
- emit finished(job->jobId, error);
- }
- }
- m_jobs.erase(it);
- break;
- default:
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_STATUS packet.");
- }
-}
-
-void SftpChannelPrivate::handleName()
-{
- const SftpNameResponse &response = m_incomingPacket.asNameResponse();
- JobMap::Iterator it = lookupJob(response.requestId);
- switch (it.value()->type()) {
- case AbstractSftpOperation::ListDir: {
- SftpListDir::Ptr op = it.value().staticCast<SftpListDir>();
- if (op->state != SftpListDir::Open) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_NAME packet.");
- }
-
- QList<SftpFileInfo> fileInfoList;
- for (int i = 0; i < response.files.count(); ++i) {
- const SftpFile &file = response.files.at(i);
-
- SftpFileInfo fileInfo;
- fileInfo.name = file.fileName;
- attributesToFileInfo(file.attributes, fileInfo);
- fileInfoList << fileInfo;
- }
- emit fileInfoAvailable(op->jobId, fileInfoList);
- sendData(m_outgoingPacket.generateReadDir(op->remoteHandle,
- op->jobId).rawData());
- break;
- }
- default:
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_NAME packet.");
- }
-}
-
-void SftpChannelPrivate::handleReadData()
-{
- const SftpDataResponse &response = m_incomingPacket.asDataResponse();
- JobMap::Iterator it = lookupJob(response.requestId);
- if (it.value()->type() != AbstractSftpOperation::Download) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_DATA packet.");
- }
-
- SftpDownload::Ptr op = it.value().staticCast<SftpDownload>();
- if (op->hasError) {
- finishTransferRequest(it);
- return;
- }
-
- if (!op->localFile->seek(op->offsets[response.requestId])) {
- reportRequestError(op, op->localFile->errorString());
- finishTransferRequest(it);
- return;
- }
-
- if (op->localFile->write(response.data) != response.data.size()) {
- reportRequestError(op, op->localFile->errorString());
- finishTransferRequest(it);
- return;
- }
-
- if (op->offset >= op->fileSize && op->fileSize != 0)
- finishTransferRequest(it);
- else
- sendReadRequest(op, response.requestId);
-}
-
-void SftpChannelPrivate::handleAttrs()
-{
- const SftpAttrsResponse &response = m_incomingPacket.asAttrsResponse();
- JobMap::Iterator it = lookupJob(response.requestId);
-
- SftpStatFile::Ptr statOp = it.value().dynamicCast<SftpStatFile>();
- if (statOp) {
- SftpFileInfo fileInfo;
- fileInfo.name = QFileInfo(statOp->path).fileName();
- attributesToFileInfo(response.attrs, fileInfo);
- emit fileInfoAvailable(it.key(), QList<SftpFileInfo>() << fileInfo);
- emit finished(it.key());
- m_jobs.erase(it);
- return;
- }
-
- AbstractSftpTransfer::Ptr transfer
- = it.value().dynamicCast<AbstractSftpTransfer>();
- if (!transfer || transfer->state != AbstractSftpTransfer::Open
- || !transfer->statRequested) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_FXP_ATTRS packet.");
- }
- Q_ASSERT(transfer->type() == AbstractSftpOperation::UploadFile
- || transfer->type() == AbstractSftpOperation::Download);
-
- if (transfer->type() == AbstractSftpOperation::Download) {
- SftpDownload::Ptr op = transfer.staticCast<SftpDownload>();
- if (response.attrs.sizePresent) {
- op->fileSize = response.attrs.size;
- } else {
- op->fileSize = 0;
- op->eofId = op->jobId;
- }
- op->statRequested = false;
- spawnReadRequests(op);
- } else {
- SftpUploadFile::Ptr op = transfer.staticCast<SftpUploadFile>();
- if (op->parentJob && op->parentJob->hasError) {
- op->hasError = true;
- sendTransferCloseHandle(op, op->jobId);
- return;
- }
-
- if (response.attrs.sizePresent) {
- op->offset = response.attrs.size;
- spawnWriteRequests(it);
- } else {
- if (op->parentJob)
- op->parentJob->setError();
- reportRequestError(op, tr("Cannot append to remote file: "
- "Server does not support the file size attribute."));
- sendTransferCloseHandle(op, op->jobId);
- }
- }
-}
-
-SftpChannelPrivate::JobMap::Iterator SftpChannelPrivate::lookupJob(SftpJobId id)
-{
- JobMap::Iterator it = m_jobs.find(id);
- if (it == m_jobs.end()) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid request id in SFTP packet.");
- }
- return it;
-}
-
-void SftpChannelPrivate::closeHook()
-{
- for (JobMap::ConstIterator it = m_jobs.constBegin(); it != m_jobs.constEnd(); ++it)
- emit finished(it.key(), tr("SFTP channel closed unexpectedly."));
- m_jobs.clear();
- m_incomingData.clear();
- m_incomingPacket.clear();
- emit closed();
-}
-
-void SftpChannelPrivate::handleOpenSuccessInternal()
-{
- qCDebug(sshLog, "SFTP session started");
- m_sendFacility.sendSftpPacket(remoteChannel());
- m_sftpState = SubsystemRequested;
-}
-
-void SftpChannelPrivate::handleOpenFailureInternal(const QString &reason)
-{
- if (channelState() != SessionRequested) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
- }
- emit channelError(tr("Server could not start session: %1").arg(reason));
-}
-
-void SftpChannelPrivate::sendReadRequest(const SftpDownload::Ptr &job,
- quint32 requestId)
-{
- Q_ASSERT(job->eofId == SftpInvalidJob);
- sendData(m_outgoingPacket.generateReadFile(job->remoteHandle, job->offset,
- AbstractSftpPacket::MaxDataSize, requestId).rawData());
- job->offsets[requestId] = job->offset;
- job->offset += AbstractSftpPacket::MaxDataSize;
- if (job->offset >= job->fileSize)
- job->eofId = requestId;
-}
-
-void SftpChannelPrivate::reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job,
- const QString &error)
-{
- emit finished(job->jobId, error);
- job->hasError = true;
-}
-
-void SftpChannelPrivate::finishTransferRequest(const JobMap::Iterator &it)
-{
- AbstractSftpTransfer::Ptr job = it.value().staticCast<AbstractSftpTransfer>();
- if (job->inFlightCount == 1)
- sendTransferCloseHandle(job, it.key());
- else
- removeTransferRequest(it);
-}
-
-void SftpChannelPrivate::sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job,
- quint32 requestId)
-{
- sendData(m_outgoingPacket.generateCloseHandle(job->remoteHandle,
- requestId).rawData());
- job->state = SftpDownload::CloseRequested;
-}
-
-void SftpChannelPrivate::attributesToFileInfo(const SftpFileAttributes &attributes,
- SftpFileInfo &fileInfo) const
-{
- if (attributes.sizePresent) {
- fileInfo.sizeValid = true;
- fileInfo.size = attributes.size;
- }
- if (attributes.permissionsPresent) {
- if (attributes.permissions & 0x8000) // S_IFREG
- fileInfo.type = FileTypeRegular;
- else if (attributes.permissions & 0x4000) // S_IFDIR
- fileInfo.type = FileTypeDirectory;
- else
- fileInfo.type = FileTypeOther;
- fileInfo.permissionsValid = true;
- fileInfo.permissions = 0;
- if (attributes.permissions & 00001) // S_IXOTH
- fileInfo.permissions |= QFile::ExeOther;
- if (attributes.permissions & 00002) // S_IWOTH
- fileInfo.permissions |= QFile::WriteOther;
- if (attributes.permissions & 00004) // S_IROTH
- fileInfo.permissions |= QFile::ReadOther;
- if (attributes.permissions & 00010) // S_IXGRP
- fileInfo.permissions |= QFile::ExeGroup;
- if (attributes.permissions & 00020) // S_IWGRP
- fileInfo.permissions |= QFile::WriteGroup;
- if (attributes.permissions & 00040) // S_IRGRP
- fileInfo.permissions |= QFile::ReadGroup;
- if (attributes.permissions & 00100) // S_IXUSR
- fileInfo.permissions |= QFile::ExeUser | QFile::ExeOwner;
- if (attributes.permissions & 00200) // S_IWUSR
- fileInfo.permissions |= QFile::WriteUser | QFile::WriteOwner;
- if (attributes.permissions & 00400) // S_IRUSR
- fileInfo.permissions |= QFile::ReadUser | QFile::ReadOwner;
- }
- if (attributes.timesPresent) {
- fileInfo.mtime = attributes.mtime;
- fileInfo.mtimeValid = true;
- }
-}
-
-void SftpChannelPrivate::removeTransferRequest(const JobMap::Iterator &it)
-{
- --it.value().staticCast<AbstractSftpTransfer>()->inFlightCount;
- m_jobs.erase(it);
-}
-
-void SftpChannelPrivate::sendWriteRequest(const JobMap::Iterator &it)
-{
- SftpUploadFile::Ptr job = it.value().staticCast<SftpUploadFile>();
- QByteArray data = job->localFile->read(AbstractSftpPacket::MaxDataSize);
- if (job->localFile->error() != QFile::NoError) {
- if (job->parentJob)
- job->parentJob->setError();
- reportRequestError(job, tr("Error reading local file: %1")
- .arg(job->localFile->errorString()));
- finishTransferRequest(it);
- } else if (data.isEmpty()) {
- finishTransferRequest(it);
- } else {
- sendData(m_outgoingPacket.generateWriteFile(job->remoteHandle,
- job->offset, data, it.key()).rawData());
- job->offset += AbstractSftpPacket::MaxDataSize;
- }
-}
-
-void SftpChannelPrivate::spawnWriteRequests(const JobMap::Iterator &it)
-{
- SftpUploadFile::Ptr op = it.value().staticCast<SftpUploadFile>();
- op->calculateInFlightCount(AbstractSftpPacket::MaxDataSize);
- sendWriteRequest(it);
- for (int i = 1; !op->hasError && i < op->inFlightCount; ++i)
- sendWriteRequest(m_jobs.insert(++m_nextJobId, op));
-}
-
-void SftpChannelPrivate::spawnReadRequests(const SftpDownload::Ptr &job)
-{
- job->calculateInFlightCount(AbstractSftpPacket::MaxDataSize);
- sendReadRequest(job, job->jobId);
- for (int i = 1; i < job->inFlightCount; ++i) {
- const quint32 requestId = ++m_nextJobId;
- m_jobs.insert(requestId, job);
- sendReadRequest(job, requestId);
- }
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpchannel.h b/src/libs/ssh/sftpchannel.h
deleted file mode 100644
index 78857459ee..0000000000
--- a/src/libs/ssh/sftpchannel.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sftpdefs.h"
-#include "sftpincomingpacket_p.h"
-
-#include "ssh_global.h"
-
-#include <QByteArray>
-#include <QObject>
-#include <QSharedPointer>
-#include <QString>
-
-namespace QSsh {
-
-namespace Internal {
-class SftpChannelPrivate;
-class SshChannelManager;
-class SshSendFacility;
-} // namespace Internal
-
-class QSSH_EXPORT SftpChannel : public QObject
-{
- Q_OBJECT
-
- friend class Internal::SftpChannelPrivate;
- friend class Internal::SshChannelManager;
-public:
- typedef QSharedPointer<SftpChannel> Ptr;
-
- enum State { Uninitialized, Initializing, Initialized, Closing, Closed };
- State state() const;
-
- void initialize();
- void closeChannel();
-
- SftpJobId statFile(const QString &path);
- SftpJobId listDirectory(const QString &dirPath);
- SftpJobId createDirectory(const QString &dirPath);
- SftpJobId removeDirectory(const QString &dirPath);
- SftpJobId removeFile(const QString &filePath);
- SftpJobId renameFileOrDirectory(const QString &oldPath,
- const QString &newPath);
- SftpJobId createFile(const QString &filePath, SftpOverwriteMode mode);
- SftpJobId createLink(const QString &filePath, const QString &target);
- SftpJobId uploadFile(const QString &localFilePath,
- const QString &remoteFilePath, SftpOverwriteMode mode);
- SftpJobId downloadFile(const QString &remoteFilePath,
- const QString &localFilePath, SftpOverwriteMode mode);
- SftpJobId uploadDir(const QString &localDirPath,
- const QString &remoteParentDirPath);
-
- ~SftpChannel();
-
-signals:
- void initialized();
- void channelError(const QString &reason);
- void closed();
-
- // error.isEmpty <=> finished successfully
- void finished(QSsh::SftpJobId job, const QString &error = QString());
-
- // TODO: Also emit for each file copied by uploadDir().
- void dataAvailable(QSsh::SftpJobId job, const QString &data);
-
- /*
- * This signal is emitted as a result of:
- * - statFile() (with the list having exactly one element)
- * - listDirectory() (potentially more than once)
- */
- void fileInfoAvailable(QSsh::SftpJobId job, const QList<QSsh::SftpFileInfo> &fileInfoList);
-
-private:
- SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility);
-
- Internal::SftpChannelPrivate *d;
-};
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpchannel_p.h b/src/libs/ssh/sftpchannel_p.h
deleted file mode 100644
index 6ab1c3a2db..0000000000
--- a/src/libs/ssh/sftpchannel_p.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sftpdefs.h"
-#include "sftpincomingpacket_p.h"
-#include "sftpoperation_p.h"
-#include "sftpoutgoingpacket_p.h"
-#include "sshchannel_p.h"
-
-#include <QByteArray>
-#include <QMap>
-
-namespace QSsh {
-class SftpChannel;
-namespace Internal {
-
-class SftpChannelPrivate : public AbstractSshChannel
-{
- Q_OBJECT
- friend class QSsh::SftpChannel;
-public:
- enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized };
-
-signals:
- void initialized();
- void channelError(const QString &reason);
- void closed();
- void finished(QSsh::SftpJobId job, const QString &error = QString());
- void dataAvailable(QSsh::SftpJobId job, const QString &data);
- void fileInfoAvailable(QSsh::SftpJobId job, const QList<QSsh::SftpFileInfo> &fileInfoList);
-
-private:
- typedef QMap<SftpJobId, AbstractSftpOperation::Ptr> JobMap;
-
- SftpChannelPrivate(quint32 channelId, SshSendFacility &sendFacility,
- SftpChannel *sftp);
- SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
-
- virtual void handleChannelSuccess();
- virtual void handleChannelFailure();
-
- virtual void handleOpenSuccessInternal();
- virtual void handleOpenFailureInternal(const QString &reason);
- virtual void handleChannelDataInternal(const QByteArray &data);
- virtual void handleChannelExtendedDataInternal(quint32 type,
- const QByteArray &data);
- virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
- virtual void handleExitSignal(const SshChannelExitSignal &signal);
-
- virtual void closeHook();
-
- void handleCurrentPacket();
- void handleServerVersion();
- void handleHandle();
- void handleStatus();
- void handleName();
- void handleReadData();
- void handleAttrs();
-
- void handleStatusGeneric(const JobMap::Iterator &it,
- const SftpStatusResponse &response);
- void handleMkdirStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response);
- void handleLsStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response);
- void handleGetStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response);
- void handlePutStatus(const JobMap::Iterator &it,
- const SftpStatusResponse &response);
-
- void handleLsHandle(const JobMap::Iterator &it);
- void handleCreateFileHandle(const JobMap::Iterator &it);
- void handleGetHandle(const JobMap::Iterator &it);
- void handlePutHandle(const JobMap::Iterator &it);
-
- void spawnReadRequests(const SftpDownload::Ptr &job);
- void spawnWriteRequests(const JobMap::Iterator &it);
- void sendReadRequest(const SftpDownload::Ptr &job, quint32 requestId);
- void sendWriteRequest(const JobMap::Iterator &it);
- void finishTransferRequest(const JobMap::Iterator &it);
- void removeTransferRequest(const JobMap::Iterator &it);
- void reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job,
- const QString &error);
- void sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job,
- quint32 requestId);
-
- void attributesToFileInfo(const SftpFileAttributes &attributes, SftpFileInfo &fileInfo) const;
-
- JobMap::Iterator lookupJob(SftpJobId id);
- JobMap m_jobs;
- SftpOutgoingPacket m_outgoingPacket;
- SftpIncomingPacket m_incomingPacket;
- QByteArray m_incomingData;
- SftpJobId m_nextJobId;
- SftpState m_sftpState;
- SftpChannel *m_sftp;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpdefs.h b/src/libs/ssh/sftpdefs.h
index b996c38ca4..e3d9be9b97 100644
--- a/src/libs/ssh/sftpdefs.h
+++ b/src/libs/ssh/sftpdefs.h
@@ -28,10 +28,32 @@
#include "ssh_global.h"
#include <QFile>
+#include <QList>
#include <QString>
+#include <memory>
+
namespace QSsh {
+class SftpTransfer;
+using SftpTransferPtr = std::unique_ptr<SftpTransfer>;
+class SftpSession;
+using SftpSessionPtr = std::unique_ptr<SftpSession>;
+
+enum class FileTransferErrorHandling { Abort, Ignore };
+
+class FileToTransfer
+{
+public:
+ FileToTransfer(const QString &source, const QString &target)
+ : sourceFile(source), targetFile(target) {}
+ QString sourceFile;
+ QString targetFile;
+};
+using FilesToTransfer = QList<FileToTransfer>;
+
+namespace Internal { enum class FileTransferType { Upload, Download }; }
+
typedef quint32 SftpJobId;
QSSH_EXPORT extern const SftpJobId SftpInvalidJob;
@@ -48,12 +70,6 @@ public:
SftpFileType type = FileTypeUnknown;
quint64 size = 0;
QFile::Permissions permissions;
- quint32 mtime = 0;
-
- // The RFC allows an SFTP server not to support any file attributes beyond the name.
- bool sizeValid = false;
- bool permissionsValid = false;
- bool mtimeValid = false;
};
} // namespace QSsh
diff --git a/src/libs/ssh/sftpfilesystemmodel.cpp b/src/libs/ssh/sftpfilesystemmodel.cpp
index b1a173759c..555796b812 100644
--- a/src/libs/ssh/sftpfilesystemmodel.cpp
+++ b/src/libs/ssh/sftpfilesystemmodel.cpp
@@ -25,10 +25,12 @@
#include "sftpfilesystemmodel.h"
-#include "sftpchannel.h"
+#include "sftpsession.h"
#include "sshconnection.h"
#include "sshconnectionmanager.h"
+#include <utils/qtcassert.h>
+
#include <QFileInfo>
#include <QHash>
#include <QIcon>
@@ -71,7 +73,7 @@ SftpFileNode *indexToFileNode(const QModelIndex &index)
SftpDirNode *indexToDirNode(const QModelIndex &index)
{
SftpFileNode * const fileNode = indexToFileNode(index);
- QSSH_ASSERT(fileNode);
+ QTC_CHECK(fileNode);
return dynamic_cast<SftpDirNode *>(fileNode);
}
@@ -81,7 +83,7 @@ class SftpFileSystemModelPrivate
{
public:
SshConnection *sshConnection;
- SftpChannel::Ptr sftpChannel;
+ SftpSessionPtr sftpSession;
QString rootDirectory;
SftpFileNode *rootNode;
SftpJobId statJobId;
@@ -109,9 +111,9 @@ SftpFileSystemModel::~SftpFileSystemModel()
void SftpFileSystemModel::setSshConnection(const SshConnectionParameters &sshParams)
{
- QSSH_ASSERT_AND_RETURN(!d->sshConnection);
+ QTC_ASSERT(!d->sshConnection, return);
d->sshConnection = QSsh::acquireConnection(sshParams);
- connect(d->sshConnection, &SshConnection::error,
+ connect(d->sshConnection, &SshConnection::errorOccurred,
this, &SftpFileSystemModel::handleSshConnectionFailure);
if (d->sshConnection->state() == SshConnection::Connected) {
handleSshConnectionEstablished();
@@ -142,12 +144,11 @@ QString SftpFileSystemModel::rootDirectory() const
SftpJobId SftpFileSystemModel::downloadFile(const QModelIndex &index, const QString &targetFilePath)
{
- QSSH_ASSERT_AND_RETURN_VALUE(d->rootNode, SftpInvalidJob);
+ QTC_ASSERT(d->rootNode, return SftpInvalidJob);
const SftpFileNode * const fileNode = indexToFileNode(index);
- QSSH_ASSERT_AND_RETURN_VALUE(fileNode, SftpInvalidJob);
- QSSH_ASSERT_AND_RETURN_VALUE(fileNode->fileInfo.type == FileTypeRegular, SftpInvalidJob);
- const SftpJobId jobId = d->sftpChannel->downloadFile(fileNode->path, targetFilePath,
- SftpOverwriteExisting);
+ QTC_ASSERT(fileNode, return SftpInvalidJob);
+ QTC_ASSERT(fileNode->fileInfo.type == FileTypeRegular, return SftpInvalidJob);
+ const SftpJobId jobId = d->sftpSession->downloadFile(fileNode->path, targetFilePath);
if (jobId != SftpInvalidJob)
d->externalJobs << jobId;
return jobId;
@@ -211,8 +212,8 @@ QModelIndex SftpFileSystemModel::index(int row, int column, const QModelIndex &p
if (!parent.isValid())
return createIndex(row, column, d->rootNode);
const SftpDirNode * const parentNode = indexToDirNode(parent);
- QSSH_ASSERT_AND_RETURN_VALUE(parentNode, QModelIndex());
- QSSH_ASSERT_AND_RETURN_VALUE(row < parentNode->children.count(), QModelIndex());
+ QTC_ASSERT(parentNode, return QModelIndex());
+ QTC_ASSERT(row < parentNode->children.count(), return QModelIndex());
SftpFileNode * const childNode = parentNode->children.at(row);
return createIndex(row, column, childNode);
}
@@ -223,14 +224,14 @@ QModelIndex SftpFileSystemModel::parent(const QModelIndex &child) const
return QModelIndex();
const SftpFileNode * const childNode = indexToFileNode(child);
- QSSH_ASSERT_AND_RETURN_VALUE(childNode, QModelIndex());
+ QTC_ASSERT(childNode, return QModelIndex());
if (childNode == d->rootNode)
return QModelIndex();
SftpDirNode * const parentNode = childNode->parent;
if (parentNode == d->rootNode)
return createIndex(0, 0, d->rootNode);
const SftpDirNode * const grandParentNode = parentNode->parent;
- QSSH_ASSERT_AND_RETURN_VALUE(grandParentNode, QModelIndex());
+ QTC_ASSERT(grandParentNode, return QModelIndex());
return createIndex(grandParentNode->children.indexOf(parentNode), 0, parentNode);
}
@@ -247,22 +248,22 @@ int SftpFileSystemModel::rowCount(const QModelIndex &parent) const
return 0;
if (dirNode->lsState != SftpDirNode::LsNotYetCalled)
return dirNode->children.count();
- d->lsOps.insert(d->sftpChannel->listDirectory(dirNode->path), dirNode);
+ d->lsOps.insert(d->sftpSession->ls(dirNode->path), dirNode);
dirNode->lsState = SftpDirNode::LsRunning;
return 0;
}
void SftpFileSystemModel::statRootDirectory()
{
- d->statJobId = d->sftpChannel->statFile(d->rootDirectory);
+ d->statJobId = d->sftpSession->ls(d->rootDirectory);
}
void SftpFileSystemModel::shutDown()
{
- if (d->sftpChannel) {
- disconnect(d->sftpChannel.data(), 0, this, 0);
- d->sftpChannel->closeChannel();
- d->sftpChannel.clear();
+ if (d->sftpSession) {
+ disconnect(d->sftpSession.get(), 0, this, 0);
+ d->sftpSession->quit();
+ d->sftpSession.release()->deleteLater();
}
if (d->sshConnection) {
disconnect(d->sshConnection, 0, this, 0);
@@ -283,25 +284,24 @@ void SftpFileSystemModel::handleSshConnectionFailure()
void SftpFileSystemModel::handleSftpChannelInitialized()
{
- connect(d->sftpChannel.data(),
- &SftpChannel::fileInfoAvailable,
+ connect(d->sftpSession.get(), &SftpSession::fileInfoAvailable,
this, &SftpFileSystemModel::handleFileInfo);
- connect(d->sftpChannel.data(), &SftpChannel::finished,
+ connect(d->sftpSession.get(), &SftpSession::commandFinished,
this, &SftpFileSystemModel::handleSftpJobFinished);
statRootDirectory();
}
void SftpFileSystemModel::handleSshConnectionEstablished()
{
- d->sftpChannel = d->sshConnection->createSftpChannel();
- connect(d->sftpChannel.data(), &SftpChannel::initialized,
+ d->sftpSession = d->sshConnection->createSftpSession();
+ connect(d->sftpSession.get(), &SftpSession::started,
this, &SftpFileSystemModel::handleSftpChannelInitialized);
- connect(d->sftpChannel.data(), &SftpChannel::channelError,
- this, &SftpFileSystemModel::handleSftpChannelError);
- d->sftpChannel->initialize();
+ connect(d->sftpSession.get(), &SftpSession::done,
+ this, &SftpFileSystemModel::handleSftpSessionClosed);
+ d->sftpSession->start();
}
-void SftpFileSystemModel::handleSftpChannelError(const QString &reason)
+void SftpFileSystemModel::handleSftpSessionClosed(const QString &reason)
{
emit connectionError(reason);
beginResetModel();
@@ -312,18 +312,18 @@ void SftpFileSystemModel::handleSftpChannelError(const QString &reason)
void SftpFileSystemModel::handleFileInfo(SftpJobId jobId, const QList<SftpFileInfo> &fileInfoList)
{
if (jobId == d->statJobId) {
- QSSH_ASSERT_AND_RETURN(!d->rootNode);
+ QTC_ASSERT(!d->rootNode, return);
beginInsertRows(QModelIndex(), 0, 0);
d->rootNode = new SftpDirNode;
d->rootNode->path = d->rootDirectory;
- d->rootNode->fileInfo = fileInfoList.first();
+ d->rootNode->fileInfo.type = FileTypeDirectory;
d->rootNode->fileInfo.name = d->rootDirectory == QLatin1String("/")
? d->rootDirectory : QFileInfo(d->rootDirectory).fileName();
endInsertRows();
return;
}
SftpDirNode * const parentNode = d->lsOps.value(jobId);
- QSSH_ASSERT_AND_RETURN(parentNode);
+ QTC_ASSERT(parentNode, return);
QList<SftpFileInfo> filteredList;
foreach (const SftpFileInfo &fi, fileInfoList) {
if (fi.name != QLatin1String(".") && fi.name != QLatin1String(".."))
@@ -358,14 +358,14 @@ void SftpFileSystemModel::handleSftpJobFinished(SftpJobId jobId, const QString &
if (jobId == d->statJobId) {
d->statJobId = SftpInvalidJob;
if (!errorMessage.isEmpty())
- emit sftpOperationFailed(tr("Error getting \"stat\" info about \"%1\": %2")
+ emit sftpOperationFailed(tr("Error listing root directory \"%1\": %2")
.arg(rootDirectory(), errorMessage));
return;
}
DirNodeHash::Iterator it = d->lsOps.find(jobId);
if (it != d->lsOps.end()) {
- QSSH_ASSERT(it.value()->lsState == SftpDirNode::LsRunning);
+ QTC_ASSERT(it.value()->lsState == SftpDirNode::LsRunning, return);
it.value()->lsState = SftpDirNode::LsFinished;
if (!errorMessage.isEmpty())
emit sftpOperationFailed(tr("Error listing contents of directory \"%1\": %2")
@@ -375,7 +375,7 @@ void SftpFileSystemModel::handleSftpJobFinished(SftpJobId jobId, const QString &
}
const int jobIndex = d->externalJobs.indexOf(jobId);
- QSSH_ASSERT_AND_RETURN(jobIndex != -1);
+ QTC_ASSERT(jobIndex != -1, return);
d->externalJobs.removeAt(jobIndex);
emit sftpOperationFinished(jobId, errorMessage);
}
diff --git a/src/libs/ssh/sftpfilesystemmodel.h b/src/libs/ssh/sftpfilesystemmodel.h
index 99f26ee1e2..091dfabb4c 100644
--- a/src/libs/ssh/sftpfilesystemmodel.h
+++ b/src/libs/ssh/sftpfilesystemmodel.h
@@ -80,7 +80,7 @@ private:
void handleSshConnectionEstablished();
void handleSshConnectionFailure();
void handleSftpChannelInitialized();
- void handleSftpChannelError(const QString &reason);
+ void handleSftpSessionClosed(const QString &reason);
void handleFileInfo(QSsh::SftpJobId jobId, const QList<QSsh::SftpFileInfo> &fileInfoList);
void handleSftpJobFinished(QSsh::SftpJobId jobId, const QString &errorMessage);
diff --git a/src/libs/ssh/sftpincomingpacket.cpp b/src/libs/ssh/sftpincomingpacket.cpp
deleted file mode 100644
index 4f580a16c2..0000000000
--- a/src/libs/ssh/sftpincomingpacket.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sftpincomingpacket_p.h"
-
-#include "sshexception_p.h"
-#include "sshlogging_p.h"
-#include "sshpacketparser_p.h"
-
-namespace QSsh {
-namespace Internal {
-
-SftpIncomingPacket::SftpIncomingPacket() : m_length(0)
-{
-}
-
-void SftpIncomingPacket::consumeData(QByteArray &newData)
-{
- qCDebug(sshLog, "%s: current data size = %d, new data size = %d", Q_FUNC_INFO,
- m_data.size(), newData.size());
-
- if (isComplete() || dataSize() + newData.size() < sizeof m_length)
- return;
-
- if (dataSize() < sizeof m_length) {
- moveFirstBytes(m_data, newData, sizeof m_length - m_data.size());
- m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
- if (m_length < static_cast<quint32>(TypeOffset + 1)
- || m_length > MaxPacketSize) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid length field in SFTP packet.");
- }
- }
-
- moveFirstBytes(m_data, newData,
- qMin<quint32>(m_length - dataSize() + 4, newData.size()));
-}
-
-void SftpIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source,
- int n)
-{
- target.append(source.left(n));
- source.remove(0, n);
-}
-
-bool SftpIncomingPacket::isComplete() const
-{
- return m_length == dataSize() - 4;
-}
-
-void SftpIncomingPacket::clear()
-{
- m_data.clear();
- m_length = 0;
-}
-
-quint32 SftpIncomingPacket::extractServerVersion() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_FXP_VERSION);
- try {
- return SshPacketParser::asUint32(m_data, TypeOffset + 1);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_FXP_VERSION packet.");
- }
-}
-
-SftpHandleResponse SftpIncomingPacket::asHandleResponse() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_FXP_HANDLE);
- try {
- SftpHandleResponse response;
- quint32 offset = RequestIdOffset;
- response.requestId = SshPacketParser::asUint32(m_data, &offset);
- response.handle = SshPacketParser::asString(m_data, &offset);
- return response;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_FXP_HANDLE packet");
- }
-}
-
-SftpStatusResponse SftpIncomingPacket::asStatusResponse() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_FXP_STATUS);
- try {
- SftpStatusResponse response;
- quint32 offset = RequestIdOffset;
- response.requestId = SshPacketParser::asUint32(m_data, &offset);
- response.status = static_cast<SftpStatusCode>(SshPacketParser::asUint32(m_data, &offset));
- response.errorString = SshPacketParser::asUserString(m_data, &offset);
- response.language = SshPacketParser::asString(m_data, &offset);
- return response;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_FXP_STATUS packet.");
- }
-}
-
-SftpNameResponse SftpIncomingPacket::asNameResponse() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_FXP_NAME);
- try {
- SftpNameResponse response;
- quint32 offset = RequestIdOffset;
- response.requestId = SshPacketParser::asUint32(m_data, &offset);
- const quint32 count = SshPacketParser::asUint32(m_data, &offset);
- for (quint32 i = 0; i < count; ++i)
- response.files << asFile(offset);
- return response;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_FXP_NAME packet.");
- }
-}
-
-SftpDataResponse SftpIncomingPacket::asDataResponse() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_FXP_DATA);
- try {
- SftpDataResponse response;
- quint32 offset = RequestIdOffset;
- response.requestId = SshPacketParser::asUint32(m_data, &offset);
- response.data = SshPacketParser::asString(m_data, &offset);
- return response;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_FXP_DATA packet.");
- }
-}
-
-SftpAttrsResponse SftpIncomingPacket::asAttrsResponse() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_FXP_ATTRS);
- try {
- SftpAttrsResponse response;
- quint32 offset = RequestIdOffset;
- response.requestId = SshPacketParser::asUint32(m_data, &offset);
- response.attrs = asFileAttributes(offset);
- return response;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_FXP_ATTRS packet.");
- }
-}
-
-SftpFile SftpIncomingPacket::asFile(quint32 &offset) const
-{
- SftpFile file;
- file.fileName
- = QString::fromUtf8(SshPacketParser::asString(m_data, &offset));
- file.longName
- = QString::fromUtf8(SshPacketParser::asString(m_data, &offset));
- file.attributes = asFileAttributes(offset);
- return file;
-}
-
-SftpFileAttributes SftpIncomingPacket::asFileAttributes(quint32 &offset) const
-{
- SftpFileAttributes attributes;
- const quint32 flags = SshPacketParser::asUint32(m_data, &offset);
- attributes.sizePresent = flags & SSH_FILEXFER_ATTR_SIZE;
- attributes.timesPresent = flags & SSH_FILEXFER_ATTR_ACMODTIME;
- attributes.uidAndGidPresent = flags & SSH_FILEXFER_ATTR_UIDGID;
- attributes.permissionsPresent = flags & SSH_FILEXFER_ATTR_PERMISSIONS;
- if (attributes.sizePresent)
- attributes.size = SshPacketParser::asUint64(m_data, &offset);
- if (attributes.uidAndGidPresent) {
- attributes.uid = SshPacketParser::asUint32(m_data, &offset);
- attributes.gid = SshPacketParser::asUint32(m_data, &offset);
- }
- if (attributes.permissionsPresent)
- attributes.permissions = SshPacketParser::asUint32(m_data, &offset);
- if (attributes.timesPresent) {
- attributes.atime = SshPacketParser::asUint32(m_data, &offset);
- attributes.mtime = SshPacketParser::asUint32(m_data, &offset);
- }
- if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
- const quint32 count = SshPacketParser::asUint32(m_data, &offset);
- for (quint32 i = 0; i < count; ++i) {
- SshPacketParser::asString(m_data, &offset);
- SshPacketParser::asString(m_data, &offset);
- }
- }
- return attributes;
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpincomingpacket_p.h b/src/libs/ssh/sftpincomingpacket_p.h
deleted file mode 100644
index fe372e30fb..0000000000
--- a/src/libs/ssh/sftpincomingpacket_p.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sftppacket_p.h"
-
-namespace QSsh {
-namespace Internal {
-
-struct SftpHandleResponse {
- quint32 requestId;
- QByteArray handle;
-};
-
-struct SftpStatusResponse {
- quint32 requestId;
- SftpStatusCode status;
- QString errorString;
- QByteArray language;
-};
-
-struct SftpFileAttributes {
- bool sizePresent;
- bool timesPresent;
- bool uidAndGidPresent;
- bool permissionsPresent;
- quint64 size;
- quint32 uid;
- quint32 gid;
- quint32 permissions;
- quint32 atime;
- quint32 mtime;
-};
-
-struct SftpFile {
- QString fileName;
- QString longName; // Not present in later RFCs, so we don't expose this to the user.
- SftpFileAttributes attributes;
-};
-
-struct SftpNameResponse {
- quint32 requestId;
- QList<SftpFile> files;
-};
-
-struct SftpDataResponse {
- quint32 requestId;
- QByteArray data;
-};
-
-struct SftpAttrsResponse {
- quint32 requestId;
- SftpFileAttributes attrs;
-};
-
-class SftpIncomingPacket : public AbstractSftpPacket
-{
-public:
- SftpIncomingPacket();
-
- void consumeData(QByteArray &data);
- void clear();
- bool isComplete() const;
- quint32 extractServerVersion() const;
- SftpHandleResponse asHandleResponse() const;
- SftpStatusResponse asStatusResponse() const;
- SftpNameResponse asNameResponse() const;
- SftpDataResponse asDataResponse() const;
- SftpAttrsResponse asAttrsResponse() const;
-
-private:
- void moveFirstBytes(QByteArray &target, QByteArray &source, int n);
-
- SftpFileAttributes asFileAttributes(quint32 &offset) const;
- SftpFile asFile(quint32 &offset) const;
-
- quint32 m_length;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpoperation.cpp b/src/libs/ssh/sftpoperation.cpp
deleted file mode 100644
index 257a851542..0000000000
--- a/src/libs/ssh/sftpoperation.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sftpoperation_p.h"
-
-#include "sftpoutgoingpacket_p.h"
-
-#include <QFile>
-
-namespace QSsh {
-namespace Internal {
-
-AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId)
-{
-}
-
-AbstractSftpOperation::~AbstractSftpOperation() { }
-
-
-SftpStatFile::SftpStatFile(SftpJobId jobId, const QString &path)
- : AbstractSftpOperation(jobId), path(path)
-{
-}
-
-SftpOutgoingPacket &SftpStatFile::initialPacket(SftpOutgoingPacket &packet)
-{
- return packet.generateStat(path, jobId);
-}
-
-SftpMakeDir::SftpMakeDir(SftpJobId jobId, const QString &path,
- const SftpUploadDir::Ptr &parentJob)
- : AbstractSftpOperation(jobId), parentJob(parentJob), remoteDir(path)
-{
-}
-
-SftpOutgoingPacket &SftpMakeDir::initialPacket(SftpOutgoingPacket &packet)
-{
- return packet.generateMkDir(remoteDir, jobId);
-}
-
-
-SftpRmDir::SftpRmDir(SftpJobId id, const QString &path)
- : AbstractSftpOperation(id), remoteDir(path)
-{
-}
-
-SftpOutgoingPacket &SftpRmDir::initialPacket(SftpOutgoingPacket &packet)
-{
- return packet.generateRmDir(remoteDir, jobId);
-}
-
-
-SftpRm::SftpRm(SftpJobId jobId, const QString &path)
- : AbstractSftpOperation(jobId), remoteFile(path) {}
-
-SftpOutgoingPacket &SftpRm::initialPacket(SftpOutgoingPacket &packet)
-{
- return packet.generateRm(remoteFile, jobId);
-}
-
-
-SftpRename::SftpRename(SftpJobId jobId, const QString &oldPath,
- const QString &newPath)
- : AbstractSftpOperation(jobId), oldPath(oldPath), newPath(newPath)
-{
-}
-
-SftpOutgoingPacket &SftpRename::initialPacket(SftpOutgoingPacket &packet)
-{
- return packet.generateRename(oldPath, newPath, jobId);
-}
-
-
-SftpCreateLink::SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target)
- : AbstractSftpOperation(jobId), filePath(filePath), target(target)
-{
-}
-
-SftpOutgoingPacket &SftpCreateLink::initialPacket(SftpOutgoingPacket &packet)
-{
- return packet.generateCreateLink(filePath, target, jobId);
-}
-
-
-AbstractSftpOperationWithHandle::AbstractSftpOperationWithHandle(SftpJobId jobId,
- const QString &remotePath)
- : AbstractSftpOperation(jobId),
- remotePath(remotePath), state(Inactive), hasError(false)
-{
-}
-
-AbstractSftpOperationWithHandle::~AbstractSftpOperationWithHandle() { }
-
-
-SftpListDir::SftpListDir(SftpJobId jobId, const QString &path)
- : AbstractSftpOperationWithHandle(jobId, path)
-{
-}
-
-SftpOutgoingPacket &SftpListDir::initialPacket(SftpOutgoingPacket &packet)
-{
- state = OpenRequested;
- return packet.generateOpenDir(remotePath, jobId);
-}
-
-
-SftpCreateFile::SftpCreateFile(SftpJobId jobId, const QString &path,
- SftpOverwriteMode mode)
- : AbstractSftpOperationWithHandle(jobId, path), mode(mode)
-{
-}
-
-SftpOutgoingPacket & SftpCreateFile::initialPacket(SftpOutgoingPacket &packet)
-{
- state = OpenRequested;
- return packet.generateOpenFileForWriting(remotePath, mode,
- SftpOutgoingPacket::DefaultPermissions, jobId);
-}
-
-
-const int AbstractSftpTransfer::MaxInFlightCount = 10; // Experimentally found to be enough.
-
-AbstractSftpTransfer::AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath,
- const QSharedPointer<QFile> &localFile)
- : AbstractSftpOperationWithHandle(jobId, remotePath),
- localFile(localFile), fileSize(0), offset(0), inFlightCount(0),
- statRequested(false)
-{
-}
-
-AbstractSftpTransfer::~AbstractSftpTransfer() {}
-
-void AbstractSftpTransfer::calculateInFlightCount(quint32 chunkSize)
-{
- if (fileSize == 0) {
- inFlightCount = 1;
- } else {
- inFlightCount = fileSize / chunkSize;
- if (fileSize % chunkSize)
- ++inFlightCount;
- if (inFlightCount > MaxInFlightCount)
- inFlightCount = MaxInFlightCount;
- }
-}
-
-
-SftpDownload::SftpDownload(SftpJobId jobId, const QString &remotePath,
- const QSharedPointer<QFile> &localFile)
- : AbstractSftpTransfer(jobId, remotePath, localFile), eofId(SftpInvalidJob)
-{
-}
-
-SftpOutgoingPacket &SftpDownload::initialPacket(SftpOutgoingPacket &packet)
-{
- state = OpenRequested;
- return packet.generateOpenFileForReading(remotePath, jobId);
-}
-
-
-SftpUploadFile::SftpUploadFile(SftpJobId jobId, const QString &remotePath,
- const QSharedPointer<QFile> &localFile, SftpOverwriteMode mode,
- const SftpUploadDir::Ptr &parentJob)
- : AbstractSftpTransfer(jobId, remotePath, localFile),
- parentJob(parentJob), mode(mode)
-{
- fileSize = localFile->size();
-}
-
-SftpOutgoingPacket &SftpUploadFile::initialPacket(SftpOutgoingPacket &packet)
-{
- state = OpenRequested;
- quint32 permissions = 0;
- const QFile::Permissions &qtPermissions = localFile->permissions();
- if (qtPermissions & QFile::ExeOther)
- permissions |= 1 << 0;
- if (qtPermissions & QFile::WriteOther)
- permissions |= 1 << 1;
- if (qtPermissions & QFile::ReadOther)
- permissions |= 1 << 2;
- if (qtPermissions & QFile::ExeGroup)
- permissions |= 1<< 3;
- if (qtPermissions & QFile::WriteGroup)
- permissions |= 1<< 4;
- if (qtPermissions & QFile::ReadGroup)
- permissions |= 1<< 5;
- if (qtPermissions & QFile::ExeOwner)
- permissions |= 1<< 6;
- if (qtPermissions & QFile::WriteOwner)
- permissions |= 1<< 7;
- if (qtPermissions & QFile::ReadOwner)
- permissions |= 1<< 8;
- return packet.generateOpenFileForWriting(remotePath, mode, permissions, jobId);
-}
-
-SftpUploadDir::~SftpUploadDir() {}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpoperation_p.h b/src/libs/ssh/sftpoperation_p.h
deleted file mode 100644
index 3ee703f666..0000000000
--- a/src/libs/ssh/sftpoperation_p.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sftpdefs.h"
-
-#include <QByteArray>
-#include <QList>
-#include <QMap>
-#include <QSharedPointer>
-
-QT_BEGIN_NAMESPACE
-class QFile;
-QT_END_NAMESPACE
-
-namespace QSsh {
-namespace Internal {
-
-class SftpOutgoingPacket;
-
-struct AbstractSftpOperation
-{
- typedef QSharedPointer<AbstractSftpOperation> Ptr;
- enum Type {
- StatFile, ListDir, MakeDir, RmDir, Rm, Rename, CreateLink, CreateFile, Download, UploadFile
- };
-
- AbstractSftpOperation(SftpJobId jobId);
- virtual ~AbstractSftpOperation();
- virtual Type type() const = 0;
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet) = 0;
-
- const SftpJobId jobId;
-
-private:
- AbstractSftpOperation(const AbstractSftpOperation &);
- AbstractSftpOperation &operator=(const AbstractSftpOperation &);
-};
-
-struct SftpUploadDir;
-
-struct SftpStatFile : public AbstractSftpOperation
-{
- typedef QSharedPointer<SftpStatFile> Ptr;
-
- SftpStatFile(SftpJobId jobId, const QString &path);
- virtual Type type() const { return StatFile; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QString path;
-};
-
-struct SftpMakeDir : public AbstractSftpOperation
-{
- typedef QSharedPointer<SftpMakeDir> Ptr;
-
- SftpMakeDir(SftpJobId jobId, const QString &path,
- const QSharedPointer<SftpUploadDir> &parentJob = QSharedPointer<SftpUploadDir>());
- virtual Type type() const { return MakeDir; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QSharedPointer<SftpUploadDir> parentJob;
- const QString remoteDir;
-};
-
-struct SftpRmDir : public AbstractSftpOperation
-{
- typedef QSharedPointer<SftpRmDir> Ptr;
-
- SftpRmDir(SftpJobId id, const QString &path);
- virtual Type type() const { return RmDir; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QString remoteDir;
-};
-
-struct SftpRm : public AbstractSftpOperation
-{
- typedef QSharedPointer<SftpRm> Ptr;
-
- SftpRm(SftpJobId jobId, const QString &path);
- virtual Type type() const { return Rm; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QString remoteFile;
-};
-
-struct SftpRename : public AbstractSftpOperation
-{
- typedef QSharedPointer<SftpRename> Ptr;
-
- SftpRename(SftpJobId jobId, const QString &oldPath, const QString &newPath);
- virtual Type type() const { return Rename; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QString oldPath;
- const QString newPath;
-};
-
-struct SftpCreateLink : public AbstractSftpOperation
-{
- typedef QSharedPointer<SftpCreateLink> Ptr;
-
- SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target);
- virtual Type type() const { return CreateLink; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QString filePath;
- const QString target;
-};
-
-
-struct AbstractSftpOperationWithHandle : public AbstractSftpOperation
-{
- typedef QSharedPointer<AbstractSftpOperationWithHandle> Ptr;
- enum State { Inactive, OpenRequested, Open, CloseRequested };
-
- AbstractSftpOperationWithHandle(SftpJobId jobId, const QString &remotePath);
- ~AbstractSftpOperationWithHandle();
-
- const QString remotePath;
- QByteArray remoteHandle;
- State state;
- bool hasError;
-};
-
-
-struct SftpListDir : public AbstractSftpOperationWithHandle
-{
- typedef QSharedPointer<SftpListDir> Ptr;
-
- SftpListDir(SftpJobId jobId, const QString &path);
- virtual Type type() const { return ListDir; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-};
-
-
-struct SftpCreateFile : public AbstractSftpOperationWithHandle
-{
- typedef QSharedPointer<SftpCreateFile> Ptr;
-
- SftpCreateFile(SftpJobId jobId, const QString &path, SftpOverwriteMode mode);
- virtual Type type() const { return CreateFile; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const SftpOverwriteMode mode;
-};
-
-struct AbstractSftpTransfer : public AbstractSftpOperationWithHandle
-{
- typedef QSharedPointer<AbstractSftpTransfer> Ptr;
-
- AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath,
- const QSharedPointer<QFile> &localFile);
- ~AbstractSftpTransfer();
- void calculateInFlightCount(quint32 chunkSize);
-
- static const int MaxInFlightCount;
-
- const QSharedPointer<QFile> localFile;
- quint64 fileSize;
- quint64 offset;
- int inFlightCount;
- bool statRequested;
-};
-
-struct SftpDownload : public AbstractSftpTransfer
-{
- typedef QSharedPointer<SftpDownload> Ptr;
- SftpDownload(SftpJobId jobId, const QString &remotePath,
- const QSharedPointer<QFile> &localFile);
- virtual Type type() const { return Download; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- QMap<quint32, quint64> offsets;
- SftpJobId eofId;
-};
-
-struct SftpUploadFile : public AbstractSftpTransfer
-{
- typedef QSharedPointer<SftpUploadFile> Ptr;
-
- SftpUploadFile(SftpJobId jobId, const QString &remotePath,
- const QSharedPointer<QFile> &localFile, SftpOverwriteMode mode,
- const QSharedPointer<SftpUploadDir> &parentJob = QSharedPointer<SftpUploadDir>());
- virtual Type type() const { return UploadFile; }
- virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
-
- const QSharedPointer<SftpUploadDir> parentJob;
- SftpOverwriteMode mode;
-};
-
-// Composite operation.
-struct SftpUploadDir
-{
- typedef QSharedPointer<SftpUploadDir> Ptr;
-
- struct Dir {
- Dir(const QString &l, const QString &r) : localDir(l), remoteDir(r) {}
- QString localDir;
- QString remoteDir;
- };
-
- SftpUploadDir(SftpJobId jobId) : jobId(jobId), hasError(false) {}
- ~SftpUploadDir();
-
- void setError()
- {
- hasError = true;
- uploadsInProgress.clear();
- mkdirsInProgress.clear();
- }
-
- const SftpJobId jobId;
- bool hasError;
- QList<SftpUploadFile::Ptr> uploadsInProgress;
- QMap<SftpMakeDir::Ptr, Dir> mkdirsInProgress;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpoutgoingpacket.cpp b/src/libs/ssh/sftpoutgoingpacket.cpp
deleted file mode 100644
index 69c3a544ac..0000000000
--- a/src/libs/ssh/sftpoutgoingpacket.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sftpoutgoingpacket_p.h"
-
-#include "sshlogging_p.h"
-#include "sshpacket_p.h"
-
-#include <QtEndian>
-
-#include <limits>
-
-namespace QSsh {
-namespace Internal {
-
-namespace {
- const quint32 DefaultAttributes = 0;
- const quint32 SSH_FXF_READ = 0x00000001;
- const quint32 SSH_FXF_WRITE = 0x00000002;
- const quint32 SSH_FXF_APPEND = 0x00000004;
- const quint32 SSH_FXF_CREAT = 0x00000008;
- const quint32 SSH_FXF_TRUNC = 0x00000010;
- const quint32 SSH_FXF_EXCL = 0x00000020;
-}
-
-SftpOutgoingPacket::SftpOutgoingPacket()
-{
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateInit(quint32 version)
-{
- return init(SSH_FXP_INIT, 0).appendInt(version).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateStat(const QString &path, quint32 requestId)
-{
- return init(SSH_FXP_LSTAT, requestId).appendString(path).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateOpenDir(const QString &path,
- quint32 requestId)
-{
- return init(SSH_FXP_OPENDIR, requestId).appendString(path).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateReadDir(const QByteArray &handle,
- quint32 requestId)
-{
- return init(SSH_FXP_READDIR, requestId).appendString(handle).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateCloseHandle(const QByteArray &handle,
- quint32 requestId)
-{
- return init(SSH_FXP_CLOSE, requestId).appendString(handle).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateMkDir(const QString &path,
- quint32 requestId)
-{
- return init(SSH_FXP_MKDIR, requestId).appendString(path)
- .appendInt(DefaultAttributes).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateRmDir(const QString &path,
- quint32 requestId)
-{
- return init(SSH_FXP_RMDIR, requestId).appendString(path).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateRm(const QString &path,
- quint32 requestId)
-{
- return init(SSH_FXP_REMOVE, requestId).appendString(path).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateRename(const QString &oldPath,
- const QString &newPath, quint32 requestId)
-{
- return init(SSH_FXP_RENAME, requestId).appendString(oldPath)
- .appendString(newPath).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForWriting(const QString &path,
- SftpOverwriteMode mode, quint32 permissions, quint32 requestId)
-{
- QList<quint32> attributes;
- if (permissions != DefaultPermissions)
- attributes << SSH_FILEXFER_ATTR_PERMISSIONS << permissions;
- else
- attributes << DefaultAttributes;
- return generateOpenFile(path, Write, mode, attributes, requestId);
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForReading(const QString &path,
- quint32 requestId)
-{
- // Note: Overwrite mode is irrelevant and will be ignored.
- return generateOpenFile(path, Read, SftpSkipExisting, QList<quint32>() << DefaultAttributes,
- requestId);
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateReadFile(const QByteArray &handle,
- quint64 offset, quint32 length, quint32 requestId)
-{
- return init(SSH_FXP_READ, requestId).appendString(handle).appendInt64(offset)
- .appendInt(length).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateFstat(const QByteArray &handle,
- quint32 requestId)
-{
- return init(SSH_FXP_FSTAT, requestId).appendString(handle).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateWriteFile(const QByteArray &handle,
- quint64 offset, const QByteArray &data, quint32 requestId)
-{
- return init(SSH_FXP_WRITE, requestId).appendString(handle)
- .appendInt64(offset).appendString(data).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateCreateLink(const QString &filePath,
- const QString &target, quint32 requestId)
-{
- return init(SSH_FXP_SYMLINK, requestId).appendString(filePath).appendString(target).finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFile(const QString &path,
- OpenType openType, SftpOverwriteMode mode, const QList<quint32> &attributes, quint32 requestId)
-{
- quint32 pFlags = 0;
- switch (openType) {
- case Read:
- pFlags = SSH_FXF_READ;
- break;
- case Write:
- pFlags = SSH_FXF_WRITE | SSH_FXF_CREAT;
- switch (mode) {
- case SftpOverwriteExisting: pFlags |= SSH_FXF_TRUNC; break;
- case SftpAppendToExisting: pFlags |= SSH_FXF_APPEND; break;
- case SftpSkipExisting: pFlags |= SSH_FXF_EXCL; break;
- }
- break;
- }
-
- init(SSH_FXP_OPEN, requestId).appendString(path).appendInt(pFlags);
- foreach (const quint32 attribute, attributes)
- appendInt(attribute);
- return finalize();
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::init(SftpPacketType type,
- quint32 requestId)
-{
- m_data.resize(TypeOffset + 1);
- m_data[TypeOffset] = type;
- if (type != SSH_FXP_INIT) {
- appendInt(requestId);
- qCDebug(sshLog, "Generating SFTP packet of type %d with request id %u", type, requestId);
- }
- return *this;
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::appendInt(quint32 val)
-{
- m_data.append(AbstractSshPacket::encodeInt(val));
- return *this;
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::appendInt64(quint64 value)
-{
- m_data.append(AbstractSshPacket::encodeInt(value));
- return *this;
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QString &string)
-{
- m_data.append(AbstractSshPacket::encodeString(string.toUtf8()));
- return *this;
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QByteArray &string)
-{
- m_data += AbstractSshPacket::encodeString(string);
- return *this;
-}
-
-SftpOutgoingPacket &SftpOutgoingPacket::finalize()
-{
- AbstractSshPacket::setLengthField(m_data);
- return *this;
-}
-
-const quint32 SftpOutgoingPacket::DefaultPermissions = std::numeric_limits<quint32>::max();
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpoutgoingpacket_p.h b/src/libs/ssh/sftpoutgoingpacket_p.h
deleted file mode 100644
index 0fcc67c151..0000000000
--- a/src/libs/ssh/sftpoutgoingpacket_p.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sftppacket_p.h"
-#include "sftpdefs.h"
-
-namespace QSsh {
-namespace Internal {
-
-class SftpOutgoingPacket : public AbstractSftpPacket
-{
-public:
- SftpOutgoingPacket();
- SftpOutgoingPacket &generateInit(quint32 version);
- SftpOutgoingPacket &generateStat(const QString &path, quint32 requestId);
- SftpOutgoingPacket &generateOpenDir(const QString &path, quint32 requestId);
- SftpOutgoingPacket &generateReadDir(const QByteArray &handle,
- quint32 requestId);
- SftpOutgoingPacket &generateCloseHandle(const QByteArray &handle,
- quint32 requestId);
- SftpOutgoingPacket &generateMkDir(const QString &path, quint32 requestId);
- SftpOutgoingPacket &generateRmDir(const QString &path, quint32 requestId);
- SftpOutgoingPacket &generateRm(const QString &path, quint32 requestId);
- SftpOutgoingPacket &generateRename(const QString &oldPath,
- const QString &newPath, quint32 requestId);
- SftpOutgoingPacket &generateOpenFileForWriting(const QString &path,
- SftpOverwriteMode mode, quint32 permissions, quint32 requestId);
- SftpOutgoingPacket &generateOpenFileForReading(const QString &path,
- quint32 requestId);
- SftpOutgoingPacket &generateReadFile(const QByteArray &handle,
- quint64 offset, quint32 length, quint32 requestId);
- SftpOutgoingPacket &generateFstat(const QByteArray &handle,
- quint32 requestId);
- SftpOutgoingPacket &generateWriteFile(const QByteArray &handle,
- quint64 offset, const QByteArray &data, quint32 requestId);
-
- // Note: OpenSSH's SFTP server has a bug that reverses the filePath and target
- // arguments, so this operation is not portable.
- SftpOutgoingPacket &generateCreateLink(const QString &filePath, const QString &target,
- quint32 requestId);
-
- static const quint32 DefaultPermissions;
-
-private:
- static QByteArray encodeString(const QString &string);
-
- enum OpenType { Read, Write };
- SftpOutgoingPacket &generateOpenFile(const QString &path, OpenType openType,
- SftpOverwriteMode mode, const QList<quint32> &attributes, quint32 requestId);
-
- SftpOutgoingPacket &init(SftpPacketType type, quint32 requestId);
- SftpOutgoingPacket &appendInt(quint32 value);
- SftpOutgoingPacket &appendInt64(quint64 value);
- SftpOutgoingPacket &appendString(const QString &string);
- SftpOutgoingPacket &appendString(const QByteArray &string);
- SftpOutgoingPacket &finalize();
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftppacket.cpp b/src/libs/ssh/sftppacket.cpp
deleted file mode 100644
index 4efaa35d7c..0000000000
--- a/src/libs/ssh/sftppacket.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sftppacket_p.h"
-
-#include "sshpacketparser_p.h"
-
-namespace QSsh {
-namespace Internal {
-
-const quint32 AbstractSftpPacket::MaxDataSize = 32000;
-const quint32 AbstractSftpPacket::MaxPacketSize = 34000;
-const int AbstractSftpPacket::TypeOffset = 4;
-const int AbstractSftpPacket::RequestIdOffset = TypeOffset + 1;
-const int AbstractSftpPacket::PayloadOffset = RequestIdOffset + 4;
-
-AbstractSftpPacket::AbstractSftpPacket()
-{
-}
-
-quint32 AbstractSftpPacket::requestId() const
-{
- return SshPacketParser::asUint32(m_data, RequestIdOffset);
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftppacket_p.h b/src/libs/ssh/sftppacket_p.h
deleted file mode 100644
index b99f7b36d6..0000000000
--- a/src/libs/ssh/sftppacket_p.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QByteArray>
-#include <QList>
-#include <QString>
-
-namespace QSsh {
-namespace Internal {
-
-enum SftpPacketType {
- SSH_FXP_INIT = 1,
- SSH_FXP_VERSION = 2,
- SSH_FXP_OPEN = 3,
- SSH_FXP_CLOSE = 4,
- SSH_FXP_READ = 5,
- SSH_FXP_WRITE = 6,
- SSH_FXP_LSTAT = 7,
- SSH_FXP_FSTAT = 8,
- SSH_FXP_SETSTAT = 9,
- SSH_FXP_FSETSTAT = 10,
- SSH_FXP_OPENDIR = 11,
- SSH_FXP_READDIR = 12,
- SSH_FXP_REMOVE = 13,
- SSH_FXP_MKDIR = 14,
- SSH_FXP_RMDIR = 15,
- SSH_FXP_REALPATH = 16,
- SSH_FXP_STAT = 17,
- SSH_FXP_RENAME = 18,
- SSH_FXP_READLINK = 19,
- SSH_FXP_SYMLINK = 20, // Removed from later protocol versions. Try not to use.
-
- SSH_FXP_STATUS = 101,
- SSH_FXP_HANDLE = 102,
- SSH_FXP_DATA = 103,
- SSH_FXP_NAME = 104,
- SSH_FXP_ATTRS = 105,
-
- SSH_FXP_EXTENDED = 200,
- SSH_FXP_EXTENDED_REPLY = 201
-};
-
-enum SftpStatusCode {
- SSH_FX_OK = 0,
- SSH_FX_EOF = 1,
- SSH_FX_NO_SUCH_FILE = 2,
- SSH_FX_PERMISSION_DENIED = 3,
- SSH_FX_FAILURE = 4,
- SSH_FX_BAD_MESSAGE = 5,
- SSH_FX_NO_CONNECTION = 6,
- SSH_FX_CONNECTION_LOST = 7,
- SSH_FX_OP_UNSUPPORTED = 8
-};
-
-enum SftpAttributeType {
- SSH_FILEXFER_ATTR_SIZE = 0x00000001,
- SSH_FILEXFER_ATTR_UIDGID = 0x00000002,
- SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004,
- SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008,
- SSH_FILEXFER_ATTR_EXTENDED = 0x80000000
-};
-
-class AbstractSftpPacket
-{
-public:
- AbstractSftpPacket();
- quint32 requestId() const;
- const QByteArray &rawData() const { return m_data; }
- SftpPacketType type() const { return static_cast<SftpPacketType>(m_data.at(TypeOffset)); }
-
- static const quint32 MaxDataSize; // "Pure" data size per read/writepacket.
- static const quint32 MaxPacketSize;
-
-protected:
- quint32 dataSize() const { return static_cast<quint32>(m_data.size()); }
-
- static const int TypeOffset;
- static const int RequestIdOffset;
- static const int PayloadOffset;
-
- QByteArray m_data;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sftpsession.cpp b/src/libs/ssh/sftpsession.cpp
new file mode 100644
index 0000000000..2ba5db778a
--- /dev/null
+++ b/src/libs/ssh/sftpsession.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "sftpsession.h"
+
+#include "sshlogging_p.h"
+#include "sshprocess_p.h"
+#include "sshsettings.h"
+
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+
+#include <QByteArrayList>
+#include <QFileInfo>
+#include <QQueue>
+#include <QTimer>
+
+using namespace Utils;
+
+namespace QSsh {
+using namespace Internal;
+
+enum class CommandType { Ls, Mkdir, Rmdir, Rm, Rename, Ln, Put, Get, None };
+
+struct Command
+{
+ Command() = default;
+ Command(CommandType t, const QStringList &p, SftpJobId id) : type(t), paths(p), jobId(id) {}
+ bool isValid() const { return type != CommandType::None; }
+
+ CommandType type = CommandType::None;
+ QStringList paths;
+ SftpJobId jobId = SftpInvalidJob;
+};
+
+struct SftpSession::SftpSessionPrivate
+{
+ SshProcess sftpProc;
+ QStringList connectionArgs;
+ QByteArray output;
+ QQueue<Command> pendingCommands;
+ Command activeCommand;
+ SftpJobId nextJobId = 1;
+ SftpSession::State state = SftpSession::State::Inactive;
+
+ QByteArray commandString(CommandType command) const
+ {
+ switch (command) {
+ case CommandType::Ls: return "ls -n";
+ case CommandType::Mkdir: return "mkdir";
+ case CommandType::Rmdir: return "rmdir";
+ case CommandType::Rm: return "rm";
+ case CommandType::Rename: return "rename";
+ case CommandType::Ln: return "ln -s";
+ case CommandType::Put: return "put";
+ case CommandType::Get: return "get";
+ default: QTC_ASSERT(false, return QByteArray());
+ }
+ }
+
+ SftpJobId queueCommand(CommandType command, const QStringList &paths)
+ {
+ const SftpJobId jobId = nextJobId++;
+ pendingCommands.enqueue(Command(command, paths, jobId));
+ runNextCommand();
+ return jobId;
+ }
+
+ void runNextCommand()
+ {
+ if (activeCommand.isValid())
+ return;
+ if (pendingCommands.empty())
+ return;
+ QTC_ASSERT(sftpProc.state() == QProcess::Running, return);
+ activeCommand = pendingCommands.dequeue();
+
+ // The second newline forces the prompt to appear after the command has finished.
+ sftpProc.write(commandString(activeCommand.type) + ' '
+ + QtcProcess::Arguments::createUnixArgs(activeCommand.paths)
+ .toString().toLocal8Bit() + "\n\n");
+ }
+};
+
+static QByteArray prompt() { return "sftp> "; }
+
+SftpSession::SftpSession(const QStringList &connectionArgs) : d(new SftpSessionPrivate)
+{
+ d->connectionArgs = connectionArgs;
+ connect(&d->sftpProc, &QProcess::started, [this] {
+ d->sftpProc.write("\n"); // Force initial prompt.
+ });
+ connect(&d->sftpProc, &QProcess::errorOccurred, [this](QProcess::ProcessError error) {
+ if (error == QProcess::FailedToStart) {
+ d->state = State::Inactive;
+ emit done(tr("sftp failed to start: %1").arg(d->sftpProc.errorString()));
+ }
+ });
+ connect(&d->sftpProc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), [this] {
+ d->state = State::Inactive;
+ if (d->sftpProc.exitStatus() != QProcess::NormalExit) {
+ emit done(tr("sftp crashed."));
+ return;
+ }
+ if (d->sftpProc.exitCode() != 0) {
+ emit done(QString::fromLocal8Bit(d->sftpProc.readAllStandardError()));
+ return;
+ }
+ emit done(QString());
+ });
+ connect(&d->sftpProc, &QProcess::readyReadStandardOutput, this, &SftpSession::handleStdout);
+}
+
+void SftpSession::doStart()
+{
+ if (d->state != State::Starting)
+ return;
+ const FileName sftpBinary = SshSettings::sftpFilePath();
+ if (!sftpBinary.exists()) {
+ d->state = State::Inactive;
+ emit done(tr("Cannot establish SFTP session: sftp binary \"%1\" does not exist.")
+ .arg(sftpBinary.toUserOutput()));
+ return;
+ }
+ d->activeCommand = Command();
+ const QStringList args = QStringList{"-q"} << d->connectionArgs;
+ qCDebug(sshLog) << "starting sftp session:" << sftpBinary.toUserOutput() << args;
+ d->sftpProc.start(sftpBinary.toString(), args);
+}
+
+void SftpSession::handleStdout()
+{
+ if (state() == State::Running && !d->activeCommand.isValid()) {
+ qCWarning(sshLog) << "ignoring unexpected sftp output:"
+ << d->sftpProc.readAllStandardOutput();
+ return;
+ }
+
+ d->output += d->sftpProc.readAllStandardOutput();
+ qCDebug(sshLog) << "accumulated sftp output:" << d->output;
+ const int firstPromptOffset = d->output.indexOf(prompt());
+ if (firstPromptOffset == -1)
+ return;
+ if (state() == State::Starting) {
+ d->state = State::Running;
+ d->output.clear();
+ d->sftpProc.readAllStandardError(); // The "connected" message goes to stderr.
+ emit started();
+ return;
+ }
+ const int secondPromptOffset = d->output.indexOf(prompt(), firstPromptOffset + prompt().size());
+ if (secondPromptOffset == -1)
+ return;
+ const Command command = d->activeCommand;
+ d->activeCommand = Command();
+ const QByteArray commandOutput = d->output.mid(
+ firstPromptOffset + prompt().size(),
+ secondPromptOffset - firstPromptOffset - prompt().size());
+ d->output = d->output.mid(secondPromptOffset + prompt().size());
+ if (command.type == CommandType::Ls)
+ handleLsOutput(command.jobId, commandOutput);
+ const QByteArray stdErr = d->sftpProc.readAllStandardError();
+ emit commandFinished(command.jobId, QString::fromLocal8Bit(stdErr));
+ d->runNextCommand();
+}
+
+static SftpFileType typeFromLsOutput(char c)
+{
+ if (c == '-')
+ return FileTypeRegular;
+ if (c == 'd')
+ return FileTypeDirectory;
+ return FileTypeOther;
+}
+
+static QFile::Permissions permissionsFromLsOutput(const QByteArray &output)
+{
+ QFile::Permissions perms;
+ if (output.at(0) == 'r')
+ perms |= QFile::ReadOwner;
+ if (output.at(1) == 'w')
+ perms |= QFile::WriteOwner;
+ if (output.at(2) == 'x')
+ perms |= QFile::ExeOwner;
+ if (output.at(3) == 'r')
+ perms |= QFile::ReadGroup;
+ if (output.at(4) == 'w')
+ perms |= QFile::WriteGroup;
+ if (output.at(5) == 'x')
+ perms |= QFile::ExeGroup;
+ if (output.at(6) == 'r')
+ perms |= QFile::ReadOther;
+ if (output.at(7) == 'w')
+ perms |= QFile::WriteOther;
+ if (output.at(8) == 'x')
+ perms |= QFile::ExeOther;
+ return perms;
+}
+
+void SftpSession::handleLsOutput(SftpJobId jobId, const QByteArray &output)
+{
+ QList<SftpFileInfo> allFileInfo;
+ for (const QByteArray &line : output.split('\n')) {
+ if (line.startsWith("ls") || line.isEmpty())
+ continue;
+ const QByteArrayList components = line.simplified().split(' ');
+ if (components.size() < 9) {
+ qCWarning(sshLog) << "Don't know how to parse sftp ls output:" << line;
+ continue;
+ }
+ const QByteArray typeAndPermissions = components.first();
+ if (typeAndPermissions.size() != 10) {
+ qCWarning(sshLog) << "Don't know how to parse sftp ls output:" << line;
+ continue;
+ }
+ SftpFileInfo fileInfo;
+ fileInfo.type = typeFromLsOutput(typeAndPermissions.at(0));
+ fileInfo.permissions = permissionsFromLsOutput(QByteArray::fromRawData(
+ typeAndPermissions.constData() + 1,
+ typeAndPermissions.size() - 1));
+ bool isNumber;
+ fileInfo.size = components.at(4).toULongLong(&isNumber);
+ if (!isNumber) {
+ qCWarning(sshLog) << "Don't know how to parse sftp ls output:" << line;
+ continue;
+ }
+ // TODO: This will not work for file names with weird whitespace combinations
+ fileInfo.name = QFileInfo(QString::fromUtf8(components.mid(8).join(' '))).fileName();
+ allFileInfo << fileInfo;
+ }
+ emit fileInfoAvailable(jobId, allFileInfo);
+}
+
+SftpSession::~SftpSession()
+{
+ quit();
+ delete d;
+}
+
+void SftpSession::start()
+{
+ QTC_ASSERT(d->state == State::Inactive, return);
+ d->state = State::Starting;
+ QTimer::singleShot(0, this, &SftpSession::doStart);
+}
+
+void SftpSession::quit()
+{
+ switch (state()) {
+ case State::Starting:
+ case State::Closing:
+ d->state = State::Closing;
+ d->sftpProc.kill();
+ break;
+ case State::Running:
+ d->state = State::Closing;
+ d->sftpProc.write("bye\n");
+ break;
+ case State::Inactive:
+ break;
+ }
+}
+
+SftpJobId SftpSession::ls(const QString &path)
+{
+ return d->queueCommand(CommandType::Ls, QStringList(path));
+}
+
+SftpJobId SftpSession::createDirectory(const QString &path)
+{
+ return d->queueCommand(CommandType::Mkdir, QStringList(path));
+}
+
+SftpJobId SftpSession::removeDirectory(const QString &path)
+{
+ return d->queueCommand(CommandType::Rmdir, QStringList(path));
+}
+
+SftpJobId SftpSession::removeFile(const QString &path)
+{
+ return d->queueCommand(CommandType::Rm, QStringList(path));
+}
+
+SftpJobId SftpSession::rename(const QString &oldPath, const QString &newPath)
+{
+ return d->queueCommand(CommandType::Rename, QStringList{oldPath, newPath});
+}
+
+SftpJobId SftpSession::createSoftLink(const QString &filePath, const QString &target)
+{
+ return d->queueCommand(CommandType::Ln, QStringList{filePath, target});
+}
+
+SftpJobId SftpSession::uploadFile(const QString &localFilePath, const QString &remoteFilePath)
+{
+ return d->queueCommand(CommandType::Put, QStringList{localFilePath, remoteFilePath});
+}
+
+SftpJobId SftpSession::downloadFile(const QString &remoteFilePath, const QString &localFilePath)
+{
+ return d->queueCommand(CommandType::Get, QStringList{remoteFilePath, localFilePath});
+}
+
+SftpSession::State SftpSession::state() const
+{
+ return d->state;
+}
+
+} // namespace QSsh
diff --git a/src/libs/ssh/sshtcpipforwardserver.h b/src/libs/ssh/sftpsession.h
index 2a0ed7e32b..89d0eec145 100644
--- a/src/libs/ssh/sshtcpipforwardserver.h
+++ b/src/libs/ssh/sftpsession.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,57 +25,49 @@
#pragma once
+#include "sftpdefs.h"
#include "ssh_global.h"
-#include "sshforwardedtcpiptunnel.h"
+
#include <QObject>
namespace QSsh {
+class SshConnection;
-namespace Internal {
-class SshChannelManager;
-class SshTcpIpForwardServerPrivate;
-class SshSendFacility;
-class SshConnectionPrivate;
-} // namespace Internal
-
-class QSSH_EXPORT SshTcpIpForwardServer : public QObject
+class QSSH_EXPORT SftpSession : public QObject
{
+ friend class SshConnection;
Q_OBJECT
- friend class Internal::SshChannelManager;
- friend class Internal::SshConnectionPrivate;
-
public:
- enum State {
- Inactive,
- Initializing,
- Listening,
- Closing
- };
+ ~SftpSession() override;
+ void start();
+ void quit();
- typedef QSharedPointer<SshTcpIpForwardServer> Ptr;
- ~SshTcpIpForwardServer();
+ SftpJobId ls(const QString &path);
+ SftpJobId createDirectory(const QString &path);
+ SftpJobId removeDirectory(const QString &path);
+ SftpJobId removeFile(const QString &path);
+ SftpJobId rename(const QString &oldPath, const QString &newPath);
+ SftpJobId createSoftLink(const QString &filePath, const QString &target);
+ SftpJobId uploadFile(const QString &localFilePath, const QString &remoteFilePath);
+ SftpJobId downloadFile(const QString &remoteFilePath, const QString &localFilePath);
- const QString &bindAddress() const;
- quint16 port() const;
+ enum class State { Inactive, Starting, Running, Closing };
State state() const;
- void initialize();
- void close();
-
- SshForwardedTcpIpTunnel::Ptr nextPendingConnection();
signals:
- void error(const QString &reason);
- void newConnection();
- void stateChanged(State state);
+ void started();
+ void done(const QString &error);
+ void commandFinished(SftpJobId job, const QString &error);
+ void fileInfoAvailable(SftpJobId job, const QList<SftpFileInfo> &fileInfoList);
private:
- SshTcpIpForwardServer(const QString &bindAddress, quint16 bindPort,
- Internal::SshSendFacility &sendFacility);
- void setListening(quint16 port);
- void setClosed();
- void setNewConnection(const SshForwardedTcpIpTunnel::Ptr &connection);
+ SftpSession(const QStringList &connectionArgs);
+ void doStart();
+ void handleStdout();
+ void handleLsOutput(SftpJobId jobId, const QByteArray &output);
- Internal::SshTcpIpForwardServerPrivate * const d;
+ struct SftpSessionPrivate;
+ SftpSessionPrivate * const d;
};
} // namespace QSsh
diff --git a/src/libs/ssh/sftptransfer.cpp b/src/libs/ssh/sftptransfer.cpp
new file mode 100644
index 0000000000..3bfc89713d
--- /dev/null
+++ b/src/libs/ssh/sftptransfer.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "sftptransfer.h"
+
+#include "sshprocess_p.h"
+#include "sshsettings.h"
+
+#include <QDir>
+#include <QFileInfo>
+#include <QStringList>
+#include <QTemporaryFile>
+#include <QTimer>
+
+#include <utils/algorithm.h>
+#include <utils/qtcprocess.h>
+
+using namespace Utils;
+
+namespace QSsh {
+
+struct SftpTransfer::SftpTransferPrivate
+{
+ Internal::SshProcess sftpProc;
+ FilesToTransfer files;
+ Internal::FileTransferType transferType;
+ FileTransferErrorHandling errorHandlingMode;
+ QStringList connectionArgs;
+ QTemporaryFile batchFile;
+
+ QStringList dirsToCreate() const
+ {
+ QStringList dirs;
+ for (const FileToTransfer &f : qAsConst(files)) {
+ QString parentDir = QFileInfo(f.targetFile).path();
+ while (true) {
+ if (dirs.contains(parentDir) || !parentDir.startsWith('/'))
+ break;
+ dirs << parentDir;
+ parentDir = QFileInfo(parentDir).path();
+ }
+ }
+ sort(dirs, [](const QString &d1, const QString &d2) {
+ if (d1 == "/" && d2 != "/")
+ return true;
+ return d1.count('/') < d2.count('/');
+ });
+ return dirs;
+ }
+ QByteArray transferCommand(bool link) const
+ {
+ QByteArray command;
+ switch (transferType) {
+ case Internal::FileTransferType::Upload:
+ command = link ? "ln -s" : "put";
+ break;
+ case Internal::FileTransferType::Download:
+ command = "get";
+ break;
+ }
+ if (errorHandlingMode == FileTransferErrorHandling::Ignore)
+ command.prepend('-');
+ return command;
+ }
+};
+
+SftpTransfer::~SftpTransfer()
+{
+ delete d;
+}
+
+void SftpTransfer::start()
+{
+ QTimer::singleShot(0, this, &SftpTransfer::doStart);
+}
+
+void SftpTransfer::stop()
+{
+ d->sftpProc.terminate();
+}
+
+SftpTransfer::SftpTransfer(const FilesToTransfer &files, Internal::FileTransferType type,
+ FileTransferErrorHandling errorHandlingMode,
+ const QStringList &connectionArgs)
+ : d(new SftpTransferPrivate)
+{
+ d->files = files;
+ d->transferType = type;
+ d->errorHandlingMode = errorHandlingMode;
+ d->connectionArgs = connectionArgs;
+ connect(&d->sftpProc, &QProcess::errorOccurred, [this](QProcess::ProcessError error) {
+ if (error == QProcess::FailedToStart)
+ emitError(tr("sftp failed to start: %1").arg(d->sftpProc.errorString()));
+ });
+ connect(&d->sftpProc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), [this] {
+ if (d->sftpProc.exitStatus() != QProcess::NormalExit) {
+ emitError(tr("sftp crashed."));
+ return;
+ }
+ if (d->sftpProc.exitCode() != 0) {
+ emitError(QString::fromLocal8Bit(d->sftpProc.readAllStandardError()));
+ return;
+ }
+ emit done(QString());
+ });
+ connect(&d->sftpProc, &QProcess::readyReadStandardOutput, [this] {
+ emit progress(QString::fromLocal8Bit(d->sftpProc.readAllStandardOutput()));
+ });
+}
+
+void SftpTransfer::doStart()
+{
+ const FileName sftpBinary = SshSettings::sftpFilePath();
+ if (!sftpBinary.exists()) {
+ emitError(tr("sftp binary \"%1\" does not exist.").arg(sftpBinary.toUserOutput()));
+ return;
+ }
+ if (!d->batchFile.isOpen() && !d->batchFile.open()) {
+ emitError(tr("Could not create temporary file: %1").arg(d->batchFile.errorString()));
+ return;
+ }
+ d->batchFile.resize(0);
+ for (const QString &dir : d->dirsToCreate()) {
+ switch (d->transferType) {
+ case Internal::FileTransferType::Upload:
+ d->batchFile.write("-mkdir " + QtcProcess::quoteArgUnix(dir).toLocal8Bit() + '\n');
+ break;
+ case Internal::FileTransferType::Download:
+ if (!QDir::root().mkdir(dir)) {
+ emitError(tr("Failed to create local directory \"%1\"")
+ .arg(QDir::toNativeSeparators(dir)));
+ return;
+ }
+ break;
+ }
+ }
+ for (const FileToTransfer &f : d->files) {
+ bool link = false;
+ if (d->transferType == Internal::FileTransferType::Upload) {
+ QFileInfo fi(f.sourceFile);
+ if (fi.isSymLink()) {
+ link = true;
+ const QString target = fi.dir().relativeFilePath(fi.symLinkTarget()); // see QTBUG-5817.
+ d->batchFile.write("-rm " + QtcProcess::quoteArgUnix(f.targetFile).toLocal8Bit()
+ + '\n');
+ }
+ }
+ d->batchFile.write(d->transferCommand(link) + ' '
+ + QtcProcess::quoteArgUnix(f.sourceFile).toLocal8Bit() + ' '
+ + QtcProcess::quoteArgUnix(f.targetFile).toLocal8Bit() + '\n');
+ }
+ d->batchFile.flush();
+ d->sftpProc.start(sftpBinary.toString(),
+ QStringList{"-b", d->batchFile.fileName()} << d->connectionArgs);
+ emit started();
+}
+
+void SftpTransfer::emitError(const QString &details)
+{
+ emit done(tr("File transfer failed: %1").arg(details));
+}
+
+} // namespace QSsh
diff --git a/src/libs/ssh/sshx11inforetriever_p.h b/src/libs/ssh/sftptransfer.h
index fc27672f4f..4c1c9cb636 100644
--- a/src/libs/ssh/sshx11inforetriever_p.h
+++ b/src/libs/ssh/sftptransfer.h
@@ -25,41 +25,38 @@
#pragma once
+#include "sftpdefs.h"
#include "ssh_global.h"
#include <QObject>
-#include <QString>
-
-QT_BEGIN_NAMESPACE
-class QByteArray;
-class QProcess;
-class QTemporaryFile;
-QT_END_NAMESPACE
namespace QSsh {
-namespace Internal {
-class X11DisplayInfo;
+class SshConnection;
-class QSSH_AUTOTEST_EXPORT SshX11InfoRetriever : public QObject
+class QSSH_EXPORT SftpTransfer : public QObject
{
+ friend class SshConnection;
Q_OBJECT
public:
- SshX11InfoRetriever(const QString &displayName, QObject *parent = nullptr);
+ ~SftpTransfer();
+
void start();
+ void stop();
signals:
- void failure(const QString &message);
- void success(const X11DisplayInfo &displayInfo);
+ void started();
+ void done(const QString &error);
+ void progress(const QString &output);
private:
- void emitFailure(const QString &reason);
-
- const QString m_displayName;
- QProcess * const m_xauthProc;
- QTemporaryFile * const m_xauthFile;
-
- enum class State { Inactive, RunningGenerate, RunningList } m_state = State::Inactive;
+ SftpTransfer(const FilesToTransfer &files, Internal::FileTransferType type,
+ FileTransferErrorHandling errorHandlingMode,
+ const QStringList &connectionArgs);
+ void doStart();
+ void emitError(const QString &details);
+
+ struct SftpTransferPrivate;
+ SftpTransferPrivate * const d;
};
-} // namespace Internal
} // namespace QSsh
diff --git a/src/libs/ssh/ssh.pro b/src/libs/ssh/ssh.pro
index 26f8a2ab54..2dc628c49e 100644
--- a/src/libs/ssh/ssh.pro
+++ b/src/libs/ssh/ssh.pro
@@ -3,100 +3,35 @@ DEFINES += QTCSSH_LIBRARY
include(../../qtcreatorlibrary.pri)
-SOURCES = $$PWD/sshsendfacility.cpp \
- $$PWD/sshremoteprocess.cpp \
- $$PWD/sshpacketparser.cpp \
- $$PWD/sshpacket.cpp \
- $$PWD/sshoutgoingpacket.cpp \
- $$PWD/sshkeygenerator.cpp \
- $$PWD/sshkeyexchange.cpp \
- $$PWD/sshincomingpacket.cpp \
- $$PWD/sshcryptofacility.cpp \
- $$PWD/sshconnection.cpp \
- $$PWD/sshchannelmanager.cpp \
- $$PWD/sshchannel.cpp \
- $$PWD/sshcapabilities.cpp \
- $$PWD/sftppacket.cpp \
- $$PWD/sftpoutgoingpacket.cpp \
- $$PWD/sftpoperation.cpp \
- $$PWD/sftpincomingpacket.cpp \
- $$PWD/sftpdefs.cpp \
- $$PWD/sftpchannel.cpp \
- $$PWD/sshremoteprocessrunner.cpp \
- $$PWD/sshconnectionmanager.cpp \
- $$PWD/sshkeypasswordretriever.cpp \
- $$PWD/sftpfilesystemmodel.cpp \
- $$PWD/sshkeycreationdialog.cpp \
- $$PWD/sshdirecttcpiptunnel.cpp \
- $$PWD/sshlogging.cpp \
- $$PWD/sshhostkeydatabase.cpp \
- $$PWD/sshtcpipforwardserver.cpp \
- $$PWD/sshtcpiptunnel.cpp \
- $$PWD/sshforwardedtcpiptunnel.cpp \
- $$PWD/sshagent.cpp \
- $$PWD/opensshkeyfilereader.cpp \
- $$PWD/sshx11channel.cpp \
- $$PWD/sshx11inforetriever.cpp
+SOURCES = \
+ sftpdefs.cpp \
+ sftpfilesystemmodel.cpp \
+ sftpsession.cpp \
+ sftptransfer.cpp \
+ sshconnection.cpp \
+ sshconnectionmanager.cpp \
+ sshkeycreationdialog.cpp \
+ sshlogging.cpp \
+ sshprocess.cpp \
+ sshremoteprocess.cpp \
+ sshremoteprocessrunner.cpp \
+ sshsettings.cpp
-HEADERS = $$PWD/sshsendfacility_p.h \
- $$PWD/sshremoteprocess.h \
- $$PWD/sshremoteprocess_p.h \
- $$PWD/sshpacketparser_p.h \
- $$PWD/sshpacket_p.h \
- $$PWD/sshoutgoingpacket_p.h \
- $$PWD/sshkeygenerator.h \
- $$PWD/sshkeyexchange_p.h \
- $$PWD/sshincomingpacket_p.h \
- $$PWD/sshexception_p.h \
- $$PWD/ssherrors.h \
- $$PWD/sshcryptofacility_p.h \
- $$PWD/sshconnection.h \
- $$PWD/sshconnection_p.h \
- $$PWD/sshchannelmanager_p.h \
- $$PWD/sshchannel_p.h \
- $$PWD/sshcapabilities_p.h \
- $$PWD/sshbotanconversions_p.h \
- $$PWD/sftppacket_p.h \
- $$PWD/sftpoutgoingpacket_p.h \
- $$PWD/sftpoperation_p.h \
- $$PWD/sftpincomingpacket_p.h \
- $$PWD/sftpdefs.h \
- $$PWD/sftpchannel.h \
- $$PWD/sftpchannel_p.h \
- $$PWD/sshremoteprocessrunner.h \
- $$PWD/sshconnectionmanager.h \
- $$PWD/sshpseudoterminal.h \
- $$PWD/sshkeypasswordretriever_p.h \
- $$PWD/sftpfilesystemmodel.h \
- $$PWD/sshkeycreationdialog.h \
- $$PWD/ssh_global.h \
- $$PWD/sshdirecttcpiptunnel_p.h \
- $$PWD/sshdirecttcpiptunnel.h \
- $$PWD/sshlogging_p.h \
- $$PWD/sshhostkeydatabase.h \
- $$PWD/sshtcpipforwardserver.h \
- $$PWD/sshtcpipforwardserver_p.h \
- $$PWD/sshtcpiptunnel_p.h \
- $$PWD/sshforwardedtcpiptunnel.h \
- $$PWD/sshforwardedtcpiptunnel_p.h \
- $$PWD/sshagent_p.h \
- $$PWD/opensshkeyfilereader_p.h \
- $$PWD/sshx11channel_p.h \
- $$PWD/sshx11displayinfo_p.h \
- $$PWD/sshx11inforetriever_p.h
+HEADERS = \
+ sftpdefs.h \
+ sftpfilesystemmodel.h \
+ sftpsession.h \
+ sftptransfer.h \
+ sshconnection.h \
+ sshconnectionmanager.h \
+ sshkeycreationdialog.h \
+ sshlogging_p.h \
+ sshprocess_p.h \
+ sshremoteprocess.h \
+ sshremoteprocessrunner.h \
+ sshsettings.h \
+ ssh_global.h
FORMS = $$PWD/sshkeycreationdialog.ui
RESOURCES += $$PWD/ssh.qrc
-
-include(../botan/botan.pri)
-use_system_botan {
- CONFIG += link_pkgconfig
- PKGCONFIG += botan-2
-} else {
- BOTAN_BUILD_DIR = $$OUT_PWD/../botan/$$BOTAN_BUILD_DIR
- INCLUDEPATH += $$BOTAN_BUILD_DIR/build/include
- LIBS += $$BOTAN_BUILD_DIR/$$BOTAN_FULL_NAME
- win32: LIBS += -ladvapi32 -luser32 -lws2_32
-}
-msvc:QMAKE_CXXFLAGS += /wd4250
diff --git a/src/libs/ssh/ssh.qbs b/src/libs/ssh/ssh.qbs
index 27b3368d0e..4999d5da26 100644
--- a/src/libs/ssh/ssh.qbs
+++ b/src/libs/ssh/ssh.qbs
@@ -1,5 +1,4 @@
import qbs 1.0
-import qbs.Environment
Project {
name: "QtcSsh"
@@ -8,120 +7,40 @@ Project {
QtcLibrary {
cpp.defines: base.concat("QTCSSH_LIBRARY")
- cpp.includePaths: botanIncludes
- cpp.dynamicLibraries: botanLibs
cpp.enableExceptions: true
- Properties {
- condition: qbs.toolchain.contains("msvc")
- cpp.cxxFlags: base.concat("/wd4250");
- }
-
Depends { name: "Qt"; submodules: ["widgets", "network" ] }
- Depends { name: "Botan"; condition: !qtc.useSystemBotan }
+ Depends { name: "Utils" }
files: [
- "opensshkeyfilereader.cpp",
- "opensshkeyfilereader_p.h",
- "sftpchannel.h",
- "sftpchannel_p.h",
- "sftpchannel.cpp",
"sftpdefs.cpp",
"sftpdefs.h",
"sftpfilesystemmodel.cpp",
"sftpfilesystemmodel.h",
- "sftpincomingpacket.cpp",
- "sftpincomingpacket_p.h",
- "sftpoperation.cpp",
- "sftpoperation_p.h",
- "sftpoutgoingpacket.cpp",
- "sftpoutgoingpacket_p.h",
- "sftppacket.cpp",
- "sftppacket_p.h",
+ "sftpsession.cpp",
+ "sftpsession.h",
+ "sftptransfer.cpp",
+ "sftptransfer.h",
"ssh.qrc",
- "sshagent.cpp",
- "sshagent_p.h",
- "sshbotanconversions_p.h",
- "sshcapabilities_p.h",
- "sshcapabilities.cpp",
- "sshchannel.cpp",
- "sshchannel_p.h",
- "sshchannelmanager.cpp",
- "sshchannelmanager_p.h",
"sshconnection.h",
- "sshconnection_p.h",
"sshconnection.cpp",
"sshconnectionmanager.cpp",
"sshconnectionmanager.h",
- "sshcryptofacility.cpp",
- "sshcryptofacility_p.h",
- "sshdirecttcpiptunnel.h",
- "sshdirecttcpiptunnel_p.h",
- "sshdirecttcpiptunnel.cpp",
- "ssherrors.h",
- "sshexception_p.h",
- "sshforwardedtcpiptunnel.cpp",
- "sshforwardedtcpiptunnel.h",
- "sshforwardedtcpiptunnel_p.h",
- "sshhostkeydatabase.cpp",
- "sshhostkeydatabase.h",
- "sshincomingpacket_p.h",
- "sshincomingpacket.cpp",
"sshkeycreationdialog.cpp",
"sshkeycreationdialog.h",
"sshkeycreationdialog.ui",
- "sshkeyexchange.cpp",
- "sshkeyexchange_p.h",
- "sshkeygenerator.cpp",
- "sshkeygenerator.h",
- "sshkeypasswordretriever.cpp",
- "sshkeypasswordretriever_p.h",
"sshlogging.cpp",
"sshlogging_p.h",
- "sshoutgoingpacket.cpp",
- "sshoutgoingpacket_p.h",
- "sshpacket.cpp",
- "sshpacket_p.h",
- "sshpacketparser.cpp",
- "sshpacketparser_p.h",
- "sshpseudoterminal.h",
+ "sshprocess.cpp",
+ "sshprocess_p.h",
"sshremoteprocess.cpp",
"sshremoteprocess.h",
- "sshremoteprocess_p.h",
"sshremoteprocessrunner.cpp",
"sshremoteprocessrunner.h",
- "sshsendfacility.cpp",
- "sshsendfacility_p.h",
- "sshtcpipforwardserver.cpp",
- "sshtcpipforwardserver.h",
- "sshtcpipforwardserver_p.h",
- "sshtcpiptunnel.cpp",
- "sshtcpiptunnel_p.h",
- "sshx11channel.cpp",
- "sshx11channel_p.h",
- "sshx11displayinfo_p.h",
- "sshx11inforetriever.cpp",
- "sshx11inforetriever_p.h",
+ "sshsettings.cpp",
+ "sshsettings.h",
]
- property var botanIncludes: qtc.useSystemBotan ? ["/usr/include/botan-2"] : []
- property var botanLibs: {
- var result = [];
- if (qtc.useSystemBotan)
- result.push("botan-2")
- if (qbs.targetOS.contains("windows"))
- result.push("advapi32", "user32", "ws2_32")
- else if (qbs.targetOS.contains("linux"))
- result.push("rt", "dl");
- else if (qbs.targetOS.contains("macos"))
- result.push("dl");
- else if (qbs.targetOS.contains("unix"))
- result.push("rt");
- return result
- }
-
- Export {
- Depends { name: "Qt"; submodules: ["widgets", "network"] }
- }
+ Export { Depends { name: "Qt.network" } }
}
}
diff --git a/src/libs/ssh/ssh_dependencies.pri b/src/libs/ssh/ssh_dependencies.pri
index ccd896a82c..edca1c112c 100644
--- a/src/libs/ssh/ssh_dependencies.pri
+++ b/src/libs/ssh/ssh_dependencies.pri
@@ -1 +1,2 @@
QTC_LIB_NAME = QtcSsh
+QTC_LIB_DEPENDS += utils
diff --git a/src/libs/ssh/ssh_global.h b/src/libs/ssh/ssh_global.h
index 3941ffbfcd..437fb67f14 100644
--- a/src/libs/ssh/ssh_global.h
+++ b/src/libs/ssh/ssh_global.h
@@ -38,8 +38,3 @@
#else
# define QSSH_AUTOTEST_EXPORT
#endif
-
-#define QSSH_PRINT_WARNING qWarning("Soft assert at %s:%d", __FILE__, __LINE__)
-#define QSSH_ASSERT(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; } } while (false)
-#define QSSH_ASSERT_AND_RETURN(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; return; } } while (false)
-#define QSSH_ASSERT_AND_RETURN_VALUE(cond, value) do { if (!(cond)) { QSSH_PRINT_WARNING; return value; } } while (false)
diff --git a/src/libs/ssh/sshagent.cpp b/src/libs/ssh/sshagent.cpp
deleted file mode 100644
index 4e581fac0a..0000000000
--- a/src/libs/ssh/sshagent.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-#include "sshagent_p.h"
-
-#include "sshlogging_p.h"
-#include "sshpacket_p.h"
-#include "sshpacketparser_p.h"
-#include "ssh_global.h"
-
-#include <QTimer>
-#include <QtEndian>
-
-#include <algorithm>
-
-namespace QSsh {
-namespace Internal {
-
-// https://github.com/openssh/openssh-portable/blob/V_7_2/PROTOCOL.agent
-enum PacketType {
- SSH_AGENT_FAILURE = 5,
- SSH2_AGENTC_REQUEST_IDENTITIES = 11,
- SSH2_AGENTC_SIGN_REQUEST = 13,
- SSH2_AGENT_IDENTITIES_ANSWER = 12,
- SSH2_AGENT_SIGN_RESPONSE = 14,
-};
-
-// TODO: Remove once we require 5.7, where the endianness functions have a sane input type.
-template<typename T> static T fromBigEndian(const QByteArray &ba)
-{
- return qFromBigEndian<T>(reinterpret_cast<const uchar *>(ba.constData()));
-}
-
-void SshAgent::refreshKeysImpl()
-{
- if (state() != Connected)
- return;
- const auto keysRequestIt = std::find_if(m_pendingRequests.constBegin(),
- m_pendingRequests.constEnd(), [](const Request &r) { return r.isKeysRequest(); });
- if (keysRequestIt != m_pendingRequests.constEnd()) {
- qCDebug(sshLog) << "keys request already pending, not adding another one";
- return;
- }
- qCDebug(sshLog) << "queueing keys request";
- m_pendingRequests << Request();
- sendNextRequest();
-}
-
-void SshAgent::requestSignatureImpl(const QByteArray &key, uint token)
-{
- if (state() != Connected)
- return;
- const QByteArray data = m_dataToSign.take(qMakePair(key, token));
- QSSH_ASSERT(!data.isEmpty());
- qCDebug(sshLog) << "queueing signature request";
- m_pendingRequests.enqueue(Request(key, data, token));
- sendNextRequest();
-}
-
-void SshAgent::sendNextRequest()
-{
- if (m_pendingRequests.isEmpty())
- return;
- if (m_outgoingPacket.isComplete())
- return;
- if (hasError())
- return;
- const Request &request = m_pendingRequests.head();
- m_outgoingPacket = request.isKeysRequest() ? generateKeysPacket() : generateSigPacket(request);
- sendPacket();
-}
-
-SshAgent::Packet SshAgent::generateKeysPacket()
-{
- qCDebug(sshLog) << "requesting keys from agent";
- Packet p;
- p.size = 1;
- p.data += char(SSH2_AGENTC_REQUEST_IDENTITIES);
- return p;
-}
-
-SshAgent::Packet SshAgent::generateSigPacket(const SshAgent::Request &request)
-{
- qCDebug(sshLog) << "requesting signature from agent for key" << request.key << "and token"
- << request.token;
- Packet p;
- p.data += char(SSH2_AGENTC_SIGN_REQUEST);
- p.data += AbstractSshPacket::encodeString(request.key);
- p.data += AbstractSshPacket::encodeString(request.dataToSign);
- p.data += AbstractSshPacket::encodeInt(quint32(0));
- p.size = p.data.count();
- return p;
-}
-
-SshAgent::~SshAgent()
-{
- m_agentSocket.disconnect(this);
-}
-
-void SshAgent::storeDataToSign(const QByteArray &key, const QByteArray &data, uint token)
-{
- instance().m_dataToSign.insert(qMakePair(key, token), data);
-}
-
-void SshAgent::removeDataToSign(const QByteArray &key, uint token)
-{
- instance().m_dataToSign.remove(qMakePair(key, token));
-}
-
-SshAgent &QSsh::Internal::SshAgent::instance()
-{
- static SshAgent agent;
- return agent;
-}
-
-SshAgent::SshAgent()
-{
- connect(&m_agentSocket, &QLocalSocket::connected, this, &SshAgent::handleConnected);
- connect(&m_agentSocket, &QLocalSocket::disconnected, this, &SshAgent::handleDisconnected);
- connect(&m_agentSocket,
- static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error),
- this, &SshAgent::handleSocketError);
- connect(&m_agentSocket, &QLocalSocket::readyRead, this, &SshAgent::handleIncomingData);
- QTimer::singleShot(0, this, &SshAgent::connectToServer);
-}
-
-void SshAgent::connectToServer()
-{
- const QByteArray serverAddress = qgetenv("SSH_AUTH_SOCK");
- if (serverAddress.isEmpty()) {
- qCDebug(sshLog) << "agent failure: socket address unknown";
- m_error = tr("Cannot connect to ssh-agent: SSH_AUTH_SOCK is not set.");
- emit errorOccurred();
- return;
- }
- qCDebug(sshLog) << "connecting to ssh-agent socket" << serverAddress;
- m_state = Connecting;
- m_agentSocket.connectToServer(QString::fromLocal8Bit(serverAddress));
-}
-
-void SshAgent::handleConnected()
-{
- m_state = Connected;
- qCDebug(sshLog) << "connection to ssh-agent established";
- refreshKeys();
-}
-
-void SshAgent::handleDisconnected()
-{
- qCDebug(sshLog) << "lost connection to ssh-agent";
- m_error = tr("Lost connection to ssh-agent for unknown reason.");
- setDisconnected();
-}
-
-void SshAgent::handleSocketError()
-{
- qCDebug(sshLog) << "agent socket error" << m_agentSocket.error();
- m_error = m_agentSocket.errorString();
- setDisconnected();
-}
-
-void SshAgent::handleIncomingData()
-{
- qCDebug(sshLog) << "getting data from agent";
- m_incomingData += m_agentSocket.readAll();
- while (!hasError() && !m_incomingData.isEmpty()) {
- if (m_incomingPacket.size == 0) {
- if (m_incomingData.count() < int(sizeof m_incomingPacket.size))
- break;
- m_incomingPacket.size = fromBigEndian<quint32>(m_incomingData);
- m_incomingData.remove(0, sizeof m_incomingPacket.size);
- }
- const int bytesToTake = qMin<quint32>(m_incomingPacket.size - m_incomingPacket.data.count(),
- m_incomingData.count());
- m_incomingPacket.data += m_incomingData.left(bytesToTake);
- m_incomingData.remove(0, bytesToTake);
- if (m_incomingPacket.isComplete())
- handleIncomingPacket();
- else
- break;
- }
-}
-
-void SshAgent::handleIncomingPacket()
-{
- try {
- qCDebug(sshLog) << "received packet from agent:" << m_incomingPacket.data.toHex();
- const char messageType = m_incomingPacket.data.at(0);
- switch (messageType) {
- case SSH2_AGENT_IDENTITIES_ANSWER:
- handleIdentitiesPacket();
- break;
- case SSH2_AGENT_SIGN_RESPONSE:
- handleSignaturePacket();
- break;
- case SSH_AGENT_FAILURE:
- if (m_pendingRequests.isEmpty()) {
- qCWarning(sshLog) << "unexpected failure message from agent";
- } else {
- const Request request = m_pendingRequests.dequeue();
- if (request.isSignatureRequest()) {
- qCWarning(sshLog) << "agent failed to sign message for key"
- << request.key.toHex();
- emit signatureAvailable(request.key, QByteArray(), request.token);
- } else {
- qCWarning(sshLog) << "agent failed to retrieve key list";
- if (m_keys.isEmpty()) {
- m_error = tr("ssh-agent failed to retrieve keys.");
- setDisconnected();
- }
- }
- }
- break;
- default:
- qCWarning(sshLog) << "unexpected message type from agent:" << messageType;
- }
- } catch (const SshPacketParseException &) {
- qCWarning(sshLog()) << "received malformed packet from agent";
- handleProtocolError();
- }
- m_incomingPacket.invalidate();
- m_incomingPacket.size = 0;
- m_outgoingPacket.invalidate();
- sendNextRequest();
-}
-
-void SshAgent::handleIdentitiesPacket()
-{
- qCDebug(sshLog) << "got keys packet from agent";
- if (m_pendingRequests.isEmpty() || !m_pendingRequests.dequeue().isKeysRequest()) {
- qCDebug(sshLog) << "packet was not requested";
- handleProtocolError();
- return;
- }
- quint32 offset = 1;
- const auto keyCount = SshPacketParser::asUint32(m_incomingPacket.data, &offset);
- qCDebug(sshLog) << "packet contains" << keyCount << "keys";
- QList<QByteArray> newKeys;
- for (quint32 i = 0; i < keyCount; ++i) {
- const QByteArray key = SshPacketParser::asString(m_incomingPacket.data, &offset);
- quint32 keyOffset = 0;
- const QByteArray algoName = SshPacketParser::asString(key, &keyOffset);
- SshPacketParser::asString(key, &keyOffset); // rest of key blob
- SshPacketParser::asString(m_incomingPacket.data, &offset); // comment
- qCDebug(sshLog) << "adding key of type" << algoName;
- newKeys << key;
- }
-
- m_keys = newKeys;
- emit keysUpdated();
-}
-
-void SshAgent::handleSignaturePacket()
-{
- qCDebug(sshLog) << "got signature packet from agent";
- if (m_pendingRequests.isEmpty()) {
- qCDebug(sshLog) << "signature packet was not requested";
- handleProtocolError();
- return;
- }
- const Request request = m_pendingRequests.dequeue();
- if (!request.isSignatureRequest()) {
- qCDebug(sshLog) << "signature packet was not requested";
- handleProtocolError();
- return;
- }
- const QByteArray signature = SshPacketParser::asString(m_incomingPacket.data, 1);
- qCDebug(sshLog) << "signature for key" << request.key.toHex() << "is" << signature.toHex();
- emit signatureAvailable(request.key, signature, request.token);
-}
-
-void SshAgent::handleProtocolError()
-{
- m_error = tr("Protocol error when talking to ssh-agent.");
- setDisconnected();
-}
-
-void SshAgent::setDisconnected()
-{
- m_state = Unconnected;
- m_agentSocket.disconnect(this);
- emit errorOccurred();
-}
-
-void SshAgent::sendPacket()
-{
- const quint32 sizeMsb = qToBigEndian(m_outgoingPacket.size);
- m_agentSocket.write(reinterpret_cast<const char *>(&sizeMsb), sizeof sizeMsb);
- m_agentSocket.write(m_outgoingPacket.data);
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshagent_p.h b/src/libs/ssh/sshagent_p.h
deleted file mode 100644
index f30867b934..0000000000
--- a/src/libs/ssh/sshagent_p.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QByteArray>
-#include <QHash>
-#include <QList>
-#include <QLocalSocket>
-#include <QObject>
-#include <QPair>
-#include <QQueue>
-#include <QString>
-
-namespace QSsh {
-namespace Internal {
-
-class SshAgent : public QObject
-{
- Q_OBJECT
-public:
- enum State { Unconnected, Connecting, Connected, };
-
- ~SshAgent();
- static State state() { return instance().m_state; }
- static bool hasError() { return !instance().m_error.isEmpty(); }
- static QString errorString() { return instance().m_error; }
- static QList<QByteArray> publicKeys() { return instance().m_keys; }
-
- static void refreshKeys() { instance().refreshKeysImpl(); }
- static void storeDataToSign(const QByteArray &key, const QByteArray &data, uint token);
- static void removeDataToSign(const QByteArray &key, uint token);
- static void requestSignature(const QByteArray &key, uint token) {
- instance().requestSignatureImpl(key, token);
- }
-
- static SshAgent &instance();
-
-signals:
- void errorOccurred();
- void keysUpdated();
-
- // Empty signature means signing failure.
- void signatureAvailable(const QByteArray &key, const QByteArray &signature, uint token);
-
-private:
- struct Request {
- Request() { }
- Request(const QByteArray &k, const QByteArray &d, uint t)
- : key(k), dataToSign(d), token(t) { }
-
- bool isKeysRequest() const { return !isSignatureRequest(); }
- bool isSignatureRequest() const { return !key.isEmpty(); }
-
- QByteArray key;
- QByteArray dataToSign;
- uint token = 0;
- };
-
- struct Packet {
- bool isComplete() const { return size != 0 && int(size) == data.count(); }
- void invalidate() { size = 0; data.clear(); }
-
- quint32 size = 0;
- QByteArray data;
- };
-
- SshAgent();
- void connectToServer();
- void refreshKeysImpl();
- void requestSignatureImpl(const QByteArray &key, uint token);
-
- void sendNextRequest();
- Packet generateKeysPacket();
- Packet generateSigPacket(const Request &request);
-
- void handleConnected();
- void handleDisconnected();
- void handleSocketError();
- void handleIncomingData();
- void handleIncomingPacket();
- void handleIdentitiesPacket();
- void handleSignaturePacket();
-
- void handleProtocolError();
- void setDisconnected();
-
- void sendPacket();
-
- State m_state = Unconnected;
- QString m_error;
- QList<QByteArray> m_keys;
- QHash<QPair<QByteArray, uint>, QByteArray> m_dataToSign;
- QLocalSocket m_agentSocket;
- QByteArray m_incomingData;
- Packet m_incomingPacket;
- Packet m_outgoingPacket;
-
- QQueue<Request> m_pendingRequests;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshbotanconversions_p.h b/src/libs/ssh/sshbotanconversions_p.h
deleted file mode 100644
index 335a02323c..0000000000
--- a/src/libs/ssh/sshbotanconversions_p.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshcapabilities_p.h"
-#include "sshexception_p.h"
-
-#include <botan/secmem.h>
-#include <botan/types.h>
-
-namespace QSsh {
-namespace Internal {
-
-inline const Botan::byte *convertByteArray(const QByteArray &a)
-{
- return reinterpret_cast<const Botan::byte *>(a.constData());
-}
-
-inline Botan::byte *convertByteArray(QByteArray &a)
-{
- return reinterpret_cast<Botan::byte *>(a.data());
-}
-
-inline QByteArray convertByteArray(const Botan::SecureVector<Botan::byte> &v)
-{
- return QByteArray(reinterpret_cast<const char *>(&v.front()), static_cast<int>(v.size()));
-}
-
-inline QByteArray convertByteArray(const std::vector<std::uint8_t> &v)
-{
- return QByteArray(reinterpret_cast<const char *>(&v.front()), static_cast<int>(v.size()));
-}
-
-inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName)
-{
- if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1)
- return "modp/ietf/1024";
- if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1)
- return "modp/ietf/2048";
- if (rfcAlgoName == SshCapabilities::EcdhNistp256)
- return "secp256r1";
- if (rfcAlgoName == SshCapabilities::EcdhNistp384)
- return "secp384r1";
- if (rfcAlgoName == SshCapabilities::EcdhNistp521)
- return "secp521r1";
- throw SshClientException(SshInternalError, SSH_TR("Unexpected key exchange algorithm \"%1\"")
- .arg(QString::fromLatin1(rfcAlgoName)));
-}
-
-inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
-{
- if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc
- || rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) {
- return "AES-128";
- }
- if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc
- || rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) {
- return "TripleDES";
- }
- if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) {
- return "AES-192";
- }
- if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) {
- return "AES-256";
- }
- throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
- .arg(QString::fromLatin1(rfcAlgoName)));
-}
-
-inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName)
-{
- if (rfcAlgoName == SshCapabilities::PubKeyDss)
- return "EMSA1(SHA-1)";
- if (rfcAlgoName == SshCapabilities::PubKeyRsa)
- return "EMSA3(SHA-1)";
- if (rfcAlgoName == SshCapabilities::PubKeyEcdsa256)
- return "EMSA1(SHA-256)";
- if (rfcAlgoName == SshCapabilities::PubKeyEcdsa384)
- return "EMSA1(SHA-384)";
- if (rfcAlgoName == SshCapabilities::PubKeyEcdsa521)
- return "EMSA1(SHA-512)";
- throw SshClientException(SshInternalError, SSH_TR("Unexpected host key algorithm \"%1\"")
- .arg(QString::fromLatin1(rfcAlgoName)));
-}
-
-inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName)
-{
- if (rfcAlgoName == SshCapabilities::HMacSha1)
- return "SHA-1";
- if (rfcAlgoName == SshCapabilities::HMacSha256)
- return "SHA-256";
- if (rfcAlgoName == SshCapabilities::HMacSha384)
- return "SHA-384";
- if (rfcAlgoName == SshCapabilities::HMacSha512)
- return "SHA-512";
- throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
- .arg(QString::fromLatin1(rfcAlgoName)));
-}
-
-inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName)
-{
- if (rfcAlgoName == SshCapabilities::HMacSha1)
- return 20;
- if (rfcAlgoName == SshCapabilities::HMacSha256)
- return 32;
- if (rfcAlgoName == SshCapabilities::HMacSha384)
- return 48;
- if (rfcAlgoName == SshCapabilities::HMacSha512)
- return 64;
- throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
- .arg(QString::fromLatin1(rfcAlgoName)));
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshcapabilities.cpp b/src/libs/ssh/sshcapabilities.cpp
deleted file mode 100644
index ac0b4a55c2..0000000000
--- a/src/libs/ssh/sshcapabilities.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshcapabilities_p.h"
-
-#include "sshexception_p.h"
-
-#include <QCoreApplication>
-#include <QString>
-
-namespace QSsh {
-namespace Internal {
-
-namespace {
- QByteArray listAsByteArray(const QList<QByteArray> &list)
- {
- QByteArray array;
- foreach (const QByteArray &elem, list)
- array += elem + ',';
- if (!array.isEmpty())
- array.remove(array.count() - 1, 1);
- return array;
- }
-} // anonymous namspace
-
-const QByteArray SshCapabilities::DiffieHellmanGroup1Sha1("diffie-hellman-group1-sha1");
-const QByteArray SshCapabilities::DiffieHellmanGroup14Sha1("diffie-hellman-group14-sha1");
-const QByteArray SshCapabilities::EcdhKexNamePrefix("ecdh-sha2-nistp");
-const QByteArray SshCapabilities::EcdhNistp256 = EcdhKexNamePrefix + "256";
-const QByteArray SshCapabilities::EcdhNistp384 = EcdhKexNamePrefix + "384";
-const QByteArray SshCapabilities::EcdhNistp521 = EcdhKexNamePrefix + "521";
-const QList<QByteArray> SshCapabilities::KeyExchangeMethods = QList<QByteArray>()
- << SshCapabilities::EcdhNistp256
- << SshCapabilities::EcdhNistp384
- << SshCapabilities::EcdhNistp521
- << SshCapabilities::DiffieHellmanGroup1Sha1
- << SshCapabilities::DiffieHellmanGroup14Sha1;
-
-const QByteArray SshCapabilities::PubKeyDss("ssh-dss");
-const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa");
-const QByteArray SshCapabilities::PubKeyEcdsaPrefix("ecdsa-sha2-nistp");
-const QByteArray SshCapabilities::PubKeyEcdsa256 = SshCapabilities::PubKeyEcdsaPrefix + "256";
-const QByteArray SshCapabilities::PubKeyEcdsa384 = SshCapabilities::PubKeyEcdsaPrefix + "384";
-const QByteArray SshCapabilities::PubKeyEcdsa521 = SshCapabilities::PubKeyEcdsaPrefix + "521";
-const QList<QByteArray> SshCapabilities::PublicKeyAlgorithms = QList<QByteArray>()
- << SshCapabilities::PubKeyEcdsa256
- << SshCapabilities::PubKeyEcdsa384
- << SshCapabilities::PubKeyEcdsa521
- << SshCapabilities::PubKeyRsa
- << SshCapabilities::PubKeyDss;
-
-const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc");
-const QByteArray SshCapabilities::CryptAlgo3DesCtr("3des-ctr");
-const QByteArray SshCapabilities::CryptAlgoAes128Cbc("aes128-cbc");
-const QByteArray SshCapabilities::CryptAlgoAes128Ctr("aes128-ctr");
-const QByteArray SshCapabilities::CryptAlgoAes192Ctr("aes192-ctr");
-const QByteArray SshCapabilities::CryptAlgoAes256Ctr("aes256-ctr");
-const QList<QByteArray> SshCapabilities::EncryptionAlgorithms
- = QList<QByteArray>() << SshCapabilities::CryptAlgoAes256Ctr
- << SshCapabilities::CryptAlgoAes192Ctr
- << SshCapabilities::CryptAlgoAes128Ctr
- << SshCapabilities::CryptAlgo3DesCtr
- << SshCapabilities::CryptAlgoAes128Cbc
- << SshCapabilities::CryptAlgo3DesCbc;
-
-const QByteArray SshCapabilities::HMacSha1("hmac-sha1");
-const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96");
-const QByteArray SshCapabilities::HMacSha256("hmac-sha2-256");
-const QByteArray SshCapabilities::HMacSha384("hmac-sha2-384");
-const QByteArray SshCapabilities::HMacSha512("hmac-sha2-512");
-const QList<QByteArray> SshCapabilities::MacAlgorithms
- = QList<QByteArray>() /* << SshCapabilities::HMacSha196 */
- << SshCapabilities::HMacSha256
- << SshCapabilities::HMacSha384
- << SshCapabilities::HMacSha512
- << SshCapabilities::HMacSha1;
-
-const QList<QByteArray> SshCapabilities::CompressionAlgorithms
- = QList<QByteArray>() << "none";
-
-const QByteArray SshCapabilities::SshConnectionService("ssh-connection");
-
-QList<QByteArray> SshCapabilities::commonCapabilities(const QList<QByteArray> &myCapabilities,
- const QList<QByteArray> &serverCapabilities)
-{
- QList<QByteArray> capabilities;
- foreach (const QByteArray &myCapability, myCapabilities) {
- if (serverCapabilities.contains(myCapability))
- capabilities << myCapability;
- }
-
- if (!capabilities.isEmpty())
- return capabilities;
-
- throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- "Server and client capabilities do not match.",
- QCoreApplication::translate("SshConnection",
- "Server and client capabilities don't match. "
- "Client list was: %1.\nServer list was %2.")
- .arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data()))
- .arg(QString::fromLocal8Bit(listAsByteArray(serverCapabilities).data())));
-
-}
-
-QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilities,
- const QList<QByteArray> &serverCapabilities)
-{
- return commonCapabilities(myCapabilities, serverCapabilities).first();
-}
-
-int SshCapabilities::ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo)
-{
- if (ecdsaAlgo == PubKeyEcdsa256)
- return 32;
- if (ecdsaAlgo == PubKeyEcdsa384)
- return 48;
- if (ecdsaAlgo == PubKeyEcdsa521)
- return 66;
- throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"")
- .arg(QString::fromLatin1(ecdsaAlgo)));
-}
-
-QByteArray SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes)
-{
- if (keyWidthInBytes <= 32)
- return PubKeyEcdsa256;
- if (keyWidthInBytes <= 48)
- return PubKeyEcdsa384;
- if (keyWidthInBytes <= 66)
- return PubKeyEcdsa521;
- throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa key size (%1 bytes)")
- .arg(keyWidthInBytes));
-}
-
-const char *SshCapabilities::oid(const QByteArray &ecdsaAlgo)
-{
- if (ecdsaAlgo == PubKeyEcdsa256)
- return "secp256r1";
- if (ecdsaAlgo == PubKeyEcdsa384)
- return "secp384r1";
- if (ecdsaAlgo == PubKeyEcdsa521)
- return "secp521r1";
- throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"")
- .arg(QString::fromLatin1(ecdsaAlgo)));
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshcapabilities_p.h b/src/libs/ssh/sshcapabilities_p.h
deleted file mode 100644
index 46341681b1..0000000000
--- a/src/libs/ssh/sshcapabilities_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QByteArray>
-#include <QList>
-
-namespace QSsh {
-namespace Internal {
-
-class SshCapabilities
-{
-public:
- static const QByteArray DiffieHellmanGroup1Sha1;
- static const QByteArray DiffieHellmanGroup14Sha1;
- static const QByteArray EcdhKexNamePrefix;
- static const QByteArray EcdhNistp256;
- static const QByteArray EcdhNistp384;
- static const QByteArray EcdhNistp521; // sic
- static const QList<QByteArray> KeyExchangeMethods;
-
- static const QByteArray PubKeyDss;
- static const QByteArray PubKeyRsa;
- static const QByteArray PubKeyEcdsaPrefix;
- static const QByteArray PubKeyEcdsa256;
- static const QByteArray PubKeyEcdsa384;
- static const QByteArray PubKeyEcdsa521;
- static const QList<QByteArray> PublicKeyAlgorithms;
-
- static const QByteArray CryptAlgo3DesCbc;
- static const QByteArray CryptAlgo3DesCtr;
- static const QByteArray CryptAlgoAes128Cbc;
- static const QByteArray CryptAlgoAes128Ctr;
- static const QByteArray CryptAlgoAes192Ctr;
- static const QByteArray CryptAlgoAes256Ctr;
- static const QList<QByteArray> EncryptionAlgorithms;
-
- static const QByteArray HMacSha1;
- static const QByteArray HMacSha196;
- static const QByteArray HMacSha256;
- static const QByteArray HMacSha384;
- static const QByteArray HMacSha512;
- static const QList<QByteArray> MacAlgorithms;
-
- static const QList<QByteArray> CompressionAlgorithms;
-
- static const QByteArray SshConnectionService;
-
- static QList<QByteArray> commonCapabilities(const QList<QByteArray> &myCapabilities,
- const QList<QByteArray> &serverCapabilities);
- static QByteArray findBestMatch(const QList<QByteArray> &myCapabilities,
- const QList<QByteArray> &serverCapabilities);
-
- static int ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo);
- static QByteArray ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes);
- static const char *oid(const QByteArray &ecdsaAlgo);
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshchannel.cpp b/src/libs/ssh/sshchannel.cpp
deleted file mode 100644
index a1a15bf0a7..0000000000
--- a/src/libs/ssh/sshchannel.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshchannel_p.h"
-
-#include "sshincomingpacket_p.h"
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-
-#include <QTimer>
-
-namespace QSsh {
-namespace Internal {
-
-const quint32 NoChannel = 0xffffffffu;
-
-AbstractSshChannel::AbstractSshChannel(quint32 channelId,
- SshSendFacility &sendFacility)
- : m_sendFacility(sendFacility),
- m_localChannel(channelId), m_remoteChannel(NoChannel),
- m_localWindowSize(initialWindowSize()), m_remoteWindowSize(0),
- m_state(Inactive)
-{
- m_timeoutTimer.setSingleShot(true);
- connect(&m_timeoutTimer, &QTimer::timeout, this, &AbstractSshChannel::timeout);
-}
-
-AbstractSshChannel::~AbstractSshChannel()
-{
-
-}
-
-void AbstractSshChannel::setChannelState(ChannelState state)
-{
- m_state = state;
- if (state == Closed)
- closeHook();
-}
-
-void AbstractSshChannel::requestSessionStart()
-{
- // Note: We are just being paranoid here about the Botan exceptions,
- // which are extremely unlikely to happen, because if there was a problem
- // with our cryptography stuff, it would have hit us before, on
- // establishing the connection.
- try {
- m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize());
- setChannelState(SessionRequested);
- m_timeoutTimer.start(ReplyTimeout);
- } catch (const std::exception &e) {
- qCWarning(sshLog, "Botan error: %s", e.what());
- closeChannel();
- }
-}
-
-void AbstractSshChannel::sendData(const QByteArray &data)
-{
- try {
- m_sendBuffer += data;
- flushSendBuffer();
- } catch (const std::exception &e) {
- qCWarning(sshLog, "Botan error: %s", e.what());
- closeChannel();
- }
-}
-
-quint32 AbstractSshChannel::initialWindowSize()
-{
- return maxPacketSize();
-}
-
-quint32 AbstractSshChannel::maxPacketSize()
-{
- return 16 * 1024 * 1024;
-}
-
-void AbstractSshChannel::handleWindowAdjust(quint32 bytesToAdd)
-{
- checkChannelActive();
-
- const quint64 newValue = m_remoteWindowSize + bytesToAdd;
- if (newValue > 0xffffffffu) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Illegal window size requested.");
- }
-
- m_remoteWindowSize = newValue;
- flushSendBuffer();
-}
-
-void AbstractSshChannel::flushSendBuffer()
-{
- while (true) {
- const quint32 bytesToSend = qMin(m_remoteMaxPacketSize,
- qMin<quint32>(m_remoteWindowSize, m_sendBuffer.size()));
- if (bytesToSend == 0)
- break;
- const QByteArray &data = m_sendBuffer.left(bytesToSend);
- m_sendFacility.sendChannelDataPacket(m_remoteChannel, data);
- m_sendBuffer.remove(0, bytesToSend);
- m_remoteWindowSize -= bytesToSend;
- }
-}
-
-void AbstractSshChannel::handleOpenSuccess(quint32 remoteChannelId,
- quint32 remoteWindowSize, quint32 remoteMaxPacketSize)
-{
- const ChannelState oldState = m_state;
- switch (oldState) {
- case CloseRequested: // closeChannel() was called while we were in SessionRequested state
- case SessionRequested:
- break; // Ok, continue.
- default:
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
- }
-
- m_timeoutTimer.stop();
-
- qCDebug(sshLog, "Channel opened. remote channel id: %u, remote window size: %u, "
- "remote max packet size: %u",
- remoteChannelId, remoteWindowSize, remoteMaxPacketSize);
- m_remoteChannel = remoteChannelId;
- m_remoteWindowSize = remoteWindowSize;
- m_remoteMaxPacketSize = remoteMaxPacketSize;
- setChannelState(SessionEstablished);
- if (oldState == CloseRequested)
- closeChannel();
- else
- handleOpenSuccessInternal();
-}
-
-void AbstractSshChannel::handleOpenFailure(const QString &reason)
-{
- switch (m_state) {
- case SessionRequested:
- break; // Ok, continue.
- case CloseRequested:
- return; // Late server reply; we requested a channel close in the meantime.
- default:
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
- }
-
- m_timeoutTimer.stop();
-
- qCDebug(sshLog, "Channel open request failed for channel %u", m_localChannel);
- handleOpenFailureInternal(reason);
-}
-
-void AbstractSshChannel::handleChannelEof()
-{
- if (m_state == Inactive || m_state == Closed) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_EOF message.");
- }
- m_localWindowSize = 0;
- emit eof();
-}
-
-void AbstractSshChannel::handleChannelClose()
-{
- qCDebug(sshLog, "Receiving CLOSE for channel %u", m_localChannel);
- if (channelState() == Inactive || channelState() == Closed) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_CLOSE message.");
- }
- closeChannel();
- setChannelState(Closed);
-}
-
-void AbstractSshChannel::handleChannelData(const QByteArray &data)
-{
- const int bytesToDeliver = handleChannelOrExtendedChannelData(data);
- handleChannelDataInternal(bytesToDeliver == data.size()
- ? data : data.left(bytesToDeliver));
-}
-
-void AbstractSshChannel::handleChannelExtendedData(quint32 type, const QByteArray &data)
-{
- const int bytesToDeliver = handleChannelOrExtendedChannelData(data);
- handleChannelExtendedDataInternal(type, bytesToDeliver == data.size()
- ? data : data.left(bytesToDeliver));
-}
-
-void AbstractSshChannel::handleChannelRequest(const SshIncomingPacket &packet)
-{
- checkChannelActive();
- const QByteArray &requestType = packet.extractChannelRequestType();
- if (requestType == SshIncomingPacket::ExitStatusType)
- handleExitStatus(packet.extractChannelExitStatus());
- else if (requestType == SshIncomingPacket::ExitSignalType)
- handleExitSignal(packet.extractChannelExitSignal());
- else if (requestType != "eow@openssh.com") // Suppress warning for this one, as it's sent all the time.
- qCWarning(sshLog, "Ignoring unknown request type '%s'", requestType.data());
-}
-
-int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &data)
-{
- checkChannelActive();
-
- const int bytesToDeliver = qMin<quint32>(data.size(), maxDataSize());
- if (bytesToDeliver != data.size())
- qCWarning(sshLog, "Misbehaving server does not respect local window, clipping.");
-
- m_localWindowSize -= bytesToDeliver;
- if (m_localWindowSize < maxPacketSize()) {
- m_localWindowSize += maxPacketSize();
- m_sendFacility.sendWindowAdjustPacket(m_remoteChannel, maxPacketSize());
- }
- return bytesToDeliver;
-}
-
-void AbstractSshChannel::closeChannel()
-{
- if (m_state == CloseRequested) {
- m_timeoutTimer.stop();
- } else if (m_state != Closed) {
- if (m_state == Inactive) {
- setChannelState(Closed);
- } else {
- const ChannelState oldState = m_state;
- setChannelState(CloseRequested);
- if (m_remoteChannel != NoChannel) {
- m_sendFacility.sendChannelEofPacket(m_remoteChannel);
- m_sendFacility.sendChannelClosePacket(m_remoteChannel);
- } else {
- QSSH_ASSERT(oldState == SessionRequested);
- }
- }
- }
-}
-
-void AbstractSshChannel::checkChannelActive()
-{
- if (channelState() == Inactive || channelState() == Closed)
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Channel not open.");
-}
-
-quint32 AbstractSshChannel::maxDataSize() const
-{
- return qMin(m_localWindowSize, maxPacketSize());
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshchannel_p.h b/src/libs/ssh/sshchannel_p.h
deleted file mode 100644
index a55567708f..0000000000
--- a/src/libs/ssh/sshchannel_p.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QByteArray>
-#include <QObject>
-#include <QString>
-#include <QTimer>
-
-namespace QSsh {
-namespace Internal {
-
-struct SshChannelExitSignal;
-struct SshChannelExitStatus;
-class SshIncomingPacket;
-class SshSendFacility;
-
-class AbstractSshChannel : public QObject
-{
- Q_OBJECT
-public:
- enum ChannelState {
- Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed
- };
-
- quint32 localChannelId() const { return m_localChannel; }
- quint32 remoteChannel() const { return m_remoteChannel; }
-
- virtual void handleChannelSuccess() = 0;
- virtual void handleChannelFailure() = 0;
-
- void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize,
- quint32 remoteMaxPacketSize);
- void handleOpenFailure(const QString &reason);
- void handleWindowAdjust(quint32 bytesToAdd);
- void handleChannelEof();
- void handleChannelClose();
- void handleChannelData(const QByteArray &data);
- void handleChannelExtendedData(quint32 type, const QByteArray &data);
- void handleChannelRequest(const SshIncomingPacket &packet);
-
- void closeChannel();
-
- virtual ~AbstractSshChannel();
-
- static const int ReplyTimeout = 10000; // milli seconds
- ChannelState channelState() const { return m_state; }
-
-signals:
- void timeout();
- void eof();
-
-protected:
- AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility);
-
- void setChannelState(ChannelState state);
-
- void requestSessionStart();
- void sendData(const QByteArray &data);
-
- static quint32 initialWindowSize();
- static quint32 maxPacketSize();
-
- quint32 maxDataSize() const;
- void checkChannelActive();
-
- SshSendFacility &m_sendFacility;
- QTimer m_timeoutTimer;
-
-private:
- virtual void handleOpenSuccessInternal() = 0;
- virtual void handleOpenFailureInternal(const QString &reason) = 0;
- virtual void handleChannelDataInternal(const QByteArray &data) = 0;
- virtual void handleChannelExtendedDataInternal(quint32 type,
- const QByteArray &data) = 0;
- virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0;
- virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0;
-
- virtual void closeHook() = 0;
-
- void flushSendBuffer();
- int handleChannelOrExtendedChannelData(const QByteArray &data);
-
- const quint32 m_localChannel;
- quint32 m_remoteChannel;
- quint32 m_localWindowSize;
- quint32 m_remoteWindowSize;
- quint32 m_remoteMaxPacketSize;
- ChannelState m_state;
- QByteArray m_sendBuffer;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshchannelmanager.cpp b/src/libs/ssh/sshchannelmanager.cpp
deleted file mode 100644
index f4bfb8cf12..0000000000
--- a/src/libs/ssh/sshchannelmanager.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshchannelmanager_p.h"
-
-#include "sftpchannel.h"
-#include "sftpchannel_p.h"
-#include "sshdirecttcpiptunnel.h"
-#include "sshdirecttcpiptunnel_p.h"
-#include "sshforwardedtcpiptunnel.h"
-#include "sshforwardedtcpiptunnel_p.h"
-#include "sshincomingpacket_p.h"
-#include "sshlogging_p.h"
-#include "sshremoteprocess.h"
-#include "sshremoteprocess_p.h"
-#include "sshsendfacility_p.h"
-#include "sshtcpipforwardserver.h"
-#include "sshtcpipforwardserver_p.h"
-#include "sshx11channel_p.h"
-#include "sshx11inforetriever_p.h"
-
-#include <QList>
-
-namespace QSsh {
-namespace Internal {
-
-SshChannelManager::SshChannelManager(SshSendFacility &sendFacility,
- QObject *parent)
- : QObject(parent), m_sendFacility(sendFacility), m_nextLocalChannelId(0)
-{
-}
-
-void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet)
-{
- lookupChannel(packet.extractRecipientChannel())
- ->handleChannelRequest(packet);
-}
-
-void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet)
-{
- const SshChannelOpenGeneric channelOpen = packet.extractChannelOpen();
- if (channelOpen.channelType == SshIncomingPacket::ForwardedTcpIpType) {
- handleChannelOpenForwardedTcpIp(channelOpen);
- return;
- }
- if (channelOpen.channelType == "x11") {
- handleChannelOpenX11(channelOpen);
- return;
- }
- try {
- m_sendFacility.sendChannelOpenFailurePacket(channelOpen.commonData.remoteChannel,
- SSH_OPEN_UNKNOWN_CHANNEL_TYPE, QByteArray());
- } catch (const std::exception &e) {
- qCWarning(sshLog, "Botan error: %s", e.what());
- }
-}
-
-void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet)
-{
- const SshChannelOpenFailure &failure = packet.extractChannelOpenFailure();
- ChannelIterator it = lookupChannelAsIterator(failure.localChannel);
- try {
- it.value()->handleOpenFailure(failure.reasonString);
- } catch (const SshServerException &e) {
- removeChannel(it);
- throw e;
- }
- removeChannel(it);
-}
-
-void SshChannelManager::handleChannelOpenConfirmation(const SshIncomingPacket &packet)
-{
- const SshChannelOpenConfirmation &confirmation
- = packet.extractChannelOpenConfirmation();
- lookupChannel(confirmation.localChannel)->handleOpenSuccess(confirmation.remoteChannel,
- confirmation.remoteWindowSize, confirmation.remoteMaxPacketSize);
-}
-
-void SshChannelManager::handleChannelSuccess(const SshIncomingPacket &packet)
-{
- lookupChannel(packet.extractRecipientChannel())->handleChannelSuccess();
-}
-
-void SshChannelManager::handleChannelFailure(const SshIncomingPacket &packet)
-{
- lookupChannel(packet.extractRecipientChannel())->handleChannelFailure();
-}
-
-void SshChannelManager::handleChannelWindowAdjust(const SshIncomingPacket &packet)
-{
- const SshChannelWindowAdjust adjust = packet.extractWindowAdjust();
- lookupChannel(adjust.localChannel)->handleWindowAdjust(adjust.bytesToAdd);
-}
-
-void SshChannelManager::handleChannelData(const SshIncomingPacket &packet)
-{
- const SshChannelData &data = packet.extractChannelData();
- lookupChannel(data.localChannel)->handleChannelData(data.data);
-}
-
-void SshChannelManager::handleChannelExtendedData(const SshIncomingPacket &packet)
-{
- const SshChannelExtendedData &data = packet.extractChannelExtendedData();
- lookupChannel(data.localChannel)->handleChannelExtendedData(data.type, data.data);
-}
-
-void SshChannelManager::handleChannelEof(const SshIncomingPacket &packet)
-{
- AbstractSshChannel * const channel
- = lookupChannel(packet.extractRecipientChannel(), true);
- if (channel)
- channel->handleChannelEof();
-}
-
-void SshChannelManager::handleChannelClose(const SshIncomingPacket &packet)
-{
- const quint32 channelId = packet.extractRecipientChannel();
-
- ChannelIterator it = lookupChannelAsIterator(channelId, true);
- if (it != m_channels.end()) {
- it.value()->handleChannelClose();
- removeChannel(it);
- }
-}
-
-void SshChannelManager::handleRequestSuccess(const SshIncomingPacket &packet)
-{
- if (m_waitingForwardServers.isEmpty()) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected request success packet.",
- tr("Unexpected request success packet."));
- }
- SshTcpIpForwardServer::Ptr server = m_waitingForwardServers.takeFirst();
- if (server->state() == SshTcpIpForwardServer::Closing) {
- server->setClosed();
- } else if (server->state() == SshTcpIpForwardServer::Initializing) {
- quint16 port = server->port();
- if (port == 0)
- port = packet.extractRequestSuccess().bindPort;
- server->setListening(port);
- m_listeningForwardServers.append(server);
- } else {
- QSSH_ASSERT(false);
- }
-}
-
-void SshChannelManager::handleRequestFailure(const SshIncomingPacket &packet)
-{
- Q_UNUSED(packet);
- if (m_waitingForwardServers.isEmpty()) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected request failure packet.",
- tr("Unexpected request failure packet."));
- }
- SshTcpIpForwardServer::Ptr tunnel = m_waitingForwardServers.takeFirst();
- tunnel->setClosed();
-}
-
-SshChannelManager::ChannelIterator SshChannelManager::lookupChannelAsIterator(quint32 channelId,
- bool allowNotFound)
-{
- ChannelIterator it = m_channels.find(channelId);
- if (it == m_channels.end() && !allowNotFound) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid channel id.",
- tr("Invalid channel id %1").arg(channelId));
- }
- return it;
-}
-
-AbstractSshChannel *SshChannelManager::lookupChannel(quint32 channelId,
- bool allowNotFound)
-{
- ChannelIterator it = lookupChannelAsIterator(channelId, allowNotFound);
- return it == m_channels.end() ? 0 : it.value();
-}
-
-QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteArray &command)
-{
- SshRemoteProcess::Ptr proc(new SshRemoteProcess(command, m_nextLocalChannelId++, m_sendFacility));
- insertChannel(proc->d, proc);
- connect(proc->d, &SshRemoteProcessPrivate::destroyed, this, [this] {
- m_x11ForwardingRequests.removeOne(static_cast<SshRemoteProcessPrivate *>(sender()));
- });
- connect(proc->d, &SshRemoteProcessPrivate::x11ForwardingRequested, this,
- [this, proc = proc->d](const QString &displayName) {
- if (!x11DisplayName().isEmpty()) {
- if (x11DisplayName() != displayName) {
- proc->failToStart(tr("Cannot forward to display %1 on SSH connection that is "
- "already forwarding to display %2.")
- .arg(displayName, x11DisplayName()));
- return;
- }
- if (!m_x11DisplayInfo.cookie.isEmpty())
- proc->startProcess(m_x11DisplayInfo);
- else
- m_x11ForwardingRequests << proc;
- return;
- }
- m_x11DisplayInfo.displayName = displayName;
- m_x11ForwardingRequests << proc;
- auto * const x11InfoRetriever = new SshX11InfoRetriever(displayName, this);
- const auto failureHandler = [this](const QString &errorMessage) {
- for (SshRemoteProcessPrivate * const proc : qAsConst(m_x11ForwardingRequests))
- proc->failToStart(errorMessage);
- m_x11ForwardingRequests.clear();
- };
- connect(x11InfoRetriever, &SshX11InfoRetriever::failure, this, failureHandler);
- const auto successHandler = [this](const X11DisplayInfo &displayInfo) {
- m_x11DisplayInfo = displayInfo;
- for (SshRemoteProcessPrivate * const proc : qAsConst(m_x11ForwardingRequests))
- proc->startProcess(displayInfo);
- m_x11ForwardingRequests.clear();
- };
- connect(x11InfoRetriever, &SshX11InfoRetriever::success, this, successHandler);
- qCDebug(sshLog) << "starting x11 info retriever";
- x11InfoRetriever->start();
- });
- return proc;
-}
-
-QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteShell()
-{
- SshRemoteProcess::Ptr proc(new SshRemoteProcess(m_nextLocalChannelId++, m_sendFacility));
- insertChannel(proc->d, proc);
- return proc;
-}
-
-QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
-{
- SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility));
- insertChannel(sftp->d, sftp);
- return sftp;
-}
-
-SshDirectTcpIpTunnel::Ptr SshChannelManager::createDirectTunnel(const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
-{
- SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
- originatingHost, originatingPort, remoteHost, remotePort, m_sendFacility));
- insertChannel(tunnel->d, tunnel);
- return tunnel;
-}
-
-SshTcpIpForwardServer::Ptr SshChannelManager::createForwardServer(const QString &remoteHost,
- quint16 remotePort)
-{
- SshTcpIpForwardServer::Ptr server(new SshTcpIpForwardServer(remoteHost, remotePort,
- m_sendFacility));
- connect(server.data(), &SshTcpIpForwardServer::stateChanged,
- this, [this, server](SshTcpIpForwardServer::State state) {
- switch (state) {
- case SshTcpIpForwardServer::Closing:
- m_listeningForwardServers.removeOne(server);
- // fall through
- case SshTcpIpForwardServer::Initializing:
- m_waitingForwardServers.append(server);
- break;
- case SshTcpIpForwardServer::Listening:
- case SshTcpIpForwardServer::Inactive:
- break;
- }
- });
- return server;
-}
-
-void SshChannelManager::insertChannel(AbstractSshChannel *priv,
- const QSharedPointer<QObject> &pub)
-{
- connect(priv, &AbstractSshChannel::timeout, this, &SshChannelManager::timeout);
- m_channels.insert(priv->localChannelId(), priv);
- m_sessions.insert(priv, pub);
-}
-
-void SshChannelManager::handleChannelOpenForwardedTcpIp(
- const SshChannelOpenGeneric &channelOpenGeneric)
-{
- const SshChannelOpenForwardedTcpIp channelOpen
- = SshIncomingPacket::extractChannelOpenForwardedTcpIp(channelOpenGeneric);
-
- SshTcpIpForwardServer::Ptr server;
-
- foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
- if (candidate->port() == channelOpen.remotePort
- && candidate->bindAddress().toUtf8() == channelOpen.remoteAddress) {
- server = candidate;
- break;
- }
- };
-
-
- if (server.isNull()) {
- // Apparently the server knows a remoteAddress we are not aware of. There are plenty of ways
- // to make that happen: /etc/hosts on the server, different writings for localhost,
- // different DNS servers, ...
- // Rather than trying to figure that out, we just use the first listening forwarder with the
- // same port.
- foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
- if (candidate->port() == channelOpen.remotePort) {
- server = candidate;
- break;
- }
- };
- }
-
- if (server.isNull()) {
- try {
- m_sendFacility.sendChannelOpenFailurePacket(channelOpen.common.remoteChannel,
- SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
- QByteArray());
- } catch (const std::exception &e) {
- qCWarning(sshLog, "Botan error: %s", e.what());
- }
- return;
- }
-
- SshForwardedTcpIpTunnel::Ptr tunnel(new SshForwardedTcpIpTunnel(m_nextLocalChannelId++,
- m_sendFacility));
- tunnel->d->handleOpenSuccess(channelOpen.common.remoteChannel,
- channelOpen.common.remoteWindowSize,
- channelOpen.common.remoteMaxPacketSize);
- tunnel->open(QIODevice::ReadWrite);
- server->setNewConnection(tunnel);
- insertChannel(tunnel->d, tunnel);
-}
-
-void SshChannelManager::handleChannelOpenX11(const SshChannelOpenGeneric &channelOpenGeneric)
-{
- qCDebug(sshLog) << "incoming X11 channel open request";
- const SshChannelOpenX11 channelOpen
- = SshIncomingPacket::extractChannelOpenX11(channelOpenGeneric);
- if (m_x11DisplayInfo.cookie.isEmpty()) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server attempted to open an unrequested X11 channel.");
- }
- SshX11Channel * const x11Channel = new SshX11Channel(m_x11DisplayInfo,
- m_nextLocalChannelId++,
- m_sendFacility);
- x11Channel->setParent(this);
- x11Channel->handleOpenSuccess(channelOpen.common.remoteChannel,
- channelOpen.common.remoteWindowSize,
- channelOpen.common.remoteMaxPacketSize);
- insertChannel(x11Channel, QSharedPointer<QObject>());
-}
-
-int SshChannelManager::closeAllChannels(CloseAllMode mode)
-{
- int count = 0;
- for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) {
- AbstractSshChannel * const channel = it.value();
- QSSH_ASSERT(channel->channelState() != AbstractSshChannel::Closed);
- if (channel->channelState() != AbstractSshChannel::CloseRequested) {
- channel->closeChannel();
- ++count;
- }
- }
- if (mode == CloseAllAndReset) {
- m_channels.clear();
- m_sessions.clear();
- }
- return count;
-}
-
-int SshChannelManager::channelCount() const
-{
- return m_channels.count();
-}
-
-void SshChannelManager::removeChannel(ChannelIterator it)
-{
- if (it == m_channels.end()) {
- throw SshClientException(SshInternalError,
- QLatin1String("Internal error: Unexpected channel lookup failure"));
- }
- const int removeCount = m_sessions.remove(it.value());
- if (removeCount != 1) {
- throw SshClientException(SshInternalError,
- QString::fromLatin1("Internal error: Unexpected session count %1 for channel.")
- .arg(removeCount));
- }
- m_channels.erase(it);
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshchannelmanager_p.h b/src/libs/ssh/sshchannelmanager_p.h
deleted file mode 100644
index 10e31e7d9e..0000000000
--- a/src/libs/ssh/sshchannelmanager_p.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshx11displayinfo_p.h"
-
-#include <QHash>
-#include <QObject>
-#include <QSharedPointer>
-
-namespace QSsh {
-class SftpChannel;
-class SshDirectTcpIpTunnel;
-class SshRemoteProcess;
-class SshTcpIpForwardServer;
-
-namespace Internal {
-
-class AbstractSshChannel;
-struct SshChannelOpenGeneric;
-class SshIncomingPacket;
-class SshSendFacility;
-class SshRemoteProcessPrivate;
-
-class SshChannelManager : public QObject
-{
- Q_OBJECT
-public:
- SshChannelManager(SshSendFacility &sendFacility, QObject *parent);
-
- QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
- QSharedPointer<SshRemoteProcess> createRemoteShell();
- QSharedPointer<SftpChannel> createSftpChannel();
- QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
- QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
- quint16 remotePort);
-
- int channelCount() const;
- enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
- int closeAllChannels(CloseAllMode mode);
- QString x11DisplayName() const { return m_x11DisplayInfo.displayName; }
-
- void handleChannelRequest(const SshIncomingPacket &packet);
- void handleChannelOpen(const SshIncomingPacket &packet);
- void handleChannelOpenFailure(const SshIncomingPacket &packet);
- void handleChannelOpenConfirmation(const SshIncomingPacket &packet);
- void handleChannelSuccess(const SshIncomingPacket &packet);
- void handleChannelFailure(const SshIncomingPacket &packet);
- void handleChannelWindowAdjust(const SshIncomingPacket &packet);
- void handleChannelData(const SshIncomingPacket &packet);
- void handleChannelExtendedData(const SshIncomingPacket &packet);
- void handleChannelEof(const SshIncomingPacket &packet);
- void handleChannelClose(const SshIncomingPacket &packet);
- void handleRequestSuccess(const SshIncomingPacket &packet);
- void handleRequestFailure(const SshIncomingPacket &packet);
-
-signals:
- void timeout();
-
-private:
- typedef QHash<quint32, AbstractSshChannel *>::Iterator ChannelIterator;
-
- ChannelIterator lookupChannelAsIterator(quint32 channelId,
- bool allowNotFound = false);
- AbstractSshChannel *lookupChannel(quint32 channelId,
- bool allowNotFound = false);
- void removeChannel(ChannelIterator it);
- void insertChannel(AbstractSshChannel *priv,
- const QSharedPointer<QObject> &pub);
-
- void handleChannelOpenForwardedTcpIp(const SshChannelOpenGeneric &channelOpenGeneric);
- void handleChannelOpenX11(const SshChannelOpenGeneric &channelOpenGeneric);
-
- SshSendFacility &m_sendFacility;
- QHash<quint32, AbstractSshChannel *> m_channels;
- QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions;
- quint32 m_nextLocalChannelId;
- QList<QSharedPointer<SshTcpIpForwardServer>> m_waitingForwardServers;
- QList<QSharedPointer<SshTcpIpForwardServer>> m_listeningForwardServers;
- QList<SshRemoteProcessPrivate *> m_x11ForwardingRequests;
- X11DisplayInfo m_x11DisplayInfo;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshconnection.cpp b/src/libs/ssh/sshconnection.cpp
index 8495da64c4..6dd2e49f9d 100644
--- a/src/libs/ssh/sshconnection.cpp
+++ b/src/libs/ssh/sshconnection.cpp
@@ -24,48 +24,49 @@
****************************************************************************/
#include "sshconnection.h"
-#include "sshconnection_p.h"
-
-#include "sftpchannel.h"
-#include "sshagent_p.h"
-#include "sshcapabilities_p.h"
-#include "sshchannelmanager_p.h"
-#include "sshcryptofacility_p.h"
-#include "sshdirecttcpiptunnel.h"
-#include "sshtcpipforwardserver.h"
-#include "sshexception_p.h"
-#include "sshkeyexchange_p.h"
+
+#include "sftpsession.h"
+#include "sftptransfer.h"
#include "sshlogging_p.h"
+#include "sshprocess_p.h"
#include "sshremoteprocess.h"
+#include "sshsettings.h"
+
+#include <utils/filesystemwatcher.h>
+#include <utils/fileutils.h>
+#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
+#include <utils/temporarydirectory.h>
+
+#include <QByteArrayList>
+#include <QDir>
+#include <QFileInfo>
+#include <QTemporaryDir>
+#include <QTimer>
-#include <QFile>
-#include <QMutex>
-#include <QMutexLocker>
-#include <QNetworkProxy>
-#include <QRegExp>
-#include <QTcpSocket>
+#include <memory>
/*!
\class QSsh::SshConnection
- \brief The SshConnection class provides an SSH connection, implementing
- protocol version 2.0.
+ \brief The SshConnection class provides an SSH connection via an OpenSSH client
+ running in master mode.
- It can spawn channels for remote execution and SFTP operations (version 3).
It operates asynchronously (non-blocking) and is not thread-safe.
+
+ If connection sharing is turned off, the class operates as a simple factory
+ for processes etc and "connecting" always succeeds. The actual connection
+ is then established later, e.g. when starting the remote process.
+
*/
namespace QSsh {
+using namespace Internal;
+using namespace Utils;
-const QByteArray ClientId("SSH-2.0-QtCreator\r\n");
-
-SshConnectionParameters::SshConnectionParameters() :
- timeout(0), authenticationType(AuthenticationTypePublicKey),
- hostKeyCheckingMode(SshHostKeyCheckingNone)
+SshConnectionParameters::SshConnectionParameters()
{
url.setPort(0);
- options |= SshIgnoreDefaultProxy;
- options |= SshEnableStrictConformanceChecks;
}
static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
@@ -74,6 +75,7 @@ static inline bool equals(const SshConnectionParameters &p1, const SshConnection
&& p1.authenticationType == p2.authenticationType
&& p1.privateKeyFile == p2.privateKeyFile
&& p1.hostKeyCheckingMode == p2.hostKeyCheckingMode
+ && p1.x11DisplayName == p2.x11DisplayName
&& p1.timeout == p2.timeout;
}
@@ -87,929 +89,301 @@ bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters
return !equals(p1, p2);
}
-
-SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent)
- : QObject(parent)
-{
- qRegisterMetaType<QSsh::SshError>("QSsh::SshError");
- qRegisterMetaType<QSsh::SftpJobId>("QSsh::SftpJobId");
- qRegisterMetaType<QSsh::SftpFileInfo>("QSsh::SftpFileInfo");
- qRegisterMetaType<QList <QSsh::SftpFileInfo> >("QList<QSsh::SftpFileInfo>");
-
- d = new Internal::SshConnectionPrivate(this, serverInfo);
- connect(d, &Internal::SshConnectionPrivate::connected, this, &SshConnection::connected,
- Qt::QueuedConnection);
- connect(d, &Internal::SshConnectionPrivate::dataAvailable, this,
- &SshConnection::dataAvailable, Qt::QueuedConnection);
- connect(d, &Internal::SshConnectionPrivate::disconnected, this, &SshConnection::disconnected,
- Qt::QueuedConnection);
- connect(d, &Internal::SshConnectionPrivate::error, this,
- &SshConnection::error, Qt::QueuedConnection);
-}
-
-void SshConnection::connectToHost()
-{
- d->connectToHost();
-}
-
-void SshConnection::disconnectFromHost()
-{
- d->closeConnection(Internal::SSH_DISCONNECT_BY_APPLICATION, SshNoError, "",
- QString());
-}
-
-SshConnection::State SshConnection::state() const
-{
- switch (d->state()) {
- case Internal::SocketUnconnected:
- return Unconnected;
- case Internal::ConnectionEstablished:
- return Connected;
- default:
- return Connecting;
- }
-}
-
-SshError SshConnection::errorState() const
-{
- return d->errorState();
-}
-
-QString SshConnection::errorString() const
-{
- return d->errorString();
-}
-
-SshConnectionParameters SshConnection::connectionParameters() const
-{
- return d->m_connParams;
-}
-
-SshConnectionInfo SshConnection::connectionInfo() const
-{
- QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshConnectionInfo());
-
- return SshConnectionInfo(d->m_socket->localAddress(), d->m_socket->localPort(),
- d->m_socket->peerAddress(), d->m_socket->peerPort());
-}
-
-SshConnection::~SshConnection()
-{
- disconnect();
- disconnectFromHost();
- delete d;
-}
-
-QSharedPointer<SshRemoteProcess> SshConnection::createRemoteProcess(const QByteArray &command)
-{
- QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer<SshRemoteProcess>());
- return d->createRemoteProcess(command);
-}
-
-QSharedPointer<SshRemoteProcess> SshConnection::createRemoteShell()
-{
- QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer<SshRemoteProcess>());
- return d->createRemoteShell();
-}
-
-QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
-{
- QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer<SftpChannel>());
- return d->createSftpChannel();
-}
-
-SshDirectTcpIpTunnel::Ptr SshConnection::createDirectTunnel(const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
-{
- QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshDirectTcpIpTunnel::Ptr());
- return d->createDirectTunnel(originatingHost, originatingPort, remoteHost, remotePort);
-}
-
-QSharedPointer<SshTcpIpForwardServer> SshConnection::createForwardServer(const QString &remoteHost,
- quint16 remotePort)
-{
- QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshTcpIpForwardServer::Ptr());
- return d->createForwardServer(remoteHost, remotePort);
-}
-
-int SshConnection::closeAllChannels()
+struct SshConnection::SshConnectionPrivate
{
- try {
- return d->m_channelManager->closeAllChannels(Internal::SshChannelManager::CloseAllRegular);
- } catch (const std::exception &e) {
- qCWarning(Internal::sshLog, "%s: %s", Q_FUNC_INFO, e.what());
- return -1;
+ QString fullProcessError()
+ {
+ QString error;
+ if (masterProcess.exitStatus() != QProcess::NormalExit)
+ error = masterProcess.errorString();
+ const QByteArray stdErr = masterProcess.readAllStandardError();
+ if (!stdErr.isEmpty()) {
+ if (!error.isEmpty())
+ error.append('\n');
+ error.append(QString::fromLocal8Bit(stdErr));
+ }
+ return error;
}
-}
-
-int SshConnection::channelCount() const
-{
- return d->m_channelManager->channelCount();
-}
-
-QString SshConnection::x11DisplayName() const
-{
- return d->m_channelManager->x11DisplayName();
-}
-
-namespace Internal {
-
-SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn,
- const SshConnectionParameters &serverInfo)
- : m_socket(new QTcpSocket(this)), m_state(SocketUnconnected),
- m_sendFacility(m_socket),
- m_channelManager(new SshChannelManager(m_sendFacility, this)),
- m_connParams(serverInfo), m_error(SshNoError), m_ignoreNextPacket(false),
- m_conn(conn)
-{
- setupPacketHandlers();
- m_socket->setProxy((m_connParams.options & SshIgnoreDefaultProxy)
- ? QNetworkProxy::NoProxy : QNetworkProxy::DefaultProxy);
- m_timeoutTimer.setSingleShot(true);
- m_timeoutTimer.setInterval(m_connParams.timeout * 1000);
- m_keepAliveTimer.setSingleShot(true);
- m_keepAliveTimer.setInterval(10000);
- connect(m_channelManager, &SshChannelManager::timeout,
- this, &SshConnectionPrivate::handleTimeout);
-}
-
-SshConnectionPrivate::~SshConnectionPrivate()
-{
- disconnect();
-}
-void SshConnectionPrivate::setupPacketHandlers()
-{
- typedef SshConnectionPrivate This;
-
- setupPacketHandler(SSH_MSG_KEXINIT, StateList() << SocketConnected
- << ConnectionEstablished, &This::handleKeyExchangeInitPacket);
- setupPacketHandler(SSH_MSG_KEXDH_REPLY, StateList() << SocketConnected
- << ConnectionEstablished, &This::handleKeyExchangeReplyPacket);
-
- setupPacketHandler(SSH_MSG_NEWKEYS, StateList() << SocketConnected
- << ConnectionEstablished, &This::handleNewKeysPacket);
- setupPacketHandler(SSH_MSG_SERVICE_ACCEPT,
- StateList() << UserAuthServiceRequested,
- &This::handleServiceAcceptPacket);
- if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypePassword
- || m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods) {
- setupPacketHandler(SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
- StateList() << UserAuthRequested, &This::handlePasswordExpiredPacket);
- }
- setupPacketHandler(SSH_MSG_GLOBAL_REQUEST,
- StateList() << ConnectionEstablished, &This::handleGlobalRequest);
-
- const StateList authReqList = StateList() << UserAuthRequested;
- setupPacketHandler(SSH_MSG_USERAUTH_BANNER, authReqList,
- &This::handleUserAuthBannerPacket);
- setupPacketHandler(SSH_MSG_USERAUTH_SUCCESS, authReqList,
- &This::handleUserAuthSuccessPacket);
- setupPacketHandler(SSH_MSG_USERAUTH_FAILURE, authReqList,
- &This::handleUserAuthFailurePacket);
- if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeKeyboardInteractive
- || m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods) {
- setupPacketHandler(SSH_MSG_USERAUTH_INFO_REQUEST, authReqList,
- &This::handleUserAuthInfoRequestPacket);
+ QString socketFilePath() const
+ {
+ QTC_ASSERT(masterSocketDir, return QString());
+ return masterSocketDir->path() + "/control_socket";
}
- setupPacketHandler(SSH_MSG_USERAUTH_PK_OK, authReqList, &This::handleUserAuthKeyOkPacket);
-
- const StateList connectedList
- = StateList() << ConnectionEstablished;
- setupPacketHandler(SSH_MSG_CHANNEL_REQUEST, connectedList,
- &This::handleChannelRequest);
- setupPacketHandler(SSH_MSG_CHANNEL_OPEN, connectedList,
- &This::handleChannelOpen);
- setupPacketHandler(SSH_MSG_CHANNEL_OPEN_FAILURE, connectedList,
- &This::handleChannelOpenFailure);
- setupPacketHandler(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, connectedList,
- &This::handleChannelOpenConfirmation);
- setupPacketHandler(SSH_MSG_CHANNEL_SUCCESS, connectedList,
- &This::handleChannelSuccess);
- setupPacketHandler(SSH_MSG_CHANNEL_FAILURE, connectedList,
- &This::handleChannelFailure);
- setupPacketHandler(SSH_MSG_CHANNEL_WINDOW_ADJUST, connectedList,
- &This::handleChannelWindowAdjust);
- setupPacketHandler(SSH_MSG_CHANNEL_DATA, connectedList,
- &This::handleChannelData);
- setupPacketHandler(SSH_MSG_CHANNEL_EXTENDED_DATA, connectedList,
- &This::handleChannelExtendedData);
-
- const StateList connectedOrClosedList
- = StateList() << SocketUnconnected << ConnectionEstablished;
- setupPacketHandler(SSH_MSG_CHANNEL_EOF, connectedOrClosedList,
- &This::handleChannelEof);
- setupPacketHandler(SSH_MSG_CHANNEL_CLOSE, connectedOrClosedList,
- &This::handleChannelClose);
-
- setupPacketHandler(SSH_MSG_DISCONNECT, StateList() << SocketConnected << WaitingForAgentKeys
- << UserAuthServiceRequested << UserAuthRequested
- << ConnectionEstablished, &This::handleDisconnect);
-
- setupPacketHandler(SSH_MSG_UNIMPLEMENTED,
- StateList() << ConnectionEstablished, &This::handleUnimplementedPacket);
-
- setupPacketHandler(SSH_MSG_REQUEST_SUCCESS, connectedList,
- &This::handleRequestSuccess);
- setupPacketHandler(SSH_MSG_REQUEST_FAILURE, connectedList,
- &This::handleRequestFailure);
-}
-void SshConnectionPrivate::setupPacketHandler(SshPacketType type,
- const SshConnectionPrivate::StateList &states,
- SshConnectionPrivate::PacketHandler handler)
-{
- m_packetHandlers.insert(type, HandlerInStates(states, handler));
-}
+ QStringList connectionArgs() const
+ {
+ QString hostKeyCheckingString;
+ switch (connParams.hostKeyCheckingMode) {
+ case SshHostKeyCheckingNone:
+ case SshHostKeyCheckingAllowNoMatch:
+ // There is "accept-new" as well, but only since 7.6.
+ hostKeyCheckingString = "no";
+ break;
+ case SshHostKeyCheckingStrict:
+ hostKeyCheckingString = "yes";
+ break;
+ }
+ QStringList args{"-o", "StrictHostKeyChecking=" + hostKeyCheckingString,
+ "-o", "User=" + connParams.userName(),
+ "-o", "Port=" + QString::number(connParams.port())};
+ const bool keyOnly = connParams.authenticationType ==
+ SshConnectionParameters::AuthenticationTypeSpecificKey;
+ if (keyOnly)
+ args << "-i" << connParams.privateKeyFile;
+ if (keyOnly || SshSettings::askpassFilePath().isEmpty())
+ args << "-o" << "BatchMode=yes";
+ if (sharingEnabled)
+ args << "-o" << ("ControlPath=" + socketFilePath());
+ if (connParams.timeout != 0)
+ args << "-o" << ("ConnectTimeout=" + QString::number(connParams.timeout));
+ return args << connParams.host();
+ }
+
+ SshConnectionParameters connParams;
+ SshConnectionInfo connInfo;
+ SshProcess masterProcess;
+ QString errorString;
+ QTimer socketWatcherTimer;
+ std::unique_ptr<TemporaryDirectory> masterSocketDir;
+ FileSystemWatcher *socketWatcher = nullptr;
+ State state = Unconnected;
+ const bool sharingEnabled = SshSettings::connectionSharingEnabled();
+};
-void SshConnectionPrivate::handleSocketConnected()
-{
- m_state = SocketConnected;
- sendData(ClientId);
-}
-void SshConnectionPrivate::handleIncomingData()
+SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent)
+ : QObject(parent), d(new SshConnectionPrivate)
{
- if (m_state == SocketUnconnected)
- return; // For stuff queued in the event loop after we've called closeConnection();
-
- try {
- if (!canUseSocket())
+ qRegisterMetaType<QSsh::SftpFileInfo>("QSsh::SftpFileInfo");
+ qRegisterMetaType<QList <QSsh::SftpFileInfo> >("QList<QSsh::SftpFileInfo>");
+ d->connParams = serverInfo;
+ d->socketWatcher = new FileSystemWatcher(this);
+ connect(&d->masterProcess, &QProcess::started, [this] {
+ QFileInfo socketInfo(d->socketFilePath());
+ if (socketInfo.exists()) {
+ emitConnected();
return;
- m_incomingData += m_socket->readAll();
- qCDebug(sshLog, "state = %d, remote data size = %d", m_state, m_incomingData.count());
- if (m_serverId.isEmpty())
- handleServerId();
- handlePackets();
- } catch (const SshServerException &e) {
- closeConnection(e.error, SshProtocolError, e.errorStringServer,
- tr("SSH Protocol error: %1").arg(e.errorStringUser));
- } catch (const SshClientException &e) {
- closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "",
- e.errorString);
- } catch (const std::exception &e) {
- closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "",
- tr("Botan library exception: %1").arg(QString::fromLatin1(e.what())));
- }
-}
-
-// RFC 4253, 4.2.
-void SshConnectionPrivate::handleServerId()
-{
- qCDebug(sshLog, "%s: incoming data size = %d, incoming data = '%s'",
- Q_FUNC_INFO, m_incomingData.count(), m_incomingData.data());
- const int newLinePos = m_incomingData.indexOf('\n');
- if (newLinePos == -1)
- return; // Not enough data yet.
-
- // Lines not starting with "SSH-" are ignored.
- if (!m_incomingData.startsWith("SSH-")) {
- m_incomingData.remove(0, newLinePos + 1);
- m_serverHasSentDataBeforeId = true;
- return;
- }
-
- if (newLinePos > 255 - 1) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Identification string too long.",
- tr("Server identification string is %n characters long, but the maximum "
- "allowed length is 255.", 0, newLinePos + 1));
- }
-
- const bool hasCarriageReturn = m_incomingData.at(newLinePos - 1) == '\r';
- m_serverId = m_incomingData.left(newLinePos);
- if (hasCarriageReturn)
- m_serverId.chop(1);
- m_incomingData.remove(0, newLinePos + 1);
-
- if (m_serverId.contains('\0')) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Identification string contains illegal NUL character.",
- tr("Server identification string contains illegal NUL character."));
- }
-
- // "printable US-ASCII characters, with the exception of whitespace characters
- // and the minus sign"
- QString legalString = QLatin1String("[]!\"#$!&'()*+,./0-9:;<=>?@A-Z[\\\\^_`a-z{|}~]+");
- const QRegExp versionIdpattern(QString::fromLatin1("SSH-(%1)-%1(?: .+)?").arg(legalString));
- if (!versionIdpattern.exactMatch(QString::fromLatin1(m_serverId))) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Identification string is invalid.",
- tr("Server Identification string \"%1\" is invalid.")
- .arg(QString::fromLatin1(m_serverId)));
- }
- const QString serverProtoVersion = versionIdpattern.cap(1);
- if (serverProtoVersion != QLatin1String("2.0") && serverProtoVersion != QLatin1String("1.99")) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
- "Invalid protocol version.",
- tr("Server protocol version is \"%1\", but needs to be 2.0 or 1.99.")
- .arg(serverProtoVersion));
- }
-
- if (m_connParams.options & SshEnableStrictConformanceChecks) {
- if (serverProtoVersion == QLatin1String("2.0") && !hasCarriageReturn) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Identification string is invalid.",
- tr("Server identification string is invalid (missing carriage return)."));
}
-
- if (serverProtoVersion == QLatin1String("1.99") && m_serverHasSentDataBeforeId) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "No extra data preceding identification string allowed for 1.99.",
- tr("Server reports protocol version 1.99, but sends data "
- "before the identification string, which is not allowed."));
+ const auto socketFileChecker = [this] {
+ if (!QFileInfo::exists(d->socketFilePath()))
+ return;
+ d->socketWatcher->disconnect();
+ d->socketWatcher->removeDirectory(QFileInfo(d->socketFilePath()).path());
+ d->socketWatcherTimer.disconnect();
+ d->socketWatcherTimer.stop();
+ emitConnected();
+ };
+ connect(d->socketWatcher, &FileSystemWatcher::directoryChanged, socketFileChecker);
+ d->socketWatcher->addDirectory(socketInfo.path(), FileSystemWatcher::WatchAllChanges);
+ if (HostOsInfo::isMacHost()) {
+ // QTBUG-72455
+ d->socketWatcherTimer.setInterval(1000);
+ connect(&d->socketWatcherTimer, &QTimer::timeout, socketFileChecker);
+ d->socketWatcherTimer.start();
}
+ });
+ connect(&d->masterProcess, &QProcess::errorOccurred, [this] (QProcess::ProcessError error) {
+ switch (error) {
+ case QProcess::FailedToStart:
+ emitError(tr("Cannot establish SSH connection: Control process failed to start: %1")
+ .arg(d->fullProcessError()));
+ break;
+ case QProcess::Crashed: // Handled by finished() handler.
+ case QProcess::Timedout:
+ case QProcess::ReadError:
+ case QProcess::WriteError:
+ case QProcess::UnknownError:
+ break; // Cannot happen.
+ }
+ });
+ connect(&d->masterProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished), [this] {
+ if (d->state == Disconnecting) {
+ emitDisconnected();
+ return;
+ }
+ const QString procError = d->fullProcessError();
+ QString errorMsg = tr("SSH connection failure.");
+ if (!procError.isEmpty())
+ errorMsg.append('\n').append(procError);
+ emitError(errorMsg);
+ });
+ if (!d->connParams.x11DisplayName.isEmpty()) {
+ QProcessEnvironment env = d->masterProcess.processEnvironment();
+ env.insert("DISPLAY", d->connParams.x11DisplayName);
+ d->masterProcess.setProcessEnvironment(env);
}
-
- m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility));
- m_keyExchange->sendKexInitPacket(m_serverId);
- m_keyExchangeState = KexInitSent;
-}
-
-void SshConnectionPrivate::handlePackets()
-{
- m_incomingPacket.consumeData(m_incomingData);
- while (m_incomingPacket.isComplete()) {
- handleCurrentPacket();
- m_incomingPacket.clear();
- m_incomingPacket.consumeData(m_incomingData);
- }
-}
-
-void SshConnectionPrivate::handleCurrentPacket()
-{
- Q_ASSERT(m_incomingPacket.isComplete());
- Q_ASSERT(m_keyExchangeState == DhInitSent || !m_ignoreNextPacket);
-
- if (m_ignoreNextPacket) {
- m_ignoreNextPacket = false;
- return;
- }
-
- QHash<SshPacketType, HandlerInStates>::ConstIterator it
- = m_packetHandlers.constFind(m_incomingPacket.type());
- if (it == m_packetHandlers.constEnd()) {
- m_sendFacility.sendMsgUnimplementedPacket(m_incomingPacket.serverSeqNr());
- return;
- }
- if (!it.value().first.contains(m_state)) {
- handleUnexpectedPacket();
- return;
- }
- (this->*it.value().second)();
-}
-
-void SshConnectionPrivate::handleKeyExchangeInitPacket()
-{
- if (m_keyExchangeState != NoKeyExchange
- && m_keyExchangeState != KexInitSent) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected packet.", tr("Unexpected packet of type %1.")
- .arg(m_incomingPacket.type()));
- }
-
- // Server-initiated re-exchange.
- if (m_keyExchangeState == NoKeyExchange) {
- m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility));
- m_keyExchange->sendKexInitPacket(m_serverId);
- }
-
- // If the server sends a guessed packet, the guess must be wrong,
- // because the algorithms we support require us to initiate the
- // key exchange.
- if (m_keyExchange->sendDhInitPacket(m_incomingPacket))
- m_ignoreNextPacket = true;
-
- m_keyExchangeState = DhInitSent;
-}
-
-void SshConnectionPrivate::handleKeyExchangeReplyPacket()
-{
- if (m_keyExchangeState != DhInitSent) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected packet.", tr("Unexpected packet of type %1.")
- .arg(m_incomingPacket.type()));
- }
-
- m_keyExchange->sendNewKeysPacket(m_incomingPacket,
- ClientId.left(ClientId.size() - 2));
- m_sendFacility.recreateKeys(*m_keyExchange);
- m_keyExchangeState = NewKeysSent;
}
-void SshConnectionPrivate::handleNewKeysPacket()
+void SshConnection::connectToHost()
{
- if (m_keyExchangeState != NewKeysSent) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected packet.", tr("Unexpected packet of type %1.")
- .arg(m_incomingPacket.type()));
- }
-
- m_incomingPacket.recreateKeys(*m_keyExchange);
- m_keyExchange.reset();
- m_keyExchangeState = NoKeyExchange;
-
- if (m_state == SocketConnected) {
- m_sendFacility.sendUserAuthServiceRequestPacket();
- m_state = UserAuthServiceRequested;
- }
+ d->state = Connecting;
+ QTimer::singleShot(0, this, &SshConnection::doConnectToHost);
}
-void SshConnectionPrivate::handleServiceAcceptPacket()
+void SshConnection::disconnectFromHost()
{
- switch (m_connParams.authenticationType) {
- case SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods:
- m_triedAllPasswordBasedMethods = false;
- // Fall-through.
- case SshConnectionParameters::AuthenticationTypePassword:
- m_sendFacility.sendUserAuthByPasswordRequestPacket(m_connParams.userName().toUtf8(),
- SshCapabilities::SshConnectionService, m_connParams.password().toUtf8());
- break;
- case SshConnectionParameters::AuthenticationTypeKeyboardInteractive:
- m_sendFacility.sendUserAuthByKeyboardInteractiveRequestPacket(m_connParams.userName().toUtf8(),
- SshCapabilities::SshConnectionService);
- break;
- case SshConnectionParameters::AuthenticationTypePublicKey:
- authenticateWithPublicKey();
- break;
- case SshConnectionParameters::AuthenticationTypeAgent:
- if (SshAgent::publicKeys().isEmpty()) {
- if (m_agentKeysUpToDate)
- throw SshClientException(SshAuthenticationError, tr("ssh-agent has no keys."));
- qCDebug(sshLog) << "agent has no keys yet, waiting";
- m_state = WaitingForAgentKeys;
+ switch (d->state) {
+ case Connecting:
+ case Connected:
+ if (!d->sharingEnabled) {
+ emitDisconnected();
return;
- } else {
- tryAllAgentKeys();
}
+ d->state = Disconnecting;
+ if (HostOsInfo::isWindowsHost())
+ d->masterProcess.kill();
+ else
+ d->masterProcess.terminate();
+ break;
+ case Unconnected:
+ case Disconnecting:
break;
}
- m_state = UserAuthRequested;
-}
-
-void SshConnectionPrivate::handlePasswordExpiredPacket()
-{
- if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
- && m_triedAllPasswordBasedMethods) {
- // This means we just tried to authorize via "keyboard-interactive", in which case
- // this type of packet is not allowed.
- handleUnexpectedPacket();
- return;
- }
- throw SshClientException(SshAuthenticationError, tr("Password expired."));
-}
-
-void SshConnectionPrivate::handleUserAuthInfoRequestPacket()
-{
- if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
- && !m_triedAllPasswordBasedMethods) {
- // This means we just tried to authorize via "password", in which case
- // this type of packet is not allowed.
- handleUnexpectedPacket();
- return;
- }
-
- const SshUserAuthInfoRequestPacket requestPacket
- = m_incomingPacket.extractUserAuthInfoRequest();
- QStringList responses;
- responses.reserve(requestPacket.prompts.count());
-
- // Not very interactive, admittedly, but we don't want to be for now.
- for (int i = 0; i < requestPacket.prompts.count(); ++i)
- responses << m_connParams.password();
- m_sendFacility.sendUserAuthInfoResponsePacket(responses);
-}
-
-void SshConnectionPrivate::handleUserAuthBannerPacket()
-{
- emit dataAvailable(m_incomingPacket.extractUserAuthBanner().message);
-}
-
-void SshConnectionPrivate::handleUnexpectedPacket()
-{
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected packet.", tr("Unexpected packet of type %1.")
- .arg(m_incomingPacket.type()));
}
-void SshConnectionPrivate::handleGlobalRequest()
+SshConnection::State SshConnection::state() const
{
- m_sendFacility.sendRequestFailurePacket();
+ return d->state;
}
-void SshConnectionPrivate::handleUserAuthSuccessPacket()
+QString SshConnection::errorString() const
{
- m_state = ConnectionEstablished;
- m_timeoutTimer.stop();
- emit connected();
- m_lastInvalidMsgSeqNr = InvalidSeqNr;
- connect(&m_keepAliveTimer, &QTimer::timeout, this, &SshConnectionPrivate::sendKeepAlivePacket);
- m_keepAliveTimer.start();
+ return d->errorString;
}
-void SshConnectionPrivate::handleUserAuthFailurePacket()
+SshConnectionParameters SshConnection::connectionParameters() const
{
- if (!m_pendingKeyChecks.isEmpty()) {
- const QByteArray key = m_pendingKeyChecks.dequeue();
- SshAgent::removeDataToSign(key, tokenForAgent());
- qCDebug(sshLog) << "server rejected one of the keys supplied by the agent,"
- << m_pendingKeyChecks.count() << "keys remaining";
- if (m_pendingKeyChecks.isEmpty() && m_agentKeyToUse.isEmpty()) {
- throw SshClientException(SshAuthenticationError, tr("The server rejected all keys "
- "known to the ssh-agent."));
- }
- return;
- }
-
- // TODO: Evaluate "authentications that can continue" field and act on it.
- if (m_connParams.authenticationType
- == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
- && !m_triedAllPasswordBasedMethods) {
- m_triedAllPasswordBasedMethods = true;
- m_sendFacility.sendUserAuthByKeyboardInteractiveRequestPacket(
- m_connParams.userName().toUtf8(),
- SshCapabilities::SshConnectionService);
- return;
- }
-
- m_timeoutTimer.stop();
- QString errorMsg;
- switch (m_connParams.authenticationType) {
- case SshConnectionParameters::AuthenticationTypePublicKey:
- case SshConnectionParameters::AuthenticationTypeAgent:
- errorMsg = tr("Server rejected key.");
- break;
- default:
- errorMsg = tr("Server rejected password.");
- break;
- }
- throw SshClientException(SshAuthenticationError, errorMsg);
+ return d->connParams;
}
-void SshConnectionPrivate::handleUserAuthKeyOkPacket()
+SshConnectionInfo SshConnection::connectionInfo() const
{
- const SshUserAuthPkOkPacket &msg = m_incomingPacket.extractUserAuthPkOk();
- qCDebug(sshLog) << "server accepted key of type" << msg.algoName;
-
- if (m_pendingKeyChecks.isEmpty()) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected packet",
- tr("Server sent unexpected SSH_MSG_USERAUTH_PK_OK packet."));
+ QTC_ASSERT(state() == Connected, return SshConnectionInfo());
+ if (d->connInfo.isValid())
+ return d->connInfo;
+ QProcess p;
+ p.start(SshSettings::sshFilePath().toString(), d->connectionArgs() << "echo" << "-n"
+ << "$SSH_CLIENT");
+ if (!p.waitForStarted() || !p.waitForFinished()) {
+ qCWarning(Internal::sshLog) << "failed to retrieve connection info:" << p.errorString();
+ return SshConnectionInfo();
}
- const QByteArray key = m_pendingKeyChecks.dequeue();
- if (key != msg.keyBlob) {
- // The server must answer the requests in the order we sent them.
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected packet content",
- tr("Server sent unexpected key in SSH_MSG_USERAUTH_PK_OK packet."));
+ const QByteArrayList data = p.readAllStandardOutput().split(' ');
+ if (data.size() != 3) {
+ qCWarning(Internal::sshLog) << "failed to retrieve connection info: unexpected output";
+ return SshConnectionInfo();
}
- const uint token = tokenForAgent();
- if (!m_agentKeyToUse.isEmpty()) {
- qCDebug(sshLog) << "another key has already been accepted, ignoring this one";
- SshAgent::removeDataToSign(key, token);
- return;
+ d->connInfo.localPort = data.at(1).toInt();
+ if (d->connInfo.localPort == 0) {
+ qCWarning(Internal::sshLog) << "failed to retrieve connection info: unexpected output";
+ return SshConnectionInfo();
}
- m_agentKeyToUse = key;
- qCDebug(sshLog) << "requesting signature from agent";
- SshAgent::requestSignature(key, token);
-}
-
-void SshConnectionPrivate::handleDebugPacket()
-{
- const SshDebug &msg = m_incomingPacket.extractDebug();
- if (msg.display)
- emit dataAvailable(msg.message);
-}
-
-void SshConnectionPrivate::handleUnimplementedPacket()
-{
- const SshUnimplemented &msg = m_incomingPacket.extractUnimplemented();
- if (msg.invalidMsgSeqNr != m_lastInvalidMsgSeqNr) {
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected packet", tr("The server sent an unexpected SSH packet "
- "of type SSH_MSG_UNIMPLEMENTED."));
+ if (!d->connInfo.localAddress.setAddress(QString::fromLatin1(data.first()))) {
+ qCWarning(Internal::sshLog) << "failed to retrieve connection info: unexpected output";
+ return SshConnectionInfo();
}
- m_lastInvalidMsgSeqNr = InvalidSeqNr;
- m_timeoutTimer.stop();
- m_keepAliveTimer.start();
-}
-
-void SshConnectionPrivate::handleChannelRequest()
-{
- m_channelManager->handleChannelRequest(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelOpen()
-{
- m_channelManager->handleChannelOpen(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelOpenFailure()
-{
- m_channelManager->handleChannelOpenFailure(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelOpenConfirmation()
-{
- m_channelManager->handleChannelOpenConfirmation(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelSuccess()
-{
- m_channelManager->handleChannelSuccess(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelFailure()
-{
- m_channelManager->handleChannelFailure(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelWindowAdjust()
-{
- m_channelManager->handleChannelWindowAdjust(m_incomingPacket);
+ d->connInfo.peerPort = d->connParams.port();
+ d->connInfo.peerAddress.setAddress(d->connParams.host());
+ return d->connInfo;
}
-void SshConnectionPrivate::handleChannelData()
+bool SshConnection::sharingEnabled() const
{
- m_channelManager->handleChannelData(m_incomingPacket);
+ return d->sharingEnabled;
}
-void SshConnectionPrivate::handleChannelExtendedData()
-{
- m_channelManager->handleChannelExtendedData(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelEof()
-{
- m_channelManager->handleChannelEof(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleChannelClose()
-{
- m_channelManager->handleChannelClose(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleDisconnect()
-{
- const SshDisconnect msg = m_incomingPacket.extractDisconnect();
- throw SshServerException(SSH_DISCONNECT_CONNECTION_LOST,
- "", tr("Server closed connection: %1").arg(msg.description));
-}
-
-void SshConnectionPrivate::handleRequestSuccess()
-{
- m_channelManager->handleRequestSuccess(m_incomingPacket);
-}
-
-void SshConnectionPrivate::handleRequestFailure()
+SshConnection::~SshConnection()
{
- m_channelManager->handleRequestFailure(m_incomingPacket);
+ disconnect();
+ disconnectFromHost();
+ delete d;
}
-void SshConnectionPrivate::sendData(const QByteArray &data)
+SshRemoteProcessPtr SshConnection::createRemoteProcess(const QByteArray &command)
{
- if (canUseSocket())
- m_socket->write(data);
+ QTC_ASSERT(state() == Connected, return SshRemoteProcessPtr());
+ return SshRemoteProcessPtr(new SshRemoteProcess(command, d->connectionArgs()));
}
-uint SshConnectionPrivate::tokenForAgent() const
+SshRemoteProcessPtr SshConnection::createRemoteShell()
{
- return qHash(m_sendFacility.sessionId());
+ return createRemoteProcess(QByteArray());
}
-void SshConnectionPrivate::handleSocketDisconnected()
+SftpTransferPtr SshConnection::createUpload(const FilesToTransfer &files,
+ FileTransferErrorHandling errorHandlingMode)
{
- closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshClosedByServerError,
- "Connection closed unexpectedly.",
- tr("Connection closed unexpectedly."));
+ return setupTransfer(files, Internal::FileTransferType::Upload, errorHandlingMode);
}
-void SshConnectionPrivate::handleSocketError()
+SftpTransferPtr SshConnection::createDownload(const FilesToTransfer &files,
+ FileTransferErrorHandling errorHandlingMode)
{
- if (m_error == SshNoError) {
- closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshSocketError,
- "Network error", m_socket->errorString());
- }
+ return setupTransfer(files, Internal::FileTransferType::Download, errorHandlingMode);
}
-void SshConnectionPrivate::handleTimeout()
+SftpSessionPtr SshConnection::createSftpSession()
{
- const QString errorMessage = m_state == WaitingForAgentKeys
- ? tr("Timeout waiting for keys from ssh-agent.")
- : tr("Timeout waiting for reply from server.");
- closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshTimeoutError, "", errorMessage);
+ QTC_ASSERT(state() == Connected, return SftpSessionPtr());
+ return SftpSessionPtr(new SftpSession(d->connectionArgs()));
}
-void SshConnectionPrivate::sendKeepAlivePacket()
+void SshConnection::doConnectToHost()
{
- // This type of message is not allowed during key exchange.
- if (m_keyExchangeState != NoKeyExchange) {
- m_keepAliveTimer.start();
+ if (d->state != Connecting)
return;
- }
-
- Q_ASSERT(m_lastInvalidMsgSeqNr == InvalidSeqNr);
- m_lastInvalidMsgSeqNr = m_sendFacility.nextClientSeqNr();
- m_sendFacility.sendInvalidPacket();
- m_timeoutTimer.start();
-}
-
-void SshConnectionPrivate::handleAgentKeysUpdated()
-{
- m_agentKeysUpToDate = true;
- if (m_state == WaitingForAgentKeys) {
- m_state = UserAuthRequested;
- tryAllAgentKeys();
- }
-}
-
-void SshConnectionPrivate::handleSignatureFromAgent(const QByteArray &key,
- const QByteArray &signature, uint token)
-{
- if (token != tokenForAgent()) {
- qCDebug(sshLog) << "signature is for different connection, ignoring";
+ const FileName sshBinary = SshSettings::sshFilePath();
+ if (!sshBinary.exists()) {
+ emitError(tr("Cannot establish SSH connection: ssh binary \"%1\" does not exist.")
+ .arg(sshBinary.toUserOutput()));
return;
}
- QSSH_ASSERT(key == m_agentKeyToUse);
- m_agentSignature = signature;
- authenticateWithPublicKey();
-}
-
-void SshConnectionPrivate::tryAllAgentKeys()
-{
- const QList<QByteArray> &keys = SshAgent::publicKeys();
- if (keys.isEmpty())
- throw SshClientException(SshAuthenticationError, tr("ssh-agent has no keys."));
- qCDebug(sshLog) << "trying authentication with" << keys.count()
- << "public keys received from agent";
- foreach (const QByteArray &key, keys) {
- m_sendFacility.sendQueryPublicKeyPacket(m_connParams.userName().toUtf8(),
- SshCapabilities::SshConnectionService, key);
- m_pendingKeyChecks.enqueue(key);
- }
-}
-
-void SshConnectionPrivate::authenticateWithPublicKey()
-{
- qCDebug(sshLog) << "sending actual authentication request";
-
- QByteArray key;
- QByteArray signature;
- if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeAgent) {
- // Agent is not needed anymore after this point.
- disconnect(&SshAgent::instance(), 0, this, 0);
-
- key = m_agentKeyToUse;
- signature = m_agentSignature;
- }
-
- m_sendFacility.sendUserAuthByPublicKeyRequestPacket(m_connParams.userName().toUtf8(),
- SshCapabilities::SshConnectionService, key, signature);
-}
-
-void SshConnectionPrivate::setAgentError()
-{
- m_error = SshAgentError;
- m_errorString = SshAgent::errorString();
- emit error(m_error);
-}
-
-void SshConnectionPrivate::connectToHost()
-{
- QSSH_ASSERT_AND_RETURN(m_state == SocketUnconnected);
-
- m_incomingData.clear();
- m_incomingPacket.reset();
- m_sendFacility.reset();
- m_error = SshNoError;
- m_ignoreNextPacket = false;
- m_errorString.clear();
- m_serverId.clear();
- m_serverHasSentDataBeforeId = false;
- m_agentSignature.clear();
- m_agentKeysUpToDate = false;
- m_pendingKeyChecks.clear();
- m_agentKeyToUse.clear();
-
- switch (m_connParams.authenticationType) {
- case SshConnectionParameters::AuthenticationTypePublicKey:
- try {
- createPrivateKey();
- break;
- } catch (const SshClientException &ex) {
- m_error = ex.error;
- m_errorString = ex.errorString;
- emit error(m_error);
- return;
- }
- case SshConnectionParameters::AuthenticationTypeAgent:
- if (SshAgent::hasError()) {
- setAgentError();
- return;
- }
- connect(&SshAgent::instance(), &SshAgent::errorOccurred,
- this, &SshConnectionPrivate::setAgentError);
- connect(&SshAgent::instance(), &SshAgent::keysUpdated,
- this, &SshConnectionPrivate::handleAgentKeysUpdated);
- SshAgent::refreshKeys();
- connect(&SshAgent::instance(), &SshAgent::signatureAvailable,
- this, &SshConnectionPrivate::handleSignatureFromAgent);
- break;
- default:
- break;
- }
-
- connect(m_socket, &QAbstractSocket::connected,
- this, &SshConnectionPrivate::handleSocketConnected);
- connect(m_socket, &QIODevice::readyRead,
- this, &SshConnectionPrivate::handleIncomingData);
- connect(m_socket,
- static_cast<void (QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
- this, &SshConnectionPrivate::handleSocketError);
- connect(m_socket, &QAbstractSocket::disconnected,
- this, &SshConnectionPrivate::handleSocketDisconnected);
- connect(&m_timeoutTimer, &QTimer::timeout, this, &SshConnectionPrivate::handleTimeout);
- m_state = SocketConnecting;
- m_keyExchangeState = NoKeyExchange;
- m_timeoutTimer.start();
- m_socket->connectToHost(m_connParams.host(), m_connParams.port());
-}
-
-void SshConnectionPrivate::closeConnection(SshErrorCode sshError,
- SshError userError, const QByteArray &serverErrorString,
- const QString &userErrorString)
-{
- // Prevent endless loops by recursive exceptions.
- if (m_state == SocketUnconnected || m_error != SshNoError)
+ if (!d->sharingEnabled)
+ emitConnected();
+ QTC_ASSERT(TemporaryDirectory::masterTemporaryDirectory(), return);
+ d->masterSocketDir.reset(new TemporaryDirectory("qtc-ssh-XXXXXX"));
+ if (!d->masterSocketDir->isValid()) {
+ emitError(tr("Cannot establish SSH connection: Failed to create temporary "
+ "directory for control socket: %1")
+ .arg(d->masterSocketDir->errorString()));
return;
-
- m_error = userError;
- m_errorString = userErrorString;
- m_timeoutTimer.stop();
- disconnect(m_socket, 0, this, 0);
- disconnect(&m_timeoutTimer, 0, this, 0);
- m_keepAliveTimer.stop();
- disconnect(&m_keepAliveTimer, 0, this, 0);
- if (m_state != SocketConnected) {
- try {
- m_channelManager->closeAllChannels(SshChannelManager::CloseAllAndReset);
- m_sendFacility.sendDisconnectPacket(sshError, serverErrorString);
- } catch (...) {} // Nothing sensible to be done here.
}
- if (m_error != SshNoError)
- emit error(userError);
- if (m_state == ConnectionEstablished)
- emit disconnected();
- if (canUseSocket())
- m_socket->disconnectFromHost();
- m_state = SocketUnconnected;
+ QStringList args = QStringList{"-M", "-N", "-o", "ControlPersist=no"} << d->connectionArgs();
+ if (!d->connParams.x11DisplayName.isEmpty())
+ args.prepend("-X");
+ qCDebug(sshLog) << "establishing connection:" << sshBinary.toUserOutput() << args;
+ d->masterProcess.start(sshBinary.toString(), args);
}
-bool SshConnectionPrivate::canUseSocket() const
+void SshConnection::emitError(const QString &reason)
{
- return m_socket->isValid()
- && m_socket->state() == QAbstractSocket::ConnectedState;
-}
-
-void SshConnectionPrivate::createPrivateKey()
-{
- if (m_connParams.privateKeyFile.isEmpty())
- throw SshClientException(SshKeyFileError, tr("No private key file given."));
- QFile keyFile(m_connParams.privateKeyFile);
- if (!keyFile.open(QIODevice::ReadOnly)) {
- throw SshClientException(SshKeyFileError,
- tr("Private key file error: %1").arg(keyFile.errorString()));
- }
- m_sendFacility.createAuthenticationKey(keyFile.readAll());
+ const State oldState = d->state;
+ d->state = Unconnected;
+ d->errorString = reason;
+ emit errorOccurred();
+ if (oldState == Connected)
+ emitDisconnected();
}
-QSharedPointer<SshRemoteProcess> SshConnectionPrivate::createRemoteProcess(const QByteArray &command)
+void SshConnection::emitConnected()
{
- return m_channelManager->createRemoteProcess(command);
-}
-
-QSharedPointer<SshRemoteProcess> SshConnectionPrivate::createRemoteShell()
-{
- return m_channelManager->createRemoteShell();
-}
-
-QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
-{
- return m_channelManager->createSftpChannel();
+ d->state = Connected;
+ emit connected();
}
-SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createDirectTunnel(const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
+void SshConnection::emitDisconnected()
{
- return m_channelManager->createDirectTunnel(originatingHost, originatingPort, remoteHost,
- remotePort);
+ d->state = Unconnected;
+ emit disconnected();
}
-SshTcpIpForwardServer::Ptr SshConnectionPrivate::createForwardServer(const QString &bindAddress,
- quint16 bindPort)
+SftpTransferPtr SshConnection::setupTransfer(
+ const FilesToTransfer &files, Internal::FileTransferType type,
+ FileTransferErrorHandling errorHandlingMode)
{
- return m_channelManager->createForwardServer(bindAddress, bindPort);
+ QTC_ASSERT(state() == Connected, return SftpTransferPtr());
+ return SftpTransferPtr(new SftpTransfer(files, type, errorHandlingMode, d->connectionArgs()));
}
-const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);
-
-} // namespace Internal
} // namespace QSsh
diff --git a/src/libs/ssh/sshconnection.h b/src/libs/ssh/sshconnection.h
index ca1e3a461a..09151795d0 100644
--- a/src/libs/ssh/sshconnection.h
+++ b/src/libs/ssh/sshconnection.h
@@ -25,54 +25,34 @@
#pragma once
-#include "ssherrors.h"
-#include "sshhostkeydatabase.h"
-
+#include "sftpdefs.h"
#include "ssh_global.h"
#include <QByteArray>
#include <QFlags>
#include <QMetaType>
#include <QObject>
-#include <QSharedPointer>
#include <QString>
#include <QHostAddress>
#include <QUrl>
+#include <memory>
+
namespace QSsh {
-class SftpChannel;
-class SshDirectTcpIpTunnel;
class SshRemoteProcess;
-class SshTcpIpForwardServer;
-
-namespace Internal { class SshConnectionPrivate; }
-
-enum SshConnectionOption {
- SshIgnoreDefaultProxy = 0x1,
- SshEnableStrictConformanceChecks = 0x2
-};
-
-Q_DECLARE_FLAGS(SshConnectionOptions, SshConnectionOption)
enum SshHostKeyCheckingMode {
SshHostKeyCheckingNone,
SshHostKeyCheckingStrict,
SshHostKeyCheckingAllowNoMatch,
- SshHostKeyCheckingAllowMismatch
};
class QSSH_EXPORT SshConnectionParameters
{
public:
enum AuthenticationType {
- AuthenticationTypePassword,
- AuthenticationTypePublicKey,
- AuthenticationTypeKeyboardInteractive,
-
- // Some servers disable "password", others disable "keyboard-interactive".
- AuthenticationTypeTryAllPasswordBasedMethods,
-
- AuthenticationTypeAgent,
+ AuthenticationTypeAll,
+ AuthenticationTypeSpecificKey,
};
SshConnectionParameters();
@@ -80,19 +60,16 @@ public:
QString host() const { return url.host(); }
quint16 port() const { return url.port(); }
QString userName() const { return url.userName(); }
- QString password() const { return url.password(); }
void setHost(const QString &host) { url.setHost(host); }
void setPort(int port) { url.setPort(port); }
void setUserName(const QString &name) { url.setUserName(name); }
- void setPassword(const QString &password) { url.setPassword(password); }
QUrl url;
QString privateKeyFile;
- int timeout; // In seconds.
- AuthenticationType authenticationType;
- SshConnectionOptions options;
- SshHostKeyCheckingMode hostKeyCheckingMode;
- SshHostKeyDatabasePtr hostKeyDatabase;
+ QString x11DisplayName;
+ int timeout = 0; // In seconds.
+ AuthenticationType authenticationType = AuthenticationTypeAll;
+ SshHostKeyCheckingMode hostKeyCheckingMode = SshHostKeyCheckingAllowNoMatch;
};
QSSH_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
@@ -101,57 +78,62 @@ QSSH_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnecti
class QSSH_EXPORT SshConnectionInfo
{
public:
- SshConnectionInfo() : localPort(0), peerPort(0) {}
+ SshConnectionInfo() = default;
SshConnectionInfo(const QHostAddress &la, quint16 lp, const QHostAddress &pa, quint16 pp)
: localAddress(la), localPort(lp), peerAddress(pa), peerPort(pp) {}
+ bool isValid() const { return peerPort != 0; }
+
QHostAddress localAddress;
- quint16 localPort;
+ quint16 localPort = 0;
QHostAddress peerAddress;
- quint16 peerPort;
+ quint16 peerPort = 0;
};
+using SshRemoteProcessPtr = std::unique_ptr<SshRemoteProcess>;
+
class QSSH_EXPORT SshConnection : public QObject
{
Q_OBJECT
public:
- enum State { Unconnected, Connecting, Connected };
+ enum State { Unconnected, Connecting, Connected, Disconnecting };
explicit SshConnection(const SshConnectionParameters &serverInfo, QObject *parent = 0);
void connectToHost();
void disconnectFromHost();
State state() const;
- SshError errorState() const;
QString errorString() const;
SshConnectionParameters connectionParameters() const;
SshConnectionInfo connectionInfo() const;
+ bool sharingEnabled() const;
~SshConnection();
- QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
- QSharedPointer<SshRemoteProcess> createRemoteShell();
- QSharedPointer<SftpChannel> createSftpChannel();
- QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
- QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
- quint16 remotePort);
-
- // -1 if an error occurred, number of channels closed otherwise.
- int closeAllChannels();
-
- int channelCount() const;
-
- QString x11DisplayName() const;
+ SshRemoteProcessPtr createRemoteProcess(const QByteArray &command);
+ SshRemoteProcessPtr createRemoteShell();
+ SftpTransferPtr createUpload(const FilesToTransfer &files,
+ FileTransferErrorHandling errorHandlingMode);
+ SftpTransferPtr createDownload(const FilesToTransfer &files,
+ FileTransferErrorHandling errorHandlingMode);
+ SftpSessionPtr createSftpSession();
signals:
void connected();
void disconnected();
void dataAvailable(const QString &message);
- void error(QSsh::SshError);
+ void errorOccurred();
private:
- Internal::SshConnectionPrivate *d;
+ void doConnectToHost();
+ void emitError(const QString &reason);
+ void emitConnected();
+ void emitDisconnected();
+ SftpTransferPtr setupTransfer(const FilesToTransfer &files, Internal::FileTransferType type,
+ FileTransferErrorHandling errorHandlingMode);
+
+ struct SshConnectionPrivate;
+ SshConnectionPrivate * const d;
};
} // namespace QSsh
diff --git a/src/libs/ssh/sshconnection_p.h b/src/libs/ssh/sshconnection_p.h
deleted file mode 100644
index 9a7afe3552..0000000000
--- a/src/libs/ssh/sshconnection_p.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshconnection.h"
-#include "sshexception_p.h"
-#include "sshincomingpacket_p.h"
-#include "sshsendfacility_p.h"
-
-#include <QHash>
-#include <QList>
-#include <QQueue>
-#include <QObject>
-#include <QPair>
-#include <QScopedPointer>
-#include <QTimer>
-
-QT_BEGIN_NAMESPACE
-class QTcpSocket;
-QT_END_NAMESPACE
-
-namespace QSsh {
-class SftpChannel;
-class SshRemoteProcess;
-class SshDirectTcpIpTunnel;
-class SshTcpIpForwardServer;
-
-namespace Internal {
-class SshChannelManager;
-
-// NOTE: When you add stuff here, don't forget to update m_packetHandlers.
-enum SshStateInternal {
- SocketUnconnected, // initial and after disconnect
- SocketConnecting, // After connectToHost()
- SocketConnected, // After socket's connected() signal
- UserAuthServiceRequested,
- WaitingForAgentKeys,
- UserAuthRequested,
- ConnectionEstablished // After service has been started
- // ...
-};
-
-enum SshKeyExchangeState {
- NoKeyExchange,
- KexInitSent,
- DhInitSent,
- NewKeysSent,
- KeyExchangeSuccess // After server's DH_REPLY message
-};
-
-class SshConnectionPrivate : public QObject
-{
- Q_OBJECT
- friend class QSsh::SshConnection;
-public:
- SshConnectionPrivate(SshConnection *conn,
- const SshConnectionParameters &serverInfo);
- ~SshConnectionPrivate();
-
- void connectToHost();
- void closeConnection(SshErrorCode sshError, SshError userError,
- const QByteArray &serverErrorString, const QString &userErrorString);
- QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
- QSharedPointer<SshRemoteProcess> createRemoteShell();
- QSharedPointer<SftpChannel> createSftpChannel();
- QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
- QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
- quint16 remotePort);
-
- SshStateInternal state() const { return m_state; }
- SshError errorState() const { return m_error; }
- QString errorString() const { return m_errorString; }
-
-signals:
- void connected();
- void disconnected();
- void dataAvailable(const QString &message);
- void error(QSsh::SshError);
-
-private:
- void handleSocketConnected();
- void handleIncomingData();
- void handleSocketError();
- void handleSocketDisconnected();
- void handleTimeout();
- void sendKeepAlivePacket();
-
- void handleAgentKeysUpdated();
- void handleSignatureFromAgent(const QByteArray &key, const QByteArray &signature, uint token);
- void tryAllAgentKeys();
- void authenticateWithPublicKey();
- void setAgentError();
-
- void handleServerId();
- void handlePackets();
- void handleCurrentPacket();
- void handleKeyExchangeInitPacket();
- void handleKeyExchangeReplyPacket();
- void handleNewKeysPacket();
- void handleServiceAcceptPacket();
- void handlePasswordExpiredPacket();
- void handleUserAuthInfoRequestPacket();
- void handleUserAuthSuccessPacket();
- void handleUserAuthFailurePacket();
- void handleUserAuthKeyOkPacket();
- void handleUserAuthBannerPacket();
- void handleUnexpectedPacket();
- void handleGlobalRequest();
- void handleDebugPacket();
- void handleUnimplementedPacket();
- void handleChannelRequest();
- void handleChannelOpen();
- void handleChannelOpenFailure();
- void handleChannelOpenConfirmation();
- void handleChannelSuccess();
- void handleChannelFailure();
- void handleChannelWindowAdjust();
- void handleChannelData();
- void handleChannelExtendedData();
- void handleChannelEof();
- void handleChannelClose();
- void handleDisconnect();
- void handleRequestSuccess();
- void handleRequestFailure();
-
- bool canUseSocket() const;
- void createPrivateKey();
-
- void sendData(const QByteArray &data);
-
- uint tokenForAgent() const;
-
- typedef void (SshConnectionPrivate::*PacketHandler)();
- typedef QList<SshStateInternal> StateList;
- void setupPacketHandlers();
- void setupPacketHandler(SshPacketType type, const StateList &states,
- PacketHandler handler);
-
- typedef QPair<StateList, PacketHandler> HandlerInStates;
- QHash<SshPacketType, HandlerInStates> m_packetHandlers;
-
- static const quint64 InvalidSeqNr;
-
- QTcpSocket *m_socket;
- SshStateInternal m_state;
- SshKeyExchangeState m_keyExchangeState;
- SshIncomingPacket m_incomingPacket;
- SshSendFacility m_sendFacility;
- SshChannelManager * const m_channelManager;
- const SshConnectionParameters m_connParams;
- QByteArray m_incomingData;
- SshError m_error;
- QString m_errorString;
- QScopedPointer<SshKeyExchange> m_keyExchange;
- QTimer m_timeoutTimer;
- QTimer m_keepAliveTimer;
- bool m_ignoreNextPacket;
- SshConnection *m_conn;
- quint64 m_lastInvalidMsgSeqNr;
- QByteArray m_serverId;
- QByteArray m_agentSignature;
- QQueue<QByteArray> m_pendingKeyChecks;
- QByteArray m_agentKeyToUse;
- bool m_serverHasSentDataBeforeId;
- bool m_triedAllPasswordBasedMethods;
- bool m_agentKeysUpToDate;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshconnectionmanager.cpp b/src/libs/ssh/sshconnectionmanager.cpp
index c6a35bd4b8..c3bb1821ee 100644
--- a/src/libs/ssh/sshconnectionmanager.cpp
+++ b/src/libs/ssh/sshconnectionmanager.cpp
@@ -26,6 +26,9 @@
#include "sshconnectionmanager.h"
#include "sshconnection.h"
+#include "sshsettings.h"
+
+#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QList>
@@ -61,7 +64,7 @@ public:
moveToThread(QCoreApplication::instance()->thread());
connect(&m_removalTimer, &QTimer::timeout,
this, &SshConnectionManager::removeInactiveConnections);
- m_removalTimer.start(150000); // For a total timeout of five minutes.
+ m_removalTimer.start(SshSettings::connectionSharingTimeout() * 1000 * 60 / 2);
}
~SshConnectionManager()
@@ -71,8 +74,8 @@ public:
delete connection.connection;
}
- QSSH_ASSERT(m_acquiredConnections.isEmpty());
- QSSH_ASSERT(m_deprecatedConnections.isEmpty());
+ QTC_CHECK(m_acquiredConnections.isEmpty());
+ QTC_CHECK(m_deprecatedConnections.isEmpty());
}
SshConnection *acquireConnection(const SshConnectionParameters &sshParams)
@@ -87,6 +90,9 @@ public:
if (connection->thread() != QThread::currentThread())
continue;
+ if (connection->sharingEnabled() != SshSettings::connectionSharingEnabled())
+ continue;
+
if (m_deprecatedConnections.contains(connection)) // we were asked to no longer use this one...
continue;
@@ -102,8 +108,6 @@ public:
continue;
if (connection->thread() != QThread::currentThread()) {
- if (connection->channelCount() != 0)
- continue;
QMetaObject::invokeMethod(this, "switchToCallerThread",
Qt::BlockingQueuedConnection,
Q_ARG(SshConnection *, connection),
@@ -129,7 +133,7 @@ public:
QMutexLocker locker(&m_listMutex);
const bool wasAquired = m_acquiredConnections.removeOne(connection);
- QSSH_ASSERT_AND_RETURN(wasAquired);
+ QTC_ASSERT(wasAquired, return);
if (m_acquiredConnections.contains(connection))
return;
@@ -139,7 +143,7 @@ public:
|| connection->state() != SshConnection::Connected) {
doDelete = true;
} else {
- QSSH_ASSERT_AND_RETURN(!m_unacquiredConnections.contains(UnaquiredConnection(connection)));
+ QTC_ASSERT(!m_unacquiredConnections.contains(UnaquiredConnection(connection)), return);
// It can happen that two or more connections with the same parameters were acquired
// if the clients were running in different threads. Only keep one of them in
@@ -151,12 +155,10 @@ public:
break;
}
}
- if (!haveConnection) {
- connection->closeAllChannels(); // Clean up after neglectful clients.
+ if (!haveConnection)
m_unacquiredConnections.append(UnaquiredConnection(connection));
- } else {
+ else
doDelete = true;
- }
}
if (doDelete) {
diff --git a/src/libs/ssh/sshcryptofacility.cpp b/src/libs/ssh/sshcryptofacility.cpp
deleted file mode 100644
index 28c72da186..0000000000
--- a/src/libs/ssh/sshcryptofacility.cpp
+++ /dev/null
@@ -1,453 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshcryptofacility_p.h"
-
-#include "opensshkeyfilereader_p.h"
-#include "sshbotanconversions_p.h"
-#include "sshcapabilities_p.h"
-#include "sshexception_p.h"
-#include "sshkeyexchange_p.h"
-#include "sshkeypasswordretriever_p.h"
-#include "sshlogging_p.h"
-#include "sshpacket_p.h"
-
-#include <botan/ber_dec.h>
-#include <botan/ctr.h>
-#include <botan/dsa.h>
-#include <botan/ec_group.h>
-#include <botan/ecdsa.h>
-#include <botan/filters.h>
-#include <botan/pkcs8.h>
-#include <botan/point_gfp.h>
-#include <botan/pubkey.h>
-#include <botan/rsa.h>
-
-#include <QDebug>
-#include <QList>
-
-#include <string>
-
-using namespace Botan;
-
-namespace QSsh {
-namespace Internal {
-
-SshAbstractCryptoFacility::SshAbstractCryptoFacility()
- : m_cipherBlockSize(0), m_macLength(0)
-{
-}
-
-SshAbstractCryptoFacility::~SshAbstractCryptoFacility() {}
-
-void SshAbstractCryptoFacility::clearKeys()
-{
- m_cipherBlockSize = 0;
- m_macLength = 0;
- m_sessionId.clear();
- m_pipe.reset(0);
- m_hMac.reset(0);
-}
-
-SshAbstractCryptoFacility::Mode SshAbstractCryptoFacility::getMode(const QByteArray &algoName)
-{
- if (algoName.endsWith("-ctr"))
- return CtrMode;
- if (algoName.endsWith("-cbc"))
- return CbcMode;
- throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
- .arg(QString::fromLatin1(algoName)));
-}
-
-void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex)
-{
- checkInvariant();
-
- if (m_sessionId.isEmpty())
- m_sessionId = kex.h();
- const QByteArray &rfcCryptAlgoName = cryptAlgoName(kex);
- std::unique_ptr<BlockCipher> cipher
- = BlockCipher::create_or_throw(botanCryptAlgoName(rfcCryptAlgoName));
- m_cipherBlockSize = static_cast<quint32>(cipher->block_size());
- const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize);
- const InitializationVector iv(convertByteArray(ivData), m_cipherBlockSize);
-
- const quint32 keySize = static_cast<quint32>(cipher->key_spec().maximum_keylength());
- const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize);
- SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize);
- Keyed_Filter * const cipherMode
- = makeCipherMode(cipher.release(), getMode(rfcCryptAlgoName), iv, cryptKey);
- m_pipe.reset(new Pipe(cipherMode));
-
- m_macLength = botanHMacKeyLen(hMacAlgoName(kex));
- const QByteArray hMacKeyData = generateHash(kex, macChar(), macLength());
- SymmetricKey hMacKey(convertByteArray(hMacKeyData), macLength());
- std::unique_ptr<HashFunction> hashFunc
- = HashFunction::create_or_throw(botanHMacAlgoName(hMacAlgoName(kex)));
- m_hMac.reset(new HMAC(hashFunc.release()));
- m_hMac->set_key(hMacKey);
-}
-
-void SshAbstractCryptoFacility::convert(QByteArray &data, quint32 offset,
- quint32 dataSize) const
-{
- Q_ASSERT(offset + dataSize <= static_cast<quint32>(data.size()));
- checkInvariant();
-
- // Session id empty => No key exchange has happened yet.
- if (dataSize == 0 || m_sessionId.isEmpty())
- return;
-
- if (dataSize % cipherBlockSize() != 0) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid packet size");
- }
- m_pipe->process_msg(reinterpret_cast<const byte *>(data.constData()) + offset,
- dataSize);
- // Can't use Pipe::LAST_MESSAGE because of a VC bug.
- quint32 bytesRead = static_cast<quint32>(m_pipe->read(
- reinterpret_cast<byte *>(data.data()) + offset, dataSize, m_pipe->message_count() - 1));
- if (bytesRead != dataSize) {
- throw SshClientException(SshInternalError,
- QLatin1String("Internal error: Botan::Pipe::read() returned unexpected value"));
- }
-}
-
-Keyed_Filter *SshAbstractCryptoFacility::makeCtrCipherMode(BlockCipher *cipher,
- const InitializationVector &iv, const SymmetricKey &key)
-{
- StreamCipher_Filter * const filter = new StreamCipher_Filter(new CTR_BE(cipher));
- filter->set_key(key);
- filter->set_iv(iv);
- return filter;
-}
-
-QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data,
- quint32 dataSize) const
-{
- return m_sessionId.isEmpty()
- ? QByteArray()
- : convertByteArray(m_hMac->process(reinterpret_cast<const byte *>(data.constData()),
- dataSize));
-}
-
-QByteArray SshAbstractCryptoFacility::generateHash(const SshKeyExchange &kex,
- char c, quint32 length)
-{
- const QByteArray &k = kex.k();
- const QByteArray &h = kex.h();
- QByteArray data(k);
- data.append(h).append(c).append(m_sessionId);
- SecureVector<byte> key
- = kex.hash()->process(convertByteArray(data), data.size());
- while (key.size() < length) {
- SecureVector<byte> tmpKey;
- tmpKey.insert(tmpKey.end(), k.cbegin(), k.cend());
- tmpKey.insert(tmpKey.end(), h.cbegin(), h.cend());
- tmpKey += key;
- key += kex.hash()->process(tmpKey);
- }
- return QByteArray(reinterpret_cast<const char *>(&key.front()), length);
-}
-
-void SshAbstractCryptoFacility::checkInvariant() const
-{
- Q_ASSERT(m_sessionId.isEmpty() == !m_pipe);
-}
-
-
-const QByteArray SshEncryptionFacility::PrivKeyFileStartLineRsa("-----BEGIN RSA PRIVATE KEY-----");
-const QByteArray SshEncryptionFacility::PrivKeyFileStartLineDsa("-----BEGIN DSA PRIVATE KEY-----");
-const QByteArray SshEncryptionFacility::PrivKeyFileEndLineRsa("-----END RSA PRIVATE KEY-----");
-const QByteArray SshEncryptionFacility::PrivKeyFileEndLineDsa("-----END DSA PRIVATE KEY-----");
-const QByteArray SshEncryptionFacility::PrivKeyFileStartLineEcdsa("-----BEGIN EC PRIVATE KEY-----");
-const QByteArray SshEncryptionFacility::PrivKeyFileEndLineEcdsa("-----END EC PRIVATE KEY-----");
-
-QByteArray SshEncryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const
-{
- return kex.encryptionAlgo();
-}
-
-QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const
-{
- return kex.hMacAlgoClientToServer();
-}
-
-Keyed_Filter *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode,
- const InitializationVector &iv, const SymmetricKey &key)
-{
- switch (mode) {
- case CbcMode:
- return get_cipher(cipher->name() + "/CBC/NoPadding", key, iv, ENCRYPTION);
- case CtrMode:
- return makeCtrCipherMode(cipher, iv, key);
- }
- return 0; // For dumb compilers.
-}
-
-void SshEncryptionFacility::encrypt(QByteArray &data) const
-{
- convert(data, 0, data.size());
-}
-
-void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFileContents)
-{
- if (privKeyFileContents == m_cachedPrivKeyContents)
- return;
-
- m_authKeyAlgoName.clear();
- qCDebug(sshLog, "%s: Key not cached, reading", Q_FUNC_INFO);
- QList<BigInt> pubKeyParams;
- QList<BigInt> allKeyParams;
- QString error1;
- QString error2;
- OpenSshKeyFileReader openSshReader(m_rng);
- if (openSshReader.parseKey(privKeyFileContents)) {
- m_authKeyAlgoName = openSshReader.keyType();
- m_authKey.reset(openSshReader.privateKey().release());
- pubKeyParams = openSshReader.publicParameters();
- allKeyParams = openSshReader.allParameters();
- } else if (!createAuthenticationKeyFromPKCS8(privKeyFileContents, pubKeyParams, allKeyParams,
- error1)
- && !createAuthenticationKeyFromOpenSSL(privKeyFileContents, pubKeyParams, allKeyParams,
- error2)) {
- qCDebug(sshLog, "%s: %s\n\t%s\n", Q_FUNC_INFO, qPrintable(error1), qPrintable(error2));
- throw SshClientException(SshKeyFileError, SSH_TR("Decoding of private key file failed: "
- "Format not understood."));
- }
-
- foreach (const BigInt &b, allKeyParams) {
- if (b.is_zero()) {
- throw SshClientException(SshKeyFileError,
- SSH_TR("Decoding of private key file failed: Invalid zero parameter."));
- }
- }
-
- m_authPubKeyBlob = AbstractSshPacket::encodeString(m_authKeyAlgoName);
- auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data());
- if (ecdsaKey) {
- m_authPubKeyBlob += AbstractSshPacket::encodeString(m_authKeyAlgoName.mid(11)); // Without "ecdsa-sha2-" prefix.
- m_authPubKeyBlob += AbstractSshPacket::encodeString(
- convertByteArray(ecdsaKey->public_point().encode(PointGFp::UNCOMPRESSED)));
- } else {
- foreach (const BigInt &b, pubKeyParams)
- m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b);
- }
- m_cachedPrivKeyContents = privKeyFileContents;
-}
-
-bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents,
- QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error)
-{
- try {
- Pipe pipe;
- pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
- m_authKey.reset(PKCS8::load_key(pipe, m_rng, &get_passphrase));
- if (auto * const dsaKey = dynamic_cast<DSA_PrivateKey *>(m_authKey.data())) {
- m_authKeyAlgoName = SshCapabilities::PubKeyDss;
- pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
- << dsaKey->group_g() << dsaKey->get_y();
- allKeyParams << pubKeyParams << dsaKey->get_x();
- } else if (auto * const rsaKey = dynamic_cast<RSA_PrivateKey *>(m_authKey.data())) {
- m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
- pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
- allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
- << rsaKey->get_d();
- } else if (auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data())) {
- const BigInt value = ecdsaKey->private_value();
- m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(
- static_cast<int>(value.bytes()));
- pubKeyParams << ecdsaKey->public_point().get_affine_x()
- << ecdsaKey->public_point().get_affine_y();
- allKeyParams << pubKeyParams << value;
- } else {
- qCWarning(sshLog, "%s: Unexpected code flow, expected success or exception.",
- Q_FUNC_INFO);
- return false;
- }
- } catch (const std::exception &ex) {
- error = QLatin1String(ex.what());
- return false;
- }
-
- return true;
-}
-
-bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents,
- QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error)
-{
- try {
- bool syntaxOk = true;
- QList<QByteArray> lines = privKeyFileContents.split('\n');
- while (lines.last().isEmpty())
- lines.removeLast();
- if (lines.count() < 3) {
- syntaxOk = false;
- } else if (lines.first() == PrivKeyFileStartLineRsa) {
- if (lines.last() != PrivKeyFileEndLineRsa)
- syntaxOk = false;
- else
- m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
- } else if (lines.first() == PrivKeyFileStartLineDsa) {
- if (lines.last() != PrivKeyFileEndLineDsa)
- syntaxOk = false;
- else
- m_authKeyAlgoName = SshCapabilities::PubKeyDss;
- } else if (lines.first() == PrivKeyFileStartLineEcdsa) {
- if (lines.last() != PrivKeyFileEndLineEcdsa)
- syntaxOk = false;
- // m_authKeyAlgoName set below, as we don't know the size yet.
- } else {
- syntaxOk = false;
- }
- if (!syntaxOk) {
- error = SSH_TR("Unexpected format.");
- return false;
- }
-
- QByteArray privateKeyBlob;
- for (int i = 1; i < lines.size() - 1; ++i)
- privateKeyBlob += lines.at(i);
- privateKeyBlob = QByteArray::fromBase64(privateKeyBlob);
-
- BER_Decoder decoder(convertByteArray(privateKeyBlob), privateKeyBlob.size());
- BER_Decoder sequence = decoder.start_cons(SEQUENCE);
- size_t version;
- sequence.decode (version);
- const size_t expectedVersion = m_authKeyAlgoName.isEmpty() ? 1 : 0;
- if (version != expectedVersion) {
- error = SSH_TR("Key encoding has version %1, expected %2.")
- .arg(version).arg(expectedVersion);
- return false;
- }
-
- if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) {
- BigInt p, q, g, y, x;
- sequence.decode (p).decode (q).decode (g).decode (y).decode (x);
- DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x);
- m_authKey.reset(dsaKey);
- pubKeyParams << p << q << g << y;
- allKeyParams << pubKeyParams << x;
- } else if (m_authKeyAlgoName == SshCapabilities::PubKeyRsa) {
- BigInt p, q, e, d, n;
- sequence.decode(n).decode(e).decode(d).decode(p).decode(q);
- m_authKey.reset(new RSA_PrivateKey(p, q, e, d, n));
- pubKeyParams << e << n;
- allKeyParams << pubKeyParams << p << q << d;
- } else {
- BigInt privKey;
- sequence.decode_octet_string_bigint(privKey);
- m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(
- static_cast<int>(privKey.bytes()));
- const EC_Group group(SshCapabilities::oid(m_authKeyAlgoName));
- auto * const key = new ECDSA_PrivateKey(m_rng, group, privKey);
- m_authKey.reset(key);
- pubKeyParams << key->public_point().get_affine_x()
- << key->public_point().get_affine_y();
- allKeyParams << pubKeyParams << privKey;
- }
-
- sequence.discard_remaining();
- sequence.verify_end();
- } catch (const std::exception &ex) {
- error = QLatin1String(ex.what());
- return false;
- }
- return true;
-}
-
-QByteArray SshEncryptionFacility::authenticationAlgorithmName() const
-{
- Q_ASSERT(m_authKey);
- return m_authKeyAlgoName;
-}
-
-QByteArray SshEncryptionFacility::authenticationKeySignature(const QByteArray &data) const
-{
- Q_ASSERT(m_authKey);
-
- QScopedPointer<PK_Signer> signer(new PK_Signer(*m_authKey, m_rng,
- botanEmsaAlgoName(m_authKeyAlgoName)));
- QByteArray dataToSign = AbstractSshPacket::encodeString(sessionId()) + data;
- QByteArray signature
- = convertByteArray(signer->sign_message(convertByteArray(dataToSign),
- dataToSign.size(), m_rng));
- if (m_authKeyAlgoName.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
- // The Botan output is not quite in the format that SSH defines.
- const int halfSize = signature.count() / 2;
- const BigInt r = BigInt::decode(convertByteArray(signature), halfSize);
- const BigInt s = BigInt::decode(convertByteArray(signature.mid(halfSize)), halfSize);
- signature = AbstractSshPacket::encodeMpInt(r) + AbstractSshPacket::encodeMpInt(s);
- }
- return AbstractSshPacket::encodeString(m_authKeyAlgoName)
- + AbstractSshPacket::encodeString(signature);
-}
-
-QByteArray SshEncryptionFacility::getRandomNumbers(int count) const
-{
- QByteArray data;
- data.resize(count);
- m_rng.randomize(convertByteArray(data), count);
- return data;
-}
-
-SshEncryptionFacility::~SshEncryptionFacility() {}
-
-
-QByteArray SshDecryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const
-{
- return kex.decryptionAlgo();
-}
-
-QByteArray SshDecryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const
-{
- return kex.hMacAlgoServerToClient();
-}
-
-Keyed_Filter *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode, const InitializationVector &iv,
- const SymmetricKey &key)
-{
- switch (mode) {
- case CbcMode:
- return get_cipher(cipher->name() + "/CBC/NoPadding", key, iv, DECRYPTION);
- case CtrMode:
- return makeCtrCipherMode(cipher, iv, key);
- }
- return 0; // For dumb compilers.
-}
-
-void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset,
- quint32 dataSize) const
-{
- convert(data, offset, dataSize);
- qCDebug(sshLog, "Decrypted data:");
- const char * const start = data.constData() + offset;
- const char * const end = start + dataSize;
- for (const char *c = start; c < end; ++c)
- qCDebug(sshLog, ) << "'" << *c << "' (0x" << (static_cast<int>(*c) & 0xff) << ")";
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshcryptofacility_p.h b/src/libs/ssh/sshcryptofacility_p.h
deleted file mode 100644
index 86df75764d..0000000000
--- a/src/libs/ssh/sshcryptofacility_p.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <botan/auto_rng.h>
-#include <botan/bigint.h>
-#include <botan/block_cipher.h>
-#include <botan/hmac.h>
-#include <botan/key_filt.h>
-#include <botan/pipe.h>
-#include <botan/pk_keys.h>
-
-#include <QByteArray>
-#include <QScopedPointer>
-
-namespace QSsh {
-namespace Internal {
-
-class SshKeyExchange;
-
-class SshAbstractCryptoFacility
-{
-public:
- virtual ~SshAbstractCryptoFacility();
-
- void clearKeys();
- void recreateKeys(const SshKeyExchange &kex);
- QByteArray generateMac(const QByteArray &data, quint32 dataSize) const;
- quint32 cipherBlockSize() const { return m_cipherBlockSize; }
- quint32 macLength() const { return m_macLength; }
- QByteArray sessionId() const { return m_sessionId; }
-
-protected:
- enum Mode { CbcMode, CtrMode };
-
- SshAbstractCryptoFacility();
- void convert(QByteArray &data, quint32 offset, quint32 dataSize) const;
- Botan::Keyed_Filter *makeCtrCipherMode(Botan::BlockCipher *cipher,
- const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
-
-private:
- SshAbstractCryptoFacility(const SshAbstractCryptoFacility &);
- SshAbstractCryptoFacility &operator=(const SshAbstractCryptoFacility &);
-
- virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const = 0;
- virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const = 0;
- virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
- Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key) = 0;
- virtual char ivChar() const = 0;
- virtual char keyChar() const = 0;
- virtual char macChar() const = 0;
-
- QByteArray generateHash(const SshKeyExchange &kex, char c, quint32 length);
- void checkInvariant() const;
- static Mode getMode(const QByteArray &algoName);
-
- QByteArray m_sessionId;
- QScopedPointer<Botan::Pipe> m_pipe;
- QScopedPointer<Botan::HMAC> m_hMac;
- quint32 m_cipherBlockSize;
- quint32 m_macLength;
-};
-
-class SshEncryptionFacility : public SshAbstractCryptoFacility
-{
-public:
- void encrypt(QByteArray &data) const;
-
- void createAuthenticationKey(const QByteArray &privKeyFileContents);
- QByteArray authenticationAlgorithmName() const;
- QByteArray authenticationPublicKey() const { return m_authPubKeyBlob; }
- QByteArray authenticationKeySignature(const QByteArray &data) const;
- QByteArray getRandomNumbers(int count) const;
-
- ~SshEncryptionFacility();
-
-private:
- virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const;
- virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const;
- virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
- Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
- virtual char ivChar() const { return 'A'; }
- virtual char keyChar() const { return 'C'; }
- virtual char macChar() const { return 'E'; }
-
- bool createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents,
- QList<Botan::BigInt> &pubKeyParams, QList<Botan::BigInt> &allKeyParams, QString &error);
- bool createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents,
- QList<Botan::BigInt> &pubKeyParams, QList<Botan::BigInt> &allKeyParams, QString &error);
-
- static const QByteArray PrivKeyFileStartLineRsa;
- static const QByteArray PrivKeyFileStartLineDsa;
- static const QByteArray PrivKeyFileEndLineRsa;
- static const QByteArray PrivKeyFileEndLineDsa;
- static const QByteArray PrivKeyFileStartLineEcdsa;
- static const QByteArray PrivKeyFileEndLineEcdsa;
-
- QByteArray m_authKeyAlgoName;
- QByteArray m_authPubKeyBlob;
- QByteArray m_cachedPrivKeyContents;
- QScopedPointer<Botan::Private_Key> m_authKey;
- mutable Botan::AutoSeeded_RNG m_rng;
-};
-
-class SshDecryptionFacility : public SshAbstractCryptoFacility
-{
-public:
- void decrypt(QByteArray &data, quint32 offset, quint32 dataSize) const;
-
-private:
- virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const;
- virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const;
- virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
- Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
- virtual char ivChar() const { return 'B'; }
- virtual char keyChar() const { return 'D'; }
- virtual char macChar() const { return 'F'; }
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshdirecttcpiptunnel.cpp b/src/libs/ssh/sshdirecttcpiptunnel.cpp
deleted file mode 100644
index 9700bd99c6..0000000000
--- a/src/libs/ssh/sshdirecttcpiptunnel.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshdirecttcpiptunnel.h"
-#include "sshdirecttcpiptunnel_p.h"
-
-#include "sshincomingpacket_p.h"
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-
-#include <QTimer>
-
-namespace QSsh {
-namespace Internal {
-
-SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId,
- const QString &originatingHost, quint16 originatingPort, const QString &remoteHost,
- quint16 remotePort, SshSendFacility &sendFacility)
- : SshTcpIpTunnelPrivate(channelId, sendFacility),
- m_originatingHost(originatingHost),
- m_originatingPort(originatingPort),
- m_remoteHost(remoteHost),
- m_remotePort(remotePort)
-{
-}
-
-void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
-{
- emit initialized();
-}
-
-} // namespace Internal
-
-using namespace Internal;
-
-SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
- SshSendFacility &sendFacility)
- : d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost,
- remotePort, sendFacility))
-{
- d->init(this);
- connect(d, &SshDirectTcpIpTunnelPrivate::initialized,
- this, &SshDirectTcpIpTunnel::initialized, Qt::QueuedConnection);
-}
-
-SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel()
-{
- delete d;
-}
-
-bool SshDirectTcpIpTunnel::atEnd() const
-{
- return QIODevice::atEnd() && d->m_data.isEmpty();
-}
-
-qint64 SshDirectTcpIpTunnel::bytesAvailable() const
-{
- return QIODevice::bytesAvailable() + d->m_data.count();
-}
-
-bool SshDirectTcpIpTunnel::canReadLine() const
-{
- return QIODevice::canReadLine() || d->m_data.contains('\n');
-}
-
-void SshDirectTcpIpTunnel::close()
-{
- d->closeChannel();
- QIODevice::close();
-}
-
-void SshDirectTcpIpTunnel::initialize()
-{
- QSSH_ASSERT_AND_RETURN(d->channelState() == AbstractSshChannel::Inactive);
-
- try {
- QIODevice::open(QIODevice::ReadWrite);
- d->m_sendFacility.sendDirectTcpIpPacket(d->localChannelId(), d->initialWindowSize(),
- d->maxPacketSize(), d->m_remoteHost.toUtf8(), d->m_remotePort,
- d->m_originatingHost.toUtf8(), d->m_originatingPort);
- d->setChannelState(AbstractSshChannel::SessionRequested);
- d->m_timeoutTimer.start(d->ReplyTimeout);
- } catch (const std::exception &e) { // Won't happen, but let's play it safe.
- qCWarning(sshLog, "Botan error: %s", e.what());
- d->closeChannel();
- }
-}
-
-qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen)
-{
- return d->readData(data, maxlen);
-}
-
-qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len)
-{
- return d->writeData(data, len);
-}
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshdirecttcpiptunnel.h b/src/libs/ssh/sshdirecttcpiptunnel.h
deleted file mode 100644
index 5d23f1cfdc..0000000000
--- a/src/libs/ssh/sshdirecttcpiptunnel.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "ssh_global.h"
-
-#include <QIODevice>
-#include <QSharedPointer>
-
-namespace QSsh {
-
-namespace Internal {
-class SshChannelManager;
-class SshDirectTcpIpTunnelPrivate;
-class SshSendFacility;
-class SshTcpIpTunnelPrivate;
-} // namespace Internal
-
-class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
-{
- Q_OBJECT
-
- friend class Internal::SshChannelManager;
- friend class Internal::SshTcpIpTunnelPrivate;
-
-public:
- typedef QSharedPointer<SshDirectTcpIpTunnel> Ptr;
-
- ~SshDirectTcpIpTunnel();
-
- // QIODevice stuff
- bool atEnd() const;
- qint64 bytesAvailable() const;
- bool canReadLine() const;
- void close();
- bool isSequential() const { return true; }
-
- void initialize();
-
-signals:
- void initialized();
- void error(const QString &reason);
-
-private:
- SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
- Internal::SshSendFacility &sendFacility);
-
- // QIODevice stuff
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
-
- Internal::SshDirectTcpIpTunnelPrivate * const d;
-};
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshdirecttcpiptunnel_p.h b/src/libs/ssh/sshdirecttcpiptunnel_p.h
deleted file mode 100644
index a2a4ac1cc5..0000000000
--- a/src/libs/ssh/sshdirecttcpiptunnel_p.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshtcpiptunnel_p.h"
-
-namespace QSsh {
-class SshDirectTcpIpTunnel;
-
-namespace Internal {
-
-class SshDirectTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
-{
- Q_OBJECT
-
- friend class QSsh::SshDirectTcpIpTunnel;
-
-public:
- explicit SshDirectTcpIpTunnelPrivate(quint32 channelId, const QString &originatingHost,
- quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
- SshSendFacility &sendFacility);
-
-signals:
- void initialized();
-
-private:
- void handleOpenSuccessInternal();
-
- const QString m_originatingHost;
- const quint16 m_originatingPort;
- const QString m_remoteHost;
- const quint16 m_remotePort;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/ssherrors.h b/src/libs/ssh/ssherrors.h
deleted file mode 100644
index f8a9e2fd95..0000000000
--- a/src/libs/ssh/ssherrors.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-#define SSHERRORS_P_H
-
-#include <QMetaType>
-
-namespace QSsh {
-
-enum SshError {
- SshNoError, SshSocketError, SshTimeoutError, SshProtocolError,
- SshHostKeyError, SshKeyFileError, SshAuthenticationError,
- SshClosedByServerError, SshAgentError, SshInternalError
-};
-
-} // namespace QSsh
-
-Q_DECLARE_METATYPE(QSsh::SshError)
diff --git a/src/libs/ssh/sshexception_p.h b/src/libs/ssh/sshexception_p.h
deleted file mode 100644
index 94697df19e..0000000000
--- a/src/libs/ssh/sshexception_p.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "ssherrors.h"
-
-#include <QByteArray>
-#include <QCoreApplication>
-#include <QString>
-
-#include <exception>
-
-namespace QSsh {
-namespace Internal {
-
-enum SshErrorCode {
- SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1,
- SSH_DISCONNECT_PROTOCOL_ERROR = 2,
- SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3,
- SSH_DISCONNECT_RESERVED = 4,
- SSH_DISCONNECT_MAC_ERROR = 5,
- SSH_DISCONNECT_COMPRESSION_ERROR = 6,
- SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7,
- SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8,
- SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9,
- SSH_DISCONNECT_CONNECTION_LOST = 10,
- SSH_DISCONNECT_BY_APPLICATION = 11,
- SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12,
- SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13,
- SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14,
- SSH_DISCONNECT_ILLEGAL_USER_NAME = 15
-};
-
-#define SSH_TR(string) QCoreApplication::translate("SshConnection", string)
-
-#define SSH_SERVER_EXCEPTION(error, errorString) \
- SshServerException((error), (errorString), SSH_TR(errorString))
-
-struct SshServerException : public std::exception
-{
- SshServerException(SshErrorCode error, const QByteArray &errorStringServer,
- const QString &errorStringUser)
- : error(error), errorStringServer(errorStringServer),
- errorStringUser(errorStringUser) {}
- const char *what() const noexcept override { return errorStringServer.constData(); }
-
- const SshErrorCode error;
- const QByteArray errorStringServer;
- const QString errorStringUser;
-};
-
-struct SshClientException : public std::exception
-{
- SshClientException(SshError error, const QString &errorString)
- : error(error), errorString(errorString), errorStringPrintable(errorString.toLocal8Bit()) {}
- const char *what() const noexcept override { return errorStringPrintable.constData(); }
-
- const SshError error;
- const QString errorString;
- const QByteArray errorStringPrintable;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshforwardedtcpiptunnel.cpp b/src/libs/ssh/sshforwardedtcpiptunnel.cpp
deleted file mode 100644
index 22442f7c80..0000000000
--- a/src/libs/ssh/sshforwardedtcpiptunnel.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshforwardedtcpiptunnel.h"
-#include "sshforwardedtcpiptunnel_p.h"
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-
-namespace QSsh {
-
-namespace Internal {
-SshForwardedTcpIpTunnelPrivate::SshForwardedTcpIpTunnelPrivate(quint32 channelId,
- SshSendFacility &sendFacility) :
- SshTcpIpTunnelPrivate(channelId, sendFacility)
-{
- setChannelState(SessionRequested);
-}
-
-void SshForwardedTcpIpTunnelPrivate::handleOpenSuccessInternal()
-{
- QSSH_ASSERT_AND_RETURN(channelState() == AbstractSshChannel::SessionEstablished);
-
- try {
- m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(),
- initialWindowSize(), maxPacketSize());
- } catch (const std::exception &e) { // Won't happen, but let's play it safe.
- qCWarning(sshLog, "Botan error: %s", e.what());
- closeChannel();
- }
-}
-
-} // namespace Internal
-
-using namespace Internal;
-
-SshForwardedTcpIpTunnel::SshForwardedTcpIpTunnel(quint32 channelId, SshSendFacility &sendFacility) :
- d(new SshForwardedTcpIpTunnelPrivate(channelId, sendFacility))
-{
- d->init(this);
-}
-
-SshForwardedTcpIpTunnel::~SshForwardedTcpIpTunnel()
-{
- delete d;
-}
-
-bool SshForwardedTcpIpTunnel::atEnd() const
-{
- return QIODevice::atEnd() && d->m_data.isEmpty();
-}
-
-qint64 SshForwardedTcpIpTunnel::bytesAvailable() const
-{
- return QIODevice::bytesAvailable() + d->m_data.count();
-}
-
-bool SshForwardedTcpIpTunnel::canReadLine() const
-{
- return QIODevice::canReadLine() || d->m_data.contains('\n');
-}
-
-void SshForwardedTcpIpTunnel::close()
-{
- d->closeChannel();
- QIODevice::close();
-}
-
-qint64 SshForwardedTcpIpTunnel::readData(char *data, qint64 maxlen)
-{
- return d->readData(data, maxlen);
-}
-
-qint64 SshForwardedTcpIpTunnel::writeData(const char *data, qint64 len)
-{
- return d->writeData(data, len);
-}
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshforwardedtcpiptunnel.h b/src/libs/ssh/sshforwardedtcpiptunnel.h
deleted file mode 100644
index cb33c30446..0000000000
--- a/src/libs/ssh/sshforwardedtcpiptunnel.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-#pragma once
-
-#include "ssh_global.h"
-#include <QIODevice>
-#include <QSharedPointer>
-
-namespace QSsh {
-
-namespace Internal {
-class SshChannelManager;
-class SshForwardedTcpIpTunnelPrivate;
-class SshSendFacility;
-class SshTcpIpTunnelPrivate;
-} // namespace Internal
-
-class QSSH_EXPORT SshForwardedTcpIpTunnel : public QIODevice
-{
- Q_OBJECT
- friend class Internal::SshChannelManager;
- friend class Internal::SshTcpIpTunnelPrivate;
-
-public:
- typedef QSharedPointer<SshForwardedTcpIpTunnel> Ptr;
- ~SshForwardedTcpIpTunnel() override;
-
- // QIODevice stuff
- bool atEnd() const override;
- qint64 bytesAvailable() const override;
- bool canReadLine() const override;
- void close() override;
- bool isSequential() const override { return true; }
-
-signals:
- void error(const QString &reason);
-
-private:
- SshForwardedTcpIpTunnel(quint32 channelId, Internal::SshSendFacility &sendFacility);
-
- // QIODevice stuff
- qint64 readData(char *data, qint64 maxlen) override;
- qint64 writeData(const char *data, qint64 len) override;
-
- Internal::SshForwardedTcpIpTunnelPrivate * const d;
-};
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshforwardedtcpiptunnel_p.h b/src/libs/ssh/sshforwardedtcpiptunnel_p.h
deleted file mode 100644
index 7b5043dac8..0000000000
--- a/src/libs/ssh/sshforwardedtcpiptunnel_p.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshforwardedtcpiptunnel.h"
-#include "sshtcpiptunnel_p.h"
-
-namespace QSsh {
-namespace Internal {
-
-class SshForwardedTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
-{
- Q_OBJECT
- friend class QSsh::SshForwardedTcpIpTunnel;
-public:
- SshForwardedTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility);
- void handleOpenSuccessInternal() override;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshhostkeydatabase.cpp b/src/libs/ssh/sshhostkeydatabase.cpp
deleted file mode 100644
index ebf1c64377..0000000000
--- a/src/libs/ssh/sshhostkeydatabase.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshhostkeydatabase.h"
-
-#include "sshlogging_p.h"
-
-#include <QByteArray>
-#include <QCoreApplication>
-#include <QDir>
-#include <QFile>
-#include <QHash>
-#include <QString>
-
-namespace QSsh {
-
-class SshHostKeyDatabase::SshHostKeyDatabasePrivate
-{
-public:
- QHash<QString, QByteArray> hostKeys;
-};
-
-SshHostKeyDatabase::SshHostKeyDatabase() : d(new SshHostKeyDatabasePrivate)
-{
-}
-
-SshHostKeyDatabase::~SshHostKeyDatabase()
-{
- delete d;
-}
-
-bool SshHostKeyDatabase::load(const QString &filePath, QString *error)
-{
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- if (error) {
- *error = QCoreApplication::translate("QSsh::Ssh",
- "Failed to open key file \"%1\" for reading: %2")
- .arg(QDir::toNativeSeparators(filePath), file.errorString());
- }
- return false;
- }
-
- d->hostKeys.clear();
- const QByteArray content = file.readAll().trimmed();
- if (content.isEmpty())
- return true;
- foreach (const QByteArray &line, content.split('\n')) {
- const QList<QByteArray> &lineData = line.trimmed().split(' ');
- if (lineData.count() != 2) {
- qCDebug(Internal::sshLog, "Unexpected line \"%s\" in file \"%s\".", line.constData(),
- qPrintable(filePath));
- continue;
- }
- d->hostKeys.insert(QString::fromUtf8(lineData.first()),
- QByteArray::fromHex(lineData.last()));
- }
-
- return true;
-}
-
-bool SshHostKeyDatabase::store(const QString &filePath, QString *error) const
-{
- QFile file(filePath);
- if (!file.open(QIODevice::WriteOnly)) {
- if (error) {
- *error = QCoreApplication::translate("QSsh::Ssh",
- "Failed to open key file \"%1\" for writing: %2")
- .arg(QDir::toNativeSeparators(filePath), file.errorString());
- }
- return false;
- }
-
- file.resize(0);
- for (auto it = d->hostKeys.constBegin(); it != d->hostKeys.constEnd(); ++it)
- file.write(it.key().toUtf8() + ' ' + it.value().toHex() + '\n');
- return true;
-}
-
-SshHostKeyDatabase::KeyLookupResult SshHostKeyDatabase::matchHostKey(const QString &hostName,
- const QByteArray &key) const
-{
- auto it = d->hostKeys.constFind(hostName);
- if (it == d->hostKeys.constEnd())
- return KeyLookupNoMatch;
- if (it.value() == key)
- return KeyLookupMatch;
- return KeyLookupMismatch;
-}
-
-void SshHostKeyDatabase::insertHostKey(const QString &hostName, const QByteArray &key)
-{
- d->hostKeys.insert(hostName, key);
-}
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshincomingpacket.cpp b/src/libs/ssh/sshincomingpacket.cpp
deleted file mode 100644
index aa3beedf6b..0000000000
--- a/src/libs/ssh/sshincomingpacket.cpp
+++ /dev/null
@@ -1,604 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshincomingpacket_p.h"
-
-#include "ssh_global.h"
-#include "sshbotanconversions_p.h"
-#include "sshcapabilities_p.h"
-#include "sshlogging_p.h"
-
-namespace QSsh {
-namespace Internal {
-
-const QByteArray SshIncomingPacket::ExitStatusType("exit-status");
-const QByteArray SshIncomingPacket::ExitSignalType("exit-signal");
-const QByteArray SshIncomingPacket::ForwardedTcpIpType("forwarded-tcpip");
-
-SshIncomingPacket::SshIncomingPacket() : m_serverSeqNr(0) { }
-
-quint32 SshIncomingPacket::cipherBlockSize() const
-{
- return qMax(m_decrypter.cipherBlockSize(), 8U);
-}
-
-quint32 SshIncomingPacket::macLength() const
-{
- return m_decrypter.macLength();
-}
-
-void SshIncomingPacket::recreateKeys(const SshKeyExchange &keyExchange)
-{
- m_decrypter.recreateKeys(keyExchange);
-}
-
-void SshIncomingPacket::reset()
-{
- clear();
- m_serverSeqNr = 0;
- m_decrypter.clearKeys();
-}
-
-void SshIncomingPacket::consumeData(QByteArray &newData)
-{
- qCDebug(sshLog, "%s: current data size = %d, new data size = %d",
- Q_FUNC_INFO, m_data.size(), newData.size());
-
- if (isComplete() || newData.isEmpty())
- return;
-
- /*
- * Until we have reached the minimum packet size, we cannot decrypt the
- * length field.
- */
- const quint32 minSize = minPacketSize();
- if (currentDataSize() < minSize) {
- const int bytesToTake
- = qMin<quint32>(minSize - currentDataSize(), newData.size());
- moveFirstBytes(m_data, newData, bytesToTake);
- qCDebug(sshLog, "Took %d bytes from new data", bytesToTake);
- if (currentDataSize() < minSize)
- return;
- }
-
- if (4 + length() + macLength() < currentDataSize())
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Server sent invalid packet.");
-
- const int bytesToTake
- = qMin<quint32>(length() + 4 + macLength() - currentDataSize(),
- newData.size());
- moveFirstBytes(m_data, newData, bytesToTake);
- qCDebug(sshLog, "Took %d bytes from new data", bytesToTake);
- if (isComplete()) {
- qCDebug(sshLog, "Message complete. Overall size: %u, payload size: %u",
- m_data.size(), m_length - paddingLength() - 1);
- decrypt();
- ++m_serverSeqNr;
- }
-}
-
-void SshIncomingPacket::decrypt()
-{
- Q_ASSERT(isComplete());
- const quint32 netDataLength = length() + 4;
- m_decrypter.decrypt(m_data, cipherBlockSize(),
- netDataLength - cipherBlockSize());
- const QByteArray &mac = m_data.mid(netDataLength, macLength());
- if (mac != generateMac(m_decrypter, m_serverSeqNr)) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_MAC_ERROR,
- "Message authentication failed.");
- }
-}
-
-void SshIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source,
- int n)
-{
- target.append(source.left(n));
- source.remove(0, n);
-}
-
-SshKeyExchangeInit SshIncomingPacket::extractKeyExchangeInitData() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_KEXINIT);
-
- SshKeyExchangeInit exchangeData;
- try {
- quint32 offset = TypeOffset + 1;
- std::memcpy(exchangeData.cookie, &m_data.constData()[offset],
- sizeof exchangeData.cookie);
- offset += sizeof exchangeData.cookie;
- exchangeData.keyAlgorithms
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.serverHostKeyAlgorithms
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.encryptionAlgorithmsClientToServer
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.encryptionAlgorithmsServerToClient
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.macAlgorithmsClientToServer
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.macAlgorithmsServerToClient
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.compressionAlgorithmsClientToServer
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.compressionAlgorithmsServerToClient
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.languagesClientToServer
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.languagesServerToClient
- = SshPacketParser::asNameList(m_data, &offset);
- exchangeData.firstKexPacketFollows
- = SshPacketParser::asBool(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- "Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet.");
- }
- return exchangeData;
-}
-
-static void getHostKeySpecificReplyData(SshKeyExchangeReply &replyData,
- const QByteArray &hostKeyAlgo, const QByteArray &input)
-{
- quint32 offset = 0;
- if (hostKeyAlgo == SshCapabilities::PubKeyDss || hostKeyAlgo == SshCapabilities::PubKeyRsa) {
- // DSS: p and q, RSA: e and n
- replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
- replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
-
- // g and y
- if (hostKeyAlgo == SshCapabilities::PubKeyDss) {
- replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
- replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
- }
- } else {
- QSSH_ASSERT_AND_RETURN(hostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix));
- if (SshPacketParser::asString(input, &offset)
- != hostKeyAlgo.mid(11)) { // Without "ecdsa-sha2-" prefix.
- throw SshPacketParseException();
- }
- replyData.q = SshPacketParser::asString(input, &offset);
- }
-}
-
-static QByteArray &padToWidth(QByteArray &data, int targetWidth)
-{
- return data.prepend(QByteArray(targetWidth - data.count(), 0));
-}
-
-SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &kexAlgo,
- const QByteArray &hostKeyAlgo) const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY);
-
- try {
- SshKeyExchangeReply replyData;
- quint32 topLevelOffset = TypeOffset + 1;
- replyData.k_s = SshPacketParser::asString(m_data, &topLevelOffset);
- quint32 k_sOffset = 0;
- if (SshPacketParser::asString(replyData.k_s, &k_sOffset) != hostKeyAlgo)
- throw SshPacketParseException();
- getHostKeySpecificReplyData(replyData, hostKeyAlgo, replyData.k_s.mid(k_sOffset));
-
- if (kexAlgo == SshCapabilities::DiffieHellmanGroup1Sha1
- || kexAlgo == SshCapabilities::DiffieHellmanGroup14Sha1) {
- replyData.f = SshPacketParser::asBigInt(m_data, &topLevelOffset);
- } else {
- QSSH_ASSERT_AND_RETURN_VALUE(kexAlgo.startsWith(SshCapabilities::EcdhKexNamePrefix),
- SshKeyExchangeReply());
- replyData.q_s = SshPacketParser::asString(m_data, &topLevelOffset);
- }
- const QByteArray fullSignature = SshPacketParser::asString(m_data, &topLevelOffset);
- quint32 sigOffset = 0;
- if (SshPacketParser::asString(fullSignature, &sigOffset) != hostKeyAlgo)
- throw SshPacketParseException();
- replyData.signatureBlob = SshPacketParser::asString(fullSignature, &sigOffset);
- if (hostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
- // Botan's PK_Verifier wants the signature in this format.
- quint32 blobOffset = 0;
- const Botan::BigInt r = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
- const Botan::BigInt s = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
- const int width = SshCapabilities::ecdsaIntegerWidthInBytes(hostKeyAlgo);
- QByteArray encodedR = convertByteArray(Botan::BigInt::encode(r));
- replyData.signatureBlob = padToWidth(encodedR, width);
- QByteArray encodedS = convertByteArray(Botan::BigInt::encode(s));
- replyData.signatureBlob += padToWidth(encodedS, width);
- }
- replyData.k_s.prepend(m_data.mid(TypeOffset + 1, 4));
- return replyData;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- "Key exchange failed: "
- "Server sent invalid key exchange reply packet.");
- }
-}
-
-SshDisconnect SshIncomingPacket::extractDisconnect() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_DISCONNECT);
-
- SshDisconnect msg;
- try {
- quint32 offset = TypeOffset + 1;
- msg.reasonCode = SshPacketParser::asUint32(m_data, &offset);
- msg.description = SshPacketParser::asUserString(m_data, &offset);
- msg.language = SshPacketParser::asString(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_DISCONNECT.");
- }
-
- return msg;
-}
-
-SshUserAuthBanner SshIncomingPacket::extractUserAuthBanner() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_USERAUTH_BANNER);
-
- try {
- SshUserAuthBanner msg;
- quint32 offset = TypeOffset + 1;
- msg.message = SshPacketParser::asUserString(m_data, &offset);
- msg.language = SshPacketParser::asString(m_data, &offset);
- return msg;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_USERAUTH_BANNER.");
- }
-}
-
-SshUserAuthInfoRequestPacket SshIncomingPacket::extractUserAuthInfoRequest() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_USERAUTH_INFO_REQUEST);
-
- try {
- SshUserAuthInfoRequestPacket msg;
- quint32 offset = TypeOffset + 1;
- msg.name = SshPacketParser::asUserString(m_data, &offset);
- msg.instruction = SshPacketParser::asUserString(m_data, &offset);
- msg.languageTag = SshPacketParser::asString(m_data, &offset);
- const quint32 promptCount = SshPacketParser::asUint32(m_data, &offset);
- msg.prompts.reserve(promptCount);
- msg.echos.reserve(promptCount);
- for (quint32 i = 0; i < promptCount; ++i) {
- msg.prompts << SshPacketParser::asUserString(m_data, &offset);
- msg.echos << SshPacketParser::asBool(m_data, &offset);
- }
- return msg;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_USERAUTH_INFO_REQUEST.");
- }
-}
-
-SshUserAuthPkOkPacket SshIncomingPacket::extractUserAuthPkOk() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_USERAUTH_PK_OK);
-
- try {
- SshUserAuthPkOkPacket msg;
- quint32 offset = TypeOffset + 1;
- msg.algoName= SshPacketParser::asString(m_data, &offset);
- msg.keyBlob = SshPacketParser::asString(m_data, &offset);
- return msg;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_USERAUTH_PK_OK.");
- }
-}
-
-SshDebug SshIncomingPacket::extractDebug() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_DEBUG);
-
- try {
- SshDebug msg;
- quint32 offset = TypeOffset + 1;
- msg.display = SshPacketParser::asBool(m_data, &offset);
- msg.message = SshPacketParser::asUserString(m_data, &offset);
- msg.language = SshPacketParser::asString(m_data, &offset);
- return msg;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_DEBUG.");
- }
-}
-
-SshRequestSuccess SshIncomingPacket::extractRequestSuccess() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_REQUEST_SUCCESS);
-
- try {
- SshRequestSuccess msg;
- quint32 offset = TypeOffset + 1;
- msg.bindPort = SshPacketParser::asUint32(m_data, &offset);
- return msg;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_REQUEST_SUCCESS.");
- }
-}
-
-SshUnimplemented SshIncomingPacket::extractUnimplemented() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_UNIMPLEMENTED);
-
- try {
- SshUnimplemented msg;
- quint32 offset = TypeOffset + 1;
- msg.invalidMsgSeqNr = SshPacketParser::asUint32(m_data, &offset);
- return msg;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_UNIMPLEMENTED.");
- }
-}
-
-SshChannelOpenGeneric SshIncomingPacket::extractChannelOpen() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN);
-
- try {
- SshChannelOpenGeneric channelOpen;
- quint32 offset = TypeOffset + 1;
- channelOpen.channelType = SshPacketParser::asString(m_data, &offset);
- channelOpen.commonData.remoteChannel = SshPacketParser::asUint32(m_data, &offset);
- channelOpen.commonData.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset);
- channelOpen.commonData.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset);
- channelOpen.typeSpecificData = m_data.mid(offset, length() - paddingLength() - offset
- + int(sizeof m_length));
- return channelOpen;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
- }
-}
-
-SshChannelOpenForwardedTcpIp SshIncomingPacket::extractChannelOpenForwardedTcpIp(
- const SshChannelOpenGeneric &genericData)
-{
- try {
- SshChannelOpenForwardedTcpIp specificData;
- specificData.common = genericData.commonData;
- quint32 offset = 0;
- specificData.remoteAddress = SshPacketParser::asString(genericData.typeSpecificData,
- &offset);
- specificData.remotePort = SshPacketParser::asUint32(genericData.typeSpecificData, &offset);
- specificData.originatorAddress = SshPacketParser::asString(genericData.typeSpecificData,
- &offset);
- specificData.originatorPort = SshPacketParser::asUint32(genericData.typeSpecificData,
- &offset);
- return specificData;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
- }
-}
-
-SshChannelOpenX11 SshIncomingPacket::extractChannelOpenX11(const SshChannelOpenGeneric &genericData)
-{
- try {
- SshChannelOpenX11 specificData;
- specificData.common = genericData.commonData;
- quint32 offset = 0;
- specificData.originatorAddress = SshPacketParser::asString(genericData.typeSpecificData,
- &offset);
- specificData.originatorPort = SshPacketParser::asUint32(genericData.typeSpecificData,
- &offset);
- return specificData;
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
- }
-}
-
-SshChannelOpenFailure SshIncomingPacket::extractChannelOpenFailure() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_FAILURE);
-
- SshChannelOpenFailure openFailure;
- try {
- quint32 offset = TypeOffset + 1;
- openFailure.localChannel = SshPacketParser::asUint32(m_data, &offset);
- openFailure.reasonCode = SshPacketParser::asUint32(m_data, &offset);
- openFailure.reasonString = QString::fromLocal8Bit(SshPacketParser::asString(m_data, &offset));
- openFailure.language = SshPacketParser::asString(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server sent invalid SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
- }
- return openFailure;
-}
-
-SshChannelOpenConfirmation SshIncomingPacket::extractChannelOpenConfirmation() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
-
- SshChannelOpenConfirmation confirmation;
- try {
- quint32 offset = TypeOffset + 1;
- confirmation.localChannel = SshPacketParser::asUint32(m_data, &offset);
- confirmation.remoteChannel = SshPacketParser::asUint32(m_data, &offset);
- confirmation.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset);
- confirmation.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server sent invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
- }
- return confirmation;
-}
-
-SshChannelWindowAdjust SshIncomingPacket::extractWindowAdjust() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_WINDOW_ADJUST);
-
- SshChannelWindowAdjust adjust;
- try {
- quint32 offset = TypeOffset + 1;
- adjust.localChannel = SshPacketParser::asUint32(m_data, &offset);
- adjust.bytesToAdd = SshPacketParser::asUint32(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_CHANNEL_WINDOW_ADJUST packet.");
- }
- return adjust;
-}
-
-SshChannelData SshIncomingPacket::extractChannelData() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_DATA);
-
- SshChannelData data;
- try {
- quint32 offset = TypeOffset + 1;
- data.localChannel = SshPacketParser::asUint32(m_data, &offset);
- data.data = SshPacketParser::asString(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_CHANNEL_DATA packet.");
- }
- return data;
-}
-
-SshChannelExtendedData SshIncomingPacket::extractChannelExtendedData() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_EXTENDED_DATA);
-
- SshChannelExtendedData data;
- try {
- quint32 offset = TypeOffset + 1;
- data.localChannel = SshPacketParser::asUint32(m_data, &offset);
- data.type = SshPacketParser::asUint32(m_data, &offset);
- data.data = SshPacketParser::asString(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_CHANNEL_EXTENDED_DATA packet.");
- }
- return data;
-}
-
-SshChannelExitStatus SshIncomingPacket::extractChannelExitStatus() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);
-
- SshChannelExitStatus exitStatus;
- try {
- quint32 offset = TypeOffset + 1;
- exitStatus.localChannel = SshPacketParser::asUint32(m_data, &offset);
- const QByteArray &type = SshPacketParser::asString(m_data, &offset);
- Q_ASSERT(type == ExitStatusType);
- Q_UNUSED(type);
- if (SshPacketParser::asBool(m_data, &offset))
- throw SshPacketParseException();
- exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid exit-status packet.");
- }
- return exitStatus;
-}
-
-SshChannelExitSignal SshIncomingPacket::extractChannelExitSignal() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);
-
- SshChannelExitSignal exitSignal;
- try {
- quint32 offset = TypeOffset + 1;
- exitSignal.localChannel = SshPacketParser::asUint32(m_data, &offset);
- const QByteArray &type = SshPacketParser::asString(m_data, &offset);
- Q_ASSERT(type == ExitSignalType);
- Q_UNUSED(type);
- if (SshPacketParser::asBool(m_data, &offset))
- throw SshPacketParseException();
- exitSignal.signal = SshPacketParser::asString(m_data, &offset);
- exitSignal.coreDumped = SshPacketParser::asBool(m_data, &offset);
- exitSignal.error = SshPacketParser::asUserString(m_data, &offset);
- exitSignal.language = SshPacketParser::asString(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid exit-signal packet.");
- }
- return exitSignal;
-}
-
-quint32 SshIncomingPacket::extractRecipientChannel() const
-{
- Q_ASSERT(isComplete());
-
- try {
- quint32 offset = TypeOffset + 1;
- return SshPacketParser::asUint32(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Server sent invalid packet.");
- }
-}
-
-QByteArray SshIncomingPacket::extractChannelRequestType() const
-{
- Q_ASSERT(isComplete());
- Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);
-
- try {
- quint32 offset = TypeOffset + 1;
- SshPacketParser::asUint32(m_data, &offset);
- return SshPacketParser::asString(m_data, &offset);
- } catch (const SshPacketParseException &) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Invalid SSH_MSG_CHANNEL_REQUEST packet.");
- }
-}
-
-void SshIncomingPacket::calculateLength() const
-{
- Q_ASSERT(currentDataSize() >= minPacketSize());
- qCDebug(sshLog, "Length field before decryption: %d-%d-%d-%d", m_data.at(0) & 0xff,
- m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff);
- m_decrypter.decrypt(m_data, 0, cipherBlockSize());
- qCDebug(sshLog, "Length field after decryption: %d-%d-%d-%d", m_data.at(0) & 0xff, m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff);
- qCDebug(sshLog, "message type = %d", m_data.at(TypeOffset));
- m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
- qCDebug(sshLog, "decrypted length is %u", m_length);
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshincomingpacket_p.h b/src/libs/ssh/sshincomingpacket_p.h
deleted file mode 100644
index d495f9ca95..0000000000
--- a/src/libs/ssh/sshincomingpacket_p.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshpacket_p.h"
-
-#include "sshcryptofacility_p.h"
-#include "sshpacketparser_p.h"
-
-#include <QStringList>
-
-namespace QSsh {
-namespace Internal {
-
-class SshKeyExchange;
-
-struct SshKeyExchangeInit
-{
- char cookie[16];
- SshNameList keyAlgorithms;
- SshNameList serverHostKeyAlgorithms;
- SshNameList encryptionAlgorithmsClientToServer;
- SshNameList encryptionAlgorithmsServerToClient;
- SshNameList macAlgorithmsClientToServer;
- SshNameList macAlgorithmsServerToClient;
- SshNameList compressionAlgorithmsClientToServer;
- SshNameList compressionAlgorithmsServerToClient;
- SshNameList languagesClientToServer;
- SshNameList languagesServerToClient;
- bool firstKexPacketFollows;
-};
-
-struct SshKeyExchangeReply
-{
- QByteArray k_s;
- QList<Botan::BigInt> hostKeyParameters; // DSS: p, q, g, y. RSA: e, n.
- QByteArray q; // For ECDSA host keys only.
- Botan::BigInt f; // For DH only.
- QByteArray q_s; // For ECDH only.
- QByteArray signatureBlob;
-};
-
-struct SshDisconnect
-{
- quint32 reasonCode;
- QString description;
- QByteArray language;
-};
-
-struct SshUserAuthBanner
-{
- QString message;
- QByteArray language;
-};
-
-struct SshUserAuthPkOkPacket
-{
- QByteArray algoName;
- QByteArray keyBlob;
-};
-
-struct SshUserAuthInfoRequestPacket
-{
- QString name;
- QString instruction;
- QByteArray languageTag;
- QStringList prompts;
- QList<bool> echos;
-};
-
-struct SshDebug
-{
- bool display;
- QString message;
- QByteArray language;
-};
-
-struct SshUnimplemented
-{
- quint32 invalidMsgSeqNr;
-};
-
-struct SshRequestSuccess
-{
- quint32 bindPort;
-};
-
-struct SshChannelOpenCommon
-{
- quint32 remoteChannel;
- quint32 remoteWindowSize;
- quint32 remoteMaxPacketSize;
-};
-
-struct SshChannelOpenGeneric
-{
- QByteArray channelType;
- SshChannelOpenCommon commonData;
- QByteArray typeSpecificData;
-};
-
-struct SshChannelOpenForwardedTcpIp
-{
- SshChannelOpenCommon common;
- QByteArray remoteAddress;
- quint32 remotePort;
- QByteArray originatorAddress;
- quint32 originatorPort;
-};
-
-struct SshChannelOpenX11
-{
- SshChannelOpenCommon common;
- QByteArray originatorAddress;
- quint32 originatorPort;
-};
-
-struct SshChannelOpenFailure
-{
- quint32 localChannel;
- quint32 reasonCode;
- QString reasonString;
- QByteArray language;
-};
-
-struct SshChannelOpenConfirmation
-{
- quint32 localChannel;
- quint32 remoteChannel;
- quint32 remoteWindowSize;
- quint32 remoteMaxPacketSize;
-};
-
-struct SshChannelWindowAdjust
-{
- quint32 localChannel;
- quint32 bytesToAdd;
-};
-
-struct SshChannelData
-{
- quint32 localChannel;
- QByteArray data;
-};
-
-struct SshChannelExtendedData
-{
- quint32 localChannel;
- quint32 type;
- QByteArray data;
-};
-
-struct SshChannelExitStatus
-{
- quint32 localChannel;
- quint32 exitStatus;
-};
-
-struct SshChannelExitSignal
-{
- quint32 localChannel;
- QByteArray signal;
- bool coreDumped;
- QString error;
- QByteArray language;
-};
-
-class SshIncomingPacket : public AbstractSshPacket
-{
-public:
- SshIncomingPacket();
-
- void consumeData(QByteArray &data);
- void recreateKeys(const SshKeyExchange &keyExchange);
- void reset();
-
- SshKeyExchangeInit extractKeyExchangeInitData() const;
- SshKeyExchangeReply extractKeyExchangeReply(const QByteArray &kexAlgo,
- const QByteArray &hostKeyAlgo) const;
- SshDisconnect extractDisconnect() const;
- SshUserAuthBanner extractUserAuthBanner() const;
- SshUserAuthInfoRequestPacket extractUserAuthInfoRequest() const;
- SshUserAuthPkOkPacket extractUserAuthPkOk() const;
- SshDebug extractDebug() const;
- SshRequestSuccess extractRequestSuccess() const;
- SshUnimplemented extractUnimplemented() const;
-
- SshChannelOpenGeneric extractChannelOpen() const;
- static SshChannelOpenForwardedTcpIp extractChannelOpenForwardedTcpIp(
- const SshChannelOpenGeneric &genericData);
- static SshChannelOpenX11 extractChannelOpenX11(const SshChannelOpenGeneric &genericData);
- SshChannelOpenFailure extractChannelOpenFailure() const;
- SshChannelOpenConfirmation extractChannelOpenConfirmation() const;
- SshChannelWindowAdjust extractWindowAdjust() const;
- SshChannelData extractChannelData() const;
- SshChannelExtendedData extractChannelExtendedData() const;
- SshChannelExitStatus extractChannelExitStatus() const;
- SshChannelExitSignal extractChannelExitSignal() const;
- quint32 extractRecipientChannel() const;
- QByteArray extractChannelRequestType() const;
-
- quint32 serverSeqNr() const { return m_serverSeqNr; }
-
- static const QByteArray ExitStatusType;
- static const QByteArray ExitSignalType;
- static const QByteArray ForwardedTcpIpType;
-
-private:
- virtual quint32 cipherBlockSize() const;
- virtual quint32 macLength() const;
- virtual void calculateLength() const;
-
- void decrypt();
- void moveFirstBytes(QByteArray &target, QByteArray &source, int n);
-
- quint32 m_serverSeqNr;
- SshDecryptionFacility m_decrypter;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshkeycreationdialog.cpp b/src/libs/ssh/sshkeycreationdialog.cpp
index 21d5114599..9c4fe8db2b 100644
--- a/src/libs/ssh/sshkeycreationdialog.cpp
+++ b/src/libs/ssh/sshkeycreationdialog.cpp
@@ -26,20 +26,23 @@
#include "sshkeycreationdialog.h"
#include "ui_sshkeycreationdialog.h"
-#include "sshkeygenerator.h"
+#include "sshsettings.h"
+#include <utils/fileutils.h>
+
+#include <QApplication>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
-#include <QApplication>
#include <QMessageBox>
+#include <QProcess>
#include <QStandardPaths>
namespace QSsh {
SshKeyCreationDialog::SshKeyCreationDialog(QWidget *parent)
- : QDialog(parent), m_keyGenerator(0), m_ui(new Ui::SshKeyCreationDialog)
+ : QDialog(parent), m_ui(new Ui::SshKeyCreationDialog)
{
m_ui->setupUi(this);
// Not using Utils::PathChooser::browseButtonLabel to avoid dependency
@@ -63,7 +66,6 @@ SshKeyCreationDialog::SshKeyCreationDialog(QWidget *parent)
SshKeyCreationDialog::~SshKeyCreationDialog()
{
- delete m_keyGenerator;
delete m_ui;
}
@@ -83,24 +85,33 @@ void SshKeyCreationDialog::keyTypeChanged()
void SshKeyCreationDialog::generateKeys()
{
- if (userForbidsOverwriting())
+ if (SshSettings::keygenFilePath().isEmpty()) {
+ showError(tr("The ssh-keygen tool was not found."));
return;
-
- const SshKeyGenerator::KeyType keyType = m_ui->rsa->isChecked()
- ? SshKeyGenerator::Rsa : SshKeyGenerator::Ecdsa;
-
- if (!m_keyGenerator)
- m_keyGenerator = new SshKeyGenerator;
-
+ }
+ if (QFileInfo::exists(privateKeyFilePath())) {
+ showError(tr("Refusing to overwrite existing private key file \"%1\".")
+ .arg(QDir::toNativeSeparators(privateKeyFilePath())));
+ return;
+ }
+ const QString keyTypeString = QLatin1String(m_ui->rsa->isChecked() ? "rsa": "ecdsa");
QApplication::setOverrideCursor(Qt::BusyCursor);
- const bool success = m_keyGenerator->generateKeys(keyType, SshKeyGenerator::Mixed,
- m_ui->comboBox->currentText().toUShort());
+ QProcess keygen;
+ const QStringList args{"-t", keyTypeString, "-b", m_ui->comboBox->currentText(),
+ "-N", QString(), "-f", privateKeyFilePath()};
+ QString errorMsg;
+ keygen.start(SshSettings::keygenFilePath().toString(), args);
+ keygen.closeWriteChannel();
+ if (!keygen.waitForStarted() || !keygen.waitForFinished())
+ errorMsg = keygen.errorString();
+ else if (keygen.exitCode() != 0)
+ errorMsg = QString::fromLocal8Bit(keygen.readAllStandardError());
+ if (!errorMsg.isEmpty()) {
+ showError(tr("The ssh-keygen tool at \"%1\" failed: %2")
+ .arg(SshSettings::keygenFilePath().toUserOutput(), errorMsg));
+ }
QApplication::restoreOverrideCursor();
-
- if (success)
- saveKeys();
- else
- QMessageBox::critical(this, tr("Key Generation Failed"), m_keyGenerator->error());
+ accept();
}
void SshKeyCreationDialog::handleBrowseButtonClicked()
@@ -117,43 +128,9 @@ void SshKeyCreationDialog::setPrivateKeyFile(const QString &filePath)
m_ui->publicKeyFileLabel->setText(filePath + QLatin1String(".pub"));
}
-void SshKeyCreationDialog::saveKeys()
-{
- const QString parentDir = QFileInfo(privateKeyFilePath()).dir().path();
- if (!QDir::root().mkpath(parentDir)) {
- QMessageBox::critical(this, tr("Cannot Save Key File"),
- tr("Failed to create directory: \"%1\".").arg(parentDir));
- return;
- }
-
- QFile privateKeyFile(privateKeyFilePath());
- if (!privateKeyFile.open(QIODevice::WriteOnly)
- || !privateKeyFile.write(m_keyGenerator->privateKey())) {
- QMessageBox::critical(this, tr("Cannot Save Private Key File"),
- tr("The private key file could not be saved: %1").arg(privateKeyFile.errorString()));
- return;
- }
- QFile::setPermissions(privateKeyFilePath(), QFile::ReadOwner | QFile::WriteOwner);
-
- QFile publicKeyFile(publicKeyFilePath());
- if (!publicKeyFile.open(QIODevice::WriteOnly)
- || !publicKeyFile.write(m_keyGenerator->publicKey())) {
- QMessageBox::critical(this, tr("Cannot Save Public Key File"),
- tr("The public key file could not be saved: %1").arg(publicKeyFile.errorString()));
- return;
- }
-
- accept();
-}
-
-bool SshKeyCreationDialog::userForbidsOverwriting()
+void SshKeyCreationDialog::showError(const QString &details)
{
- if (!QFileInfo::exists(privateKeyFilePath()) && !QFileInfo::exists(publicKeyFilePath()))
- return false;
- const QMessageBox::StandardButton reply = QMessageBox::question(this, tr("File Exists"),
- tr("There already is a file of that name. Do you want to overwrite it?"),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
- return reply != QMessageBox::Yes;
+ QMessageBox::critical(this, tr("Key Generation Failed"), details);
}
QString SshKeyCreationDialog::privateKeyFilePath() const
diff --git a/src/libs/ssh/sshkeycreationdialog.h b/src/libs/ssh/sshkeycreationdialog.h
index 31059c0213..a73fb3b3c2 100644
--- a/src/libs/ssh/sshkeycreationdialog.h
+++ b/src/libs/ssh/sshkeycreationdialog.h
@@ -30,7 +30,6 @@
#include <QDialog>
namespace QSsh {
-class SshKeyGenerator;
namespace Ui { class SshKeyCreationDialog; }
@@ -49,11 +48,9 @@ private:
void generateKeys();
void handleBrowseButtonClicked();
void setPrivateKeyFile(const QString &filePath);
- void saveKeys();
- bool userForbidsOverwriting();
+ void showError(const QString &details);
private:
- SshKeyGenerator *m_keyGenerator;
Ui::SshKeyCreationDialog *m_ui;
};
diff --git a/src/libs/ssh/sshkeyexchange.cpp b/src/libs/ssh/sshkeyexchange.cpp
deleted file mode 100644
index 3eb013f282..0000000000
--- a/src/libs/ssh/sshkeyexchange.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshkeyexchange_p.h"
-
-#include "ssh_global.h"
-#include "sshbotanconversions_p.h"
-#include "sshcapabilities_p.h"
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-#include "sshexception_p.h"
-#include "sshincomingpacket_p.h"
-
-#include <botan/auto_rng.h>
-#include <botan/dh.h>
-#include <botan/dl_group.h>
-#include <botan/dsa.h>
-#include <botan/ec_group.h>
-#include <botan/ecdh.h>
-#include <botan/ecdsa.h>
-#include <botan/lookup.h>
-#include <botan/point_gfp.h>
-#include <botan/pubkey.h>
-#include <botan/rsa.h>
-#include <botan/types.h>
-
-#include <string>
-
-using namespace Botan;
-
-namespace QSsh {
-namespace Internal {
-
-namespace {
-
- // For debugging
- void printNameList(const char *listName, const SshNameList &list)
- {
- qCDebug(sshLog, "%s:", listName);
- foreach (const QByteArray &name, list.names)
- qCDebug(sshLog, "%s", name.constData());
- }
-
- void printData(const char *name, const QByteArray &data)
- {
- qCDebug(sshLog, "The client thinks the %s has length %d and is: %s", name, data.count(),
- data.toHex().constData());
- }
-
-} // anonymous namespace
-
-SshKeyExchange::SshKeyExchange(const SshConnectionParameters &connParams,
- SshSendFacility &sendFacility)
- : m_connParams(connParams), m_sendFacility(sendFacility)
-{
-}
-
-SshKeyExchange::~SshKeyExchange() {}
-
-void SshKeyExchange::sendKexInitPacket(const QByteArray &serverId)
-{
- m_serverId = serverId;
- m_clientKexInitPayload = m_sendFacility.sendKeyExchangeInitPacket();
-}
-
-bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit)
-{
- qCDebug(sshLog, "server requests key exchange");
- serverKexInit.printRawBytes();
- SshKeyExchangeInit kexInitParams
- = serverKexInit.extractKeyExchangeInitData();
-
- printNameList("Key Algorithms", kexInitParams.keyAlgorithms);
- printNameList("Server Host Key Algorithms", kexInitParams.serverHostKeyAlgorithms);
- printNameList("Encryption algorithms client to server", kexInitParams.encryptionAlgorithmsClientToServer);
- printNameList("Encryption algorithms server to client", kexInitParams.encryptionAlgorithmsServerToClient);
- printNameList("MAC algorithms client to server", kexInitParams.macAlgorithmsClientToServer);
- printNameList("MAC algorithms server to client", kexInitParams.macAlgorithmsServerToClient);
- printNameList("Compression algorithms client to server", kexInitParams.compressionAlgorithmsClientToServer);
- printNameList("Compression algorithms client to server", kexInitParams.compressionAlgorithmsClientToServer);
- printNameList("Languages client to server", kexInitParams.languagesClientToServer);
- printNameList("Languages server to client", kexInitParams.languagesServerToClient);
- qCDebug(sshLog, "First packet follows: %d", kexInitParams.firstKexPacketFollows);
-
- m_kexAlgoName = SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods,
- kexInitParams.keyAlgorithms.names);
- m_serverHostKeyAlgo = SshCapabilities::findBestMatch(SshCapabilities::PublicKeyAlgorithms,
- kexInitParams.serverHostKeyAlgorithms.names);
- determineHashingAlgorithm(kexInitParams, true);
- determineHashingAlgorithm(kexInitParams, false);
-
- m_encryptionAlgo
- = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms,
- kexInitParams.encryptionAlgorithmsClientToServer.names);
- m_decryptionAlgo
- = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms,
- kexInitParams.encryptionAlgorithmsServerToClient.names);
- SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms,
- kexInitParams.compressionAlgorithmsClientToServer.names);
- SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms,
- kexInitParams.compressionAlgorithmsServerToClient.names);
-
- AutoSeeded_RNG rng;
- if (m_kexAlgoName.startsWith(SshCapabilities::EcdhKexNamePrefix)) {
- m_ecdhKey.reset(new ECDH_PrivateKey(rng, EC_Group(botanKeyExchangeAlgoName(m_kexAlgoName))));
- m_sendFacility.sendKeyEcdhInitPacket(convertByteArray(m_ecdhKey->public_value()));
- } else {
- m_dhKey.reset(new DH_PrivateKey(rng, DL_Group(botanKeyExchangeAlgoName(m_kexAlgoName))));
- m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y());
- }
-
- m_serverKexInitPayload = serverKexInit.payLoad();
- return kexInitParams.firstKexPacketFollows;
-}
-
-void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
- const QByteArray &clientId)
-{
-
- const SshKeyExchangeReply &reply
- = dhReply.extractKeyExchangeReply(m_kexAlgoName, m_serverHostKeyAlgo);
- if (m_dhKey && (reply.f <= 0 || reply.f >= m_dhKey->group_p())) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- "Server sent invalid f.");
- }
-
- QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId);
- concatenatedData += AbstractSshPacket::encodeString(m_serverId);
- concatenatedData += AbstractSshPacket::encodeString(m_clientKexInitPayload);
- concatenatedData += AbstractSshPacket::encodeString(m_serverKexInitPayload);
- concatenatedData += reply.k_s;
-
- printData("Client Id", AbstractSshPacket::encodeString(clientId));
- printData("Server Id", AbstractSshPacket::encodeString(m_serverId));
- printData("Client Payload", AbstractSshPacket::encodeString(m_clientKexInitPayload));
- printData("Server payload", AbstractSshPacket::encodeString(m_serverKexInitPayload));
- printData("K_S", reply.k_s);
-
- SecureVector<byte> encodedK;
- Botan::AutoSeeded_RNG rng;
- if (m_dhKey) {
- concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
- concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
- Botan::PK_Key_Agreement dhOp(*m_dhKey, rng, "Raw");
- const std::vector<std::uint8_t> encodedF = BigInt::encode(reply.f);
- encodedK = dhOp.derive_key(m_dhKey->group_p().bytes(), encodedF).bits_of();
- printData("y", AbstractSshPacket::encodeMpInt(m_dhKey->get_y()));
- printData("f", AbstractSshPacket::encodeMpInt(reply.f));
- m_dhKey.reset(nullptr);
- } else {
- Q_ASSERT(m_ecdhKey);
- concatenatedData // Q_C.
- += AbstractSshPacket::encodeString(convertByteArray(m_ecdhKey->public_value()));
- concatenatedData += AbstractSshPacket::encodeString(reply.q_s);
- Botan::PK_Key_Agreement ecdhOp(*m_ecdhKey, rng, "Raw");
- encodedK = ecdhOp.derive_key(m_ecdhKey->domain().get_p().bytes(),
- convertByteArray(reply.q_s), reply.q_s.count()).bits_of();
- m_ecdhKey.reset(nullptr);
- }
-
- const BigInt k = BigInt::decode(encodedK);
- m_k = AbstractSshPacket::encodeMpInt(k); // Roundtrip, as Botan encodes BigInts somewhat differently.
- printData("K", m_k);
- concatenatedData += m_k;
- printData("Concatenated data", concatenatedData);
-
- m_hash = HashFunction::create_or_throw(botanHMacAlgoName(hashAlgoForKexAlgo()));
- const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData),
- concatenatedData.size());
- m_h = convertByteArray(hashResult);
- printData("H", m_h);
-
- QScopedPointer<Public_Key> sigKey;
- if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) {
- const DL_Group group(reply.hostKeyParameters.at(0), reply.hostKeyParameters.at(1),
- reply.hostKeyParameters.at(2));
- DSA_PublicKey * const dsaKey
- = new DSA_PublicKey(group, reply.hostKeyParameters.at(3));
- sigKey.reset(dsaKey);
- } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) {
- RSA_PublicKey * const rsaKey
- = new RSA_PublicKey(reply.hostKeyParameters.at(1), reply.hostKeyParameters.at(0));
- sigKey.reset(rsaKey);
- } else {
- QSSH_ASSERT_AND_RETURN(m_serverHostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix));
- const EC_Group domain(SshCapabilities::oid(m_serverHostKeyAlgo));
- const PointGFp point = domain.OS2ECP(convertByteArray(reply.q), reply.q.count());
- ECDSA_PublicKey * const ecdsaKey = new ECDSA_PublicKey(domain, point);
- sigKey.reset(ecdsaKey);
- }
-
- const byte * const botanH = convertByteArray(m_h);
- const Botan::byte * const botanSig = convertByteArray(reply.signatureBlob);
- PK_Verifier verifier(*sigKey, botanEmsaAlgoName(m_serverHostKeyAlgo));
- if (!verifier.verify_message(botanH, m_h.size(), botanSig, reply.signatureBlob.size())) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- "Invalid signature in key exchange reply packet.");
- }
-
- checkHostKey(reply.k_s);
-
- m_sendFacility.sendNewKeysPacket();
-}
-
-QByteArray SshKeyExchange::hashAlgoForKexAlgo() const
-{
- if (m_kexAlgoName == SshCapabilities::EcdhNistp256)
- return SshCapabilities::HMacSha256;
- if (m_kexAlgoName == SshCapabilities::EcdhNistp384)
- return SshCapabilities::HMacSha384;
- if (m_kexAlgoName == SshCapabilities::EcdhNistp521)
- return SshCapabilities::HMacSha512;
- return SshCapabilities::HMacSha1;
-}
-
-void SshKeyExchange::determineHashingAlgorithm(const SshKeyExchangeInit &kexInit,
- bool serverToClient)
-{
- QByteArray * const algo = serverToClient ? &m_s2cHMacAlgo : &m_c2sHMacAlgo;
- const QList<QByteArray> &serverCapabilities = serverToClient
- ? kexInit.macAlgorithmsServerToClient.names
- : kexInit.macAlgorithmsClientToServer.names;
- *algo = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms, serverCapabilities);
-}
-
-void SshKeyExchange::checkHostKey(const QByteArray &hostKey)
-{
- if (m_connParams.hostKeyCheckingMode == SshHostKeyCheckingNone) {
- if (m_connParams.hostKeyDatabase)
- m_connParams.hostKeyDatabase->insertHostKey(m_connParams.host(), hostKey);
- return;
- }
-
- if (!m_connParams.hostKeyDatabase) {
- throw SshClientException(SshInternalError,
- SSH_TR("Host key database must exist "
- "if host key checking is enabled."));
- }
-
- switch (m_connParams.hostKeyDatabase->matchHostKey(m_connParams.host(), hostKey)) {
- case SshHostKeyDatabase::KeyLookupMatch:
- return; // Nothing to do.
- case SshHostKeyDatabase::KeyLookupMismatch:
- if (m_connParams.hostKeyCheckingMode != SshHostKeyCheckingAllowMismatch)
- throwHostKeyException();
- break;
- case SshHostKeyDatabase::KeyLookupNoMatch:
- if (m_connParams.hostKeyCheckingMode == SshHostKeyCheckingStrict)
- throwHostKeyException();
- break;
- }
- m_connParams.hostKeyDatabase->insertHostKey(m_connParams.host(), hostKey);
-}
-
-void SshKeyExchange::throwHostKeyException()
-{
- throw SshServerException(SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, "Host key changed",
- SSH_TR("Host key of machine \"%1\" has changed.")
- .arg(m_connParams.host()));
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshkeyexchange_p.h b/src/libs/ssh/sshkeyexchange_p.h
deleted file mode 100644
index de5828292e..0000000000
--- a/src/libs/ssh/sshkeyexchange_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshconnection.h"
-
-#include <QByteArray>
-#include <QScopedPointer>
-
-#include <memory>
-
-namespace Botan {
-class DH_PrivateKey;
-class ECDH_PrivateKey;
-class HashFunction;
-}
-
-namespace QSsh {
-namespace Internal {
-
-struct SshKeyExchangeInit;
-class SshSendFacility;
-class SshIncomingPacket;
-
-class SshKeyExchange
-{
-public:
- SshKeyExchange(const SshConnectionParameters &connParams, SshSendFacility &sendFacility);
- ~SshKeyExchange();
-
- void sendKexInitPacket(const QByteArray &serverId);
-
- // Returns true <=> the server sends a guessed package.
- bool sendDhInitPacket(const SshIncomingPacket &serverKexInit);
-
- void sendNewKeysPacket(const SshIncomingPacket &dhReply,
- const QByteArray &clientId);
-
- QByteArray k() const { return m_k; }
- QByteArray h() const { return m_h; }
- Botan::HashFunction *hash() const { return m_hash.get(); }
- QByteArray encryptionAlgo() const { return m_encryptionAlgo; }
- QByteArray decryptionAlgo() const { return m_decryptionAlgo; }
- QByteArray hMacAlgoClientToServer() const { return m_c2sHMacAlgo; }
- QByteArray hMacAlgoServerToClient() const { return m_s2cHMacAlgo; }
-
-private:
- QByteArray hashAlgoForKexAlgo() const;
- void determineHashingAlgorithm(const SshKeyExchangeInit &kexInit, bool serverToClient);
- void checkHostKey(const QByteArray &hostKey);
- Q_NORETURN void throwHostKeyException();
-
- QByteArray m_serverId;
- QByteArray m_clientKexInitPayload;
- QByteArray m_serverKexInitPayload;
- QScopedPointer<Botan::DH_PrivateKey> m_dhKey;
- QScopedPointer<Botan::ECDH_PrivateKey> m_ecdhKey;
- QByteArray m_kexAlgoName;
- QByteArray m_k;
- QByteArray m_h;
- QByteArray m_serverHostKeyAlgo;
- QByteArray m_encryptionAlgo;
- QByteArray m_decryptionAlgo;
- QByteArray m_c2sHMacAlgo;
- QByteArray m_s2cHMacAlgo;
- std::unique_ptr<Botan::HashFunction> m_hash;
- const SshConnectionParameters m_connParams;
- SshSendFacility &m_sendFacility;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshkeygenerator.cpp b/src/libs/ssh/sshkeygenerator.cpp
deleted file mode 100644
index 38828ee97f..0000000000
--- a/src/libs/ssh/sshkeygenerator.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshkeygenerator.h"
-
-#include "sshbotanconversions_p.h"
-#include "sshcapabilities_p.h"
-#include "sshlogging_p.h"
-#include "ssh_global.h"
-#include "sshpacket_p.h"
-
-#include <botan/auto_rng.h>
-#include <botan/der_enc.h>
-#include <botan/dsa.h>
-#include <botan/ecdsa.h>
-#include <botan/numthry.h>
-#include <botan/pem.h>
-#include <botan/pipe.h>
-#include <botan/pkcs8.h>
-#include <botan/rsa.h>
-#include <botan/x509_key.h>
-
-#include <QDateTime>
-#include <QInputDialog>
-
-#include <string>
-
-namespace QSsh {
-
-using namespace Botan;
-using namespace Internal;
-
-SshKeyGenerator::SshKeyGenerator() : m_type(Rsa)
-{
-}
-
-bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int keySize,
- EncryptionMode encryptionMode)
-{
- m_type = type;
- m_encryptionMode = encryptionMode;
-
- try {
- AutoSeeded_RNG rng;
- KeyPtr key;
- switch (m_type) {
- case Rsa:
- key = KeyPtr(new RSA_PrivateKey(rng, keySize));
- break;
- case Dsa:
- key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, keySize)));
- break;
- case Ecdsa: {
- const QByteArray algo = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(keySize / 8);
- key = KeyPtr(new ECDSA_PrivateKey(rng, EC_Group(SshCapabilities::oid(algo))));
- break;
- }
- }
- switch (format) {
- case Pkcs8:
- generatePkcs8KeyStrings(key, rng);
- break;
- case OpenSsl:
- generateOpenSslKeyStrings(key);
- break;
- case Mixed:
- default:
- generatePkcs8KeyString(key, true, rng);
- generateOpenSslPublicKeyString(key);
- }
- return true;
- } catch (const std::exception &e) {
- m_error = tr("Error generating key: %1").arg(QString::fromLatin1(e.what()));
- return false;
- }
-}
-
-void SshKeyGenerator::generatePkcs8KeyStrings(const KeyPtr &key, RandomNumberGenerator &rng)
-{
- generatePkcs8KeyString(key, false, rng);
- generatePkcs8KeyString(key, true, rng);
-}
-
-void SshKeyGenerator::generatePkcs8KeyString(const KeyPtr &key, bool privateKey,
- RandomNumberGenerator &rng)
-{
- Pipe pipe;
- pipe.start_msg();
- QByteArray *keyData;
- if (privateKey) {
- QString password;
- if (m_encryptionMode == DoOfferEncryption)
- password = getPassword();
- if (!password.isEmpty())
- pipe.write(PKCS8::PEM_encode(*key, rng, password.toLocal8Bit().data()));
- else
- pipe.write(PKCS8::PEM_encode(*key));
- keyData = &m_privateKey;
- } else {
- pipe.write(X509::PEM_encode(*key));
- keyData = &m_publicKey;
- }
- pipe.end_msg();
- keyData->resize(static_cast<int>(pipe.remaining(pipe.message_count() - 1)));
- if (pipe.read(convertByteArray(*keyData), keyData->size(), pipe.message_count() - 1)
- != std::size_t(keyData->size())) {
- qCWarning(sshLog) << "short read from botan pipe";
- }
-}
-
-void SshKeyGenerator::generateOpenSslKeyStrings(const KeyPtr &key)
-{
- generateOpenSslPublicKeyString(key);
- generateOpenSslPrivateKeyString(key);
-}
-
-void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key)
-{
- QList<BigInt> params;
- QByteArray keyId;
- QByteArray q;
- switch (m_type) {
- case Rsa: {
- const QSharedPointer<RSA_PrivateKey> rsaKey = key.dynamicCast<RSA_PrivateKey>();
- params << rsaKey->get_e() << rsaKey->get_n();
- keyId = SshCapabilities::PubKeyRsa;
- break;
- }
- case Dsa: {
- const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
- params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y();
- keyId = SshCapabilities::PubKeyDss;
- break;
- }
- case Ecdsa: {
- const auto ecdsaKey = key.dynamicCast<ECDSA_PrivateKey>();
- q = convertByteArray(ecdsaKey->public_point().encode(PointGFp::UNCOMPRESSED));
- keyId = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(
- static_cast<int>(ecdsaKey->private_value().bytes()));
- break;
- }
- }
-
- QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId);
- foreach (const BigInt &b, params)
- publicKeyBlob += AbstractSshPacket::encodeMpInt(b);
- if (!q.isEmpty()) {
- publicKeyBlob += AbstractSshPacket::encodeString(keyId.mid(11)); // Without "ecdsa-sha2-" prefix.
- publicKeyBlob += AbstractSshPacket::encodeString(q);
- }
- publicKeyBlob = publicKeyBlob.toBase64();
- const QByteArray id = "QtCreator/"
- + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8();
- m_publicKey = keyId + ' ' + publicKeyBlob + ' ' + id;
-}
-
-void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key)
-{
- QList<BigInt> params;
- const char *label = "";
- switch (m_type) {
- case Rsa: {
- const QSharedPointer<RSA_PrivateKey> rsaKey
- = key.dynamicCast<RSA_PrivateKey>();
- params << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() << rsaKey->get_p()
- << rsaKey->get_q();
- const BigInt dmp1 = rsaKey->get_d() % (rsaKey->get_p() - 1);
- const BigInt dmq1 = rsaKey->get_d() % (rsaKey->get_q() - 1);
- const BigInt iqmp = inverse_mod(rsaKey->get_q(), rsaKey->get_p());
- params << dmp1 << dmq1 << iqmp;
- label = "RSA PRIVATE KEY";
- break;
- }
- case Dsa: {
- const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
- params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y()
- << dsaKey->get_x();
- label = "DSA PRIVATE KEY";
- break;
- }
- case Ecdsa:
- params << key.dynamicCast<ECDSA_PrivateKey>()->private_value();
- label = "EC PRIVATE KEY";
- break;
- }
-
- DER_Encoder encoder;
- encoder.start_cons(SEQUENCE).encode(size_t(0));
- foreach (const BigInt &b, params)
- encoder.encode(b);
- encoder.end_cons();
- m_privateKey = QByteArray(PEM_Code::encode (encoder.get_contents(), label).c_str());
-}
-
-QString SshKeyGenerator::getPassword() const
-{
- QInputDialog d;
- d.setInputMode(QInputDialog::TextInput);
- d.setTextEchoMode(QLineEdit::Password);
- d.setWindowTitle(tr("Password for Private Key"));
- d.setLabelText(tr("It is recommended that you secure your private key\n"
- "with a password, which you can enter below."));
- d.setOkButtonText(tr("Encrypt Key File"));
- d.setCancelButtonText(tr("Do Not Encrypt Key File"));
- int result = QDialog::Accepted;
- QString password;
- while (result == QDialog::Accepted && password.isEmpty()) {
- result = d.exec();
- password = d.textValue();
- }
- return result == QDialog::Accepted ? password : QString();
-}
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshkeygenerator.h b/src/libs/ssh/sshkeygenerator.h
deleted file mode 100644
index 483614429e..0000000000
--- a/src/libs/ssh/sshkeygenerator.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "ssh_global.h"
-
-#include <QCoreApplication>
-#include <QSharedPointer>
-
-namespace Botan {
- class Private_Key;
- class RandomNumberGenerator;
-}
-
-namespace QSsh {
-
-class QSSH_EXPORT SshKeyGenerator
-{
- Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator)
-public:
- enum KeyType { Rsa, Dsa, Ecdsa };
- enum PrivateKeyFormat { Pkcs8, OpenSsl, Mixed };
- enum EncryptionMode { DoOfferEncryption, DoNotOfferEncryption }; // Only relevant for Pkcs8 format.
-
- SshKeyGenerator();
- bool generateKeys(KeyType type, PrivateKeyFormat format, int keySize,
- EncryptionMode encryptionMode = DoOfferEncryption);
-
- QString error() const { return m_error; }
- QByteArray privateKey() const { return m_privateKey; }
- QByteArray publicKey() const { return m_publicKey; }
- KeyType type() const { return m_type; }
-
-private:
- typedef QSharedPointer<Botan::Private_Key> KeyPtr;
-
- void generatePkcs8KeyStrings(const KeyPtr &key, Botan::RandomNumberGenerator &rng);
- void generatePkcs8KeyString(const KeyPtr &key, bool privateKey,
- Botan::RandomNumberGenerator &rng);
- void generateOpenSslKeyStrings(const KeyPtr &key);
- void generateOpenSslPrivateKeyString(const KeyPtr &key);
- void generateOpenSslPublicKeyString(const KeyPtr &key);
- QString getPassword() const;
-
- QString m_error;
- QByteArray m_publicKey;
- QByteArray m_privateKey;
- KeyType m_type;
- EncryptionMode m_encryptionMode;
-};
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshkeypasswordretriever.cpp b/src/libs/ssh/sshkeypasswordretriever.cpp
deleted file mode 100644
index 6631404a03..0000000000
--- a/src/libs/ssh/sshkeypasswordretriever.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshkeypasswordretriever_p.h"
-
-#include <QString>
-#include <QApplication>
-#include <QInputDialog>
-
-#include <iostream>
-
-namespace QSsh {
-namespace Internal {
-
-std::string get_passphrase()
-{
- const bool hasGui = dynamic_cast<QApplication *>(QApplication::instance());
- if (hasGui) {
- const QString &password = QInputDialog::getText(0,
- QCoreApplication::translate("QSsh::Ssh", "Password Required"),
- QCoreApplication::translate("QSsh::Ssh", "Please enter the password for your private key."),
- QLineEdit::Password, QString());
- return std::string(password.toLocal8Bit().data());
- } else {
- std::string password;
- std::cout << "Please enter the password for your private key (set echo off beforehand!): " << std::flush;
- std::cin >> password;
- return password;
- }
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshoutgoingpacket.cpp b/src/libs/ssh/sshoutgoingpacket.cpp
deleted file mode 100644
index ac25e0c980..0000000000
--- a/src/libs/ssh/sshoutgoingpacket.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshoutgoingpacket_p.h"
-
-#include "sshagent_p.h"
-#include "sshcapabilities_p.h"
-#include "sshcryptofacility_p.h"
-#include "sshlogging_p.h"
-#include "sshpacketparser_p.h"
-
-#include <QtEndian>
-
-namespace QSsh {
-namespace Internal {
-
-SshOutgoingPacket::SshOutgoingPacket(const SshEncryptionFacility &encrypter,
- const quint32 &seqNr) : m_encrypter(encrypter), m_seqNr(seqNr)
-{
-}
-
-quint32 SshOutgoingPacket::cipherBlockSize() const
-{
- return qMax(m_encrypter.cipherBlockSize(), 4U);
-}
-
-quint32 SshOutgoingPacket::macLength() const
-{
- return m_encrypter.macLength();
-}
-
-QByteArray SshOutgoingPacket::generateKeyExchangeInitPacket()
-{
- const QByteArray &supportedkeyExchangeMethods
- = encodeNameList(SshCapabilities::KeyExchangeMethods);
- const QByteArray &supportedPublicKeyAlgorithms
- = encodeNameList(SshCapabilities::PublicKeyAlgorithms);
- const QByteArray &supportedEncryptionAlgorithms
- = encodeNameList(SshCapabilities::EncryptionAlgorithms);
- const QByteArray &supportedMacAlgorithms
- = encodeNameList(SshCapabilities::MacAlgorithms);
- const QByteArray &supportedCompressionAlgorithms
- = encodeNameList(SshCapabilities::CompressionAlgorithms);
- const QByteArray &supportedLanguages = encodeNameList(QList<QByteArray>());
-
- init(SSH_MSG_KEXINIT);
- m_data += m_encrypter.getRandomNumbers(16);
- m_data.append(supportedkeyExchangeMethods);
- m_data.append(supportedPublicKeyAlgorithms);
- m_data.append(supportedEncryptionAlgorithms)
- .append(supportedEncryptionAlgorithms);
- m_data.append(supportedMacAlgorithms).append(supportedMacAlgorithms);
- m_data.append(supportedCompressionAlgorithms)
- .append(supportedCompressionAlgorithms);
- m_data.append(supportedLanguages).append(supportedLanguages);
- appendBool(false); // No guessed packet.
- m_data.append(QByteArray(4, 0)); // Reserved.
- QByteArray payload = m_data.mid(PayloadOffset);
- finalize();
- return payload;
-}
-
-void SshOutgoingPacket::generateKeyDhInitPacket(const Botan::BigInt &e)
-{
- init(SSH_MSG_KEXDH_INIT).appendMpInt(e).finalize();
-}
-
-void SshOutgoingPacket::generateKeyEcdhInitPacket(const QByteArray &clientQ)
-{
- init(SSH_MSG_KEX_ECDH_INIT).appendString(clientQ).finalize();
-}
-
-void SshOutgoingPacket::generateNewKeysPacket()
-{
- init(SSH_MSG_NEWKEYS).finalize();
-}
-
-void SshOutgoingPacket::generateUserAuthServiceRequestPacket()
-{
- generateServiceRequest("ssh-userauth");
-}
-
-void SshOutgoingPacket::generateServiceRequest(const QByteArray &service)
-{
- init(SSH_MSG_SERVICE_REQUEST).appendString(service).finalize();
-}
-
-void SshOutgoingPacket::generateUserAuthByPasswordRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &pwd)
-{
- init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service);
- if (pwd.isEmpty())
- appendString("none"); // RFC 4252, 5.2
- else
- appendString("password").appendBool(false).appendString(pwd);
- finalize();
-}
-
-void SshOutgoingPacket::generateUserAuthByPublicKeyRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &key, const QByteArray &signature)
-{
- init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
- .appendString("publickey").appendBool(true);
- if (!key.isEmpty()) {
- appendString(SshPacketParser::asString(key, quint32(0)));
- appendString(key);
- appendString(signature);
- } else {
- appendString(m_encrypter.authenticationAlgorithmName());
- appendString(m_encrypter.authenticationPublicKey());
- const QByteArray &dataToSign = m_data.mid(PayloadOffset);
- appendString(m_encrypter.authenticationKeySignature(dataToSign));
- }
- finalize();
-}
-
-void SshOutgoingPacket::generateQueryPublicKeyPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &publicKey)
-{
- // Name extraction cannot fail, we already verified this when receiving the key
- // from the agent.
- const QByteArray algoName = SshPacketParser::asString(publicKey, quint32(0));
- SshOutgoingPacket packetToSign(m_encrypter, m_seqNr);
- packetToSign.init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
- .appendString("publickey").appendBool(true).appendString(algoName)
- .appendString(publicKey);
- const QByteArray &dataToSign
- = encodeString(m_encrypter.sessionId()) + packetToSign.m_data.mid(PayloadOffset);
- SshAgent::storeDataToSign(publicKey, dataToSign, qHash(m_encrypter.sessionId()));
- init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
- .appendString("publickey").appendBool(false).appendString(algoName)
- .appendString(publicKey).finalize();
-}
-
-void SshOutgoingPacket::generateUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user,
- const QByteArray &service)
-{
- // RFC 4256, 3.1
- init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
- .appendString("keyboard-interactive")
- .appendString(QByteArray()) // Language tag. Deprecated and should be empty
- .appendString(QByteArray()) // Submethods.
- .finalize();
-}
-
-void SshOutgoingPacket::generateUserAuthInfoResponsePacket(const QStringList &responses)
-{
- // RFC 4256, 3.4
- init(SSH_MSG_USERAUTH_INFO_RESPONSE).appendInt(responses.count());
- foreach (const QString &response, responses)
- appendString(response.toUtf8());
- finalize();
-}
-
-void SshOutgoingPacket::generateRequestFailurePacket()
-{
- init(SSH_MSG_REQUEST_FAILURE).finalize();
-}
-
-void SshOutgoingPacket::generateIgnorePacket()
-{
- init(SSH_MSG_IGNORE).finalize();
-}
-
-void SshOutgoingPacket::generateInvalidMessagePacket()
-{
- init(SSH_MSG_INVALID).finalize();
-}
-
-void SshOutgoingPacket::generateSessionPacket(quint32 channelId,
- quint32 windowSize, quint32 maxPacketSize)
-{
- init(SSH_MSG_CHANNEL_OPEN).appendString("session").appendInt(channelId)
- .appendInt(windowSize).appendInt(maxPacketSize).finalize();
-}
-
-void SshOutgoingPacket::generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
- quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
- const QByteArray &localIpAddress, quint32 localPort)
-{
- init(SSH_MSG_CHANNEL_OPEN).appendString("direct-tcpip").appendInt(channelId)
- .appendInt(windowSize).appendInt(maxPacketSize).appendString(remoteHost)
- .appendInt(remotePort).appendString(localIpAddress).appendInt(localPort).finalize();
-}
-
-void SshOutgoingPacket::generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
-{
- init(SSH_MSG_GLOBAL_REQUEST).appendString("tcpip-forward").appendBool(true)
- .appendString(bindAddress).appendInt(bindPort).finalize();
-}
-
-void SshOutgoingPacket::generateCancelTcpIpForwardPacket(const QByteArray &bindAddress,
- quint32 bindPort)
-{
- init(SSH_MSG_GLOBAL_REQUEST).appendString("cancel-tcpip-forward").appendBool(true)
- .appendString(bindAddress).appendInt(bindPort).finalize();
-}
-
-void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel,
- const QByteArray &var, const QByteArray &value)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("env")
- .appendBool(false).appendString(var).appendString(value).finalize();
-}
-
-void SshOutgoingPacket::generateX11ForwardingPacket(quint32 remoteChannel,
- const QByteArray &protocol, const QByteArray &cookie, quint32 screenNumber)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("x11-req")
- .appendBool(false).appendBool(false).appendString(protocol)
- .appendString(cookie).appendInt(screenNumber).finalize();
-}
-
-void SshOutgoingPacket::generatePtyRequestPacket(quint32 remoteChannel,
- const SshPseudoTerminal &terminal)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
- .appendString("pty-req").appendBool(false)
- .appendString(terminal.termType).appendInt(terminal.columnCount)
- .appendInt(terminal.rowCount).appendInt(0).appendInt(0);
- QByteArray modeString;
- for (SshPseudoTerminal::ModeMap::ConstIterator it = terminal.modes.constBegin();
- it != terminal.modes.constEnd(); ++it) {
- modeString += char(it.key());
- modeString += encodeInt(it.value());
- }
- modeString += char(0); // TTY_OP_END
- appendString(modeString).finalize();
-}
-
-void SshOutgoingPacket::generateExecPacket(quint32 remoteChannel,
- const QByteArray &command)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("exec")
- .appendBool(true).appendString(command).finalize();
-}
-
-void SshOutgoingPacket::generateShellPacket(quint32 remoteChannel)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("shell")
- .appendBool(true).finalize();
-}
-
-void SshOutgoingPacket::generateSftpPacket(quint32 remoteChannel)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
- .appendString("subsystem").appendBool(true).appendString("sftp")
- .finalize();
-}
-
-void SshOutgoingPacket::generateWindowAdjustPacket(quint32 remoteChannel,
- quint32 bytesToAdd)
-{
- init(SSH_MSG_CHANNEL_WINDOW_ADJUST).appendInt(remoteChannel)
- .appendInt(bytesToAdd).finalize();
-}
-
-void SshOutgoingPacket::generateChannelDataPacket(quint32 remoteChannel,
- const QByteArray &data)
-{
- init(SSH_MSG_CHANNEL_DATA).appendInt(remoteChannel).appendString(data)
- .finalize();
-}
-
-void SshOutgoingPacket::generateChannelSignalPacket(quint32 remoteChannel,
- const QByteArray &signalName)
-{
- init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
- .appendString("signal").appendBool(false).appendString(signalName)
- .finalize();
-}
-
-void SshOutgoingPacket::generateChannelEofPacket(quint32 remoteChannel)
-{
- init(SSH_MSG_CHANNEL_EOF).appendInt(remoteChannel).finalize();
-}
-
-void SshOutgoingPacket::generateChannelClosePacket(quint32 remoteChannel)
-{
- init(SSH_MSG_CHANNEL_CLOSE).appendInt(remoteChannel).finalize();
-}
-
-void SshOutgoingPacket::generateChannelOpenConfirmationPacket(quint32 remoteChannel,
- quint32 localChannel,
- quint32 localWindowSize,
- quint32 maxPacketSize)
-{
- init(SSH_MSG_CHANNEL_OPEN_CONFIRMATION).appendInt(remoteChannel).appendInt(localChannel)
- .appendInt(localWindowSize).appendInt(maxPacketSize).finalize();
-}
-
-void SshOutgoingPacket::generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
- const QByteArray &reasonString)
-{
- init(SSH_MSG_CHANNEL_OPEN_FAILURE).appendInt(remoteChannel).appendInt(reason)
- .appendString(reasonString).appendString(QByteArray()).finalize();
-}
-
-void SshOutgoingPacket::generateDisconnectPacket(SshErrorCode reason,
- const QByteArray &reasonString)
-{
- init(SSH_MSG_DISCONNECT).appendInt(reason).appendString(reasonString)
- .appendString(QByteArray()).finalize();
-}
-
-void SshOutgoingPacket::generateMsgUnimplementedPacket(quint32 serverSeqNr)
-{
- init(SSH_MSG_UNIMPLEMENTED).appendInt(serverSeqNr).finalize();
-}
-
-SshOutgoingPacket &SshOutgoingPacket::appendInt(quint32 val)
-{
- m_data.append(encodeInt(val));
- return *this;
-}
-
-SshOutgoingPacket &SshOutgoingPacket::appendMpInt(const Botan::BigInt &number)
-{
- m_data.append(encodeMpInt(number));
- return *this;
-}
-
-SshOutgoingPacket &SshOutgoingPacket::appendBool(bool b)
-{
- m_data += static_cast<char>(b);
- return *this;
-}
-
-SshOutgoingPacket &SshOutgoingPacket::appendString(const QByteArray &string)
-{
- m_data.append(encodeString(string));
- return *this;
-}
-
-SshOutgoingPacket &SshOutgoingPacket::init(SshPacketType type)
-{
- m_data.resize(TypeOffset + 1);
- m_data[TypeOffset] = type;
- return *this;
-}
-
-SshOutgoingPacket &SshOutgoingPacket::setPadding()
-{
- m_data += m_encrypter.getRandomNumbers(MinPaddingLength);
- int padLength = MinPaddingLength;
- const int divisor = sizeDivisor();
- const int mod = m_data.size() % divisor;
- padLength += divisor - mod;
- m_data += m_encrypter.getRandomNumbers(padLength - MinPaddingLength);
- m_data[PaddingLengthOffset] = padLength;
- return *this;
-}
-
-SshOutgoingPacket &SshOutgoingPacket::encrypt()
-{
- const QByteArray &mac
- = generateMac(m_encrypter, m_seqNr);
- m_encrypter.encrypt(m_data);
- m_data += mac;
- return *this;
-}
-
-void SshOutgoingPacket::finalize()
-{
- setPadding();
- setLengthField(m_data);
- m_length = m_data.size() - 4;
- qCDebug(sshLog, "Encrypting packet of type %u", m_data.at(TypeOffset));
- encrypt();
- qCDebug(sshLog, "Sending packet of size %d", rawData().count());
- Q_ASSERT(isComplete());
-}
-
-int SshOutgoingPacket::sizeDivisor() const
-{
- return qMax(cipherBlockSize(), 8U);
-}
-
-QByteArray SshOutgoingPacket::encodeNameList(const QList<QByteArray> &list)
-{
- QByteArray data;
- data.resize(4);
- for (int i = 0; i < list.count(); ++i) {
- if (i > 0)
- data.append(',');
- data.append(list.at(i));
- }
- AbstractSshPacket::setLengthField(data);
- return data;
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshoutgoingpacket_p.h b/src/libs/ssh/sshoutgoingpacket_p.h
deleted file mode 100644
index b9392279aa..0000000000
--- a/src/libs/ssh/sshoutgoingpacket_p.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshpacket_p.h"
-
-#include "sshpseudoterminal.h"
-
-#include <QStringList>
-
-namespace QSsh {
-namespace Internal {
-
-class SshEncryptionFacility;
-
-class SshOutgoingPacket : public AbstractSshPacket
-{
-public:
- SshOutgoingPacket(const SshEncryptionFacility &encrypter,
- const quint32 &seqNr);
-
- QByteArray generateKeyExchangeInitPacket(); // Returns payload.
- void generateKeyDhInitPacket(const Botan::BigInt &e);
- void generateKeyEcdhInitPacket(const QByteArray &clientQ);
- void generateNewKeysPacket();
- void generateDisconnectPacket(SshErrorCode reason,
- const QByteArray &reasonString);
- void generateMsgUnimplementedPacket(quint32 serverSeqNr);
- void generateUserAuthServiceRequestPacket();
- void generateUserAuthByPasswordRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &pwd);
- void generateUserAuthByPublicKeyRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &key, const QByteArray &signature);
- void generateQueryPublicKeyPacket(const QByteArray &user, const QByteArray &service,
- const QByteArray &publicKey);
- void generateUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user,
- const QByteArray &service);
- void generateUserAuthInfoResponsePacket(const QStringList &responses);
- void generateRequestFailurePacket();
- void generateIgnorePacket();
- void generateInvalidMessagePacket();
- void generateSessionPacket(quint32 channelId, quint32 windowSize,
- quint32 maxPacketSize);
- void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
- quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
- const QByteArray &localIpAddress, quint32 localPort);
- void generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
- void generateCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
- void generateEnvPacket(quint32 remoteChannel, const QByteArray &var,
- const QByteArray &value);
- void generateX11ForwardingPacket(quint32 remoteChannel, const QByteArray &protocol,
- const QByteArray &cookie, quint32 screenNumber);
- void generatePtyRequestPacket(quint32 remoteChannel,
- const SshPseudoTerminal &terminal);
- void generateExecPacket(quint32 remoteChannel, const QByteArray &command);
- void generateShellPacket(quint32 remoteChannel);
- void generateSftpPacket(quint32 remoteChannel);
- void generateWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd);
- void generateChannelDataPacket(quint32 remoteChannel,
- const QByteArray &data);
- void generateChannelSignalPacket(quint32 remoteChannel,
- const QByteArray &signalName);
- void generateChannelEofPacket(quint32 remoteChannel);
- void generateChannelClosePacket(quint32 remoteChannel);
- void generateChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
- quint32 localWindowSize, quint32 maxPackeSize);
- void generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
- const QByteArray &reasonString);
-
-private:
- virtual quint32 cipherBlockSize() const;
- virtual quint32 macLength() const;
-
- static QByteArray encodeNameList(const QList<QByteArray> &list);
-
- void generateServiceRequest(const QByteArray &service);
-
- SshOutgoingPacket &init(SshPacketType type);
- SshOutgoingPacket &setPadding();
- SshOutgoingPacket &encrypt();
- void finalize();
-
- SshOutgoingPacket &appendInt(quint32 val);
- SshOutgoingPacket &appendString(const QByteArray &string);
- SshOutgoingPacket &appendMpInt(const Botan::BigInt &number);
- SshOutgoingPacket &appendBool(bool b);
- int sizeDivisor() const;
-
- const SshEncryptionFacility &m_encrypter;
- const quint32 &m_seqNr;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshpacket.cpp b/src/libs/ssh/sshpacket.cpp
deleted file mode 100644
index 1b35037fb0..0000000000
--- a/src/libs/ssh/sshpacket.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshpacket_p.h"
-
-#include "sshcapabilities_p.h"
-#include "sshcryptofacility_p.h"
-#include "sshexception_p.h"
-#include "sshlogging_p.h"
-#include "sshpacketparser_p.h"
-
-#include <QDebug>
-
-#include <cctype>
-
-namespace QSsh {
-namespace Internal {
-
-const quint32 AbstractSshPacket::PaddingLengthOffset = 4;
-const quint32 AbstractSshPacket::PayloadOffset = PaddingLengthOffset + 1;
-const quint32 AbstractSshPacket::TypeOffset = PayloadOffset;
-const quint32 AbstractSshPacket::MinPaddingLength = 4;
-
-static void printByteArray(const QByteArray &data)
-{
- qCDebug(sshLog, "%s", data.toHex().constData());
-}
-
-
-AbstractSshPacket::AbstractSshPacket() : m_length(0) { }
-AbstractSshPacket::~AbstractSshPacket() {}
-
-bool AbstractSshPacket::isComplete() const
-{
- if (currentDataSize() < minPacketSize())
- return false;
- return 4 + length() + macLength() == currentDataSize();
-}
-
-void AbstractSshPacket::clear()
-{
- m_data.clear();
- m_length = 0;
-}
-
-SshPacketType AbstractSshPacket::type() const
-{
- Q_ASSERT(isComplete());
- return static_cast<SshPacketType>(m_data.at(TypeOffset));
-}
-
-QByteArray AbstractSshPacket::payLoad() const
-{
- return QByteArray(m_data.constData() + PayloadOffset,
- length() - paddingLength() - 1);
-}
-
-void AbstractSshPacket::printRawBytes() const
-{
- printByteArray(m_data);
-}
-
-QByteArray AbstractSshPacket::encodeString(const QByteArray &string)
-{
- QByteArray data;
- data.resize(4);
- data += string;
- setLengthField(data);
- return data;
-}
-
-QByteArray AbstractSshPacket::encodeMpInt(const Botan::BigInt &number)
-{
- if (number.is_zero())
- return QByteArray(4, 0);
-
- int stringLength = static_cast<int>(number.bytes());
- const bool positiveAndMsbSet = number.sign() == Botan::BigInt::Positive
- && (number.byte_at(stringLength - 1) & 0x80);
- if (positiveAndMsbSet)
- ++stringLength;
- QByteArray data;
- data.resize(4 + stringLength);
- int pos = 4;
- if (positiveAndMsbSet)
- data[pos++] = '\0';
- number.binary_encode(reinterpret_cast<Botan::byte *>(data.data()) + pos);
- setLengthField(data);
- return data;
-}
-
-int AbstractSshPacket::paddingLength() const
-{
- return m_data[PaddingLengthOffset];
-}
-
-quint32 AbstractSshPacket::length() const
-{
- //Q_ASSERT(currentDataSize() >= minPacketSize());
- if (m_length == 0)
- calculateLength();
- return m_length;
-}
-
-void AbstractSshPacket::calculateLength() const
-{
- m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
-}
-
-QByteArray AbstractSshPacket::generateMac(const SshAbstractCryptoFacility &crypt,
- quint32 seqNr) const
-{
- const quint32 seqNrBe = qToBigEndian(seqNr);
- QByteArray data(reinterpret_cast<const char *>(&seqNrBe), sizeof seqNrBe);
- data += QByteArray(m_data.constData(), length() + 4);
- return crypt.generateMac(data, data.size());
-}
-
-quint32 AbstractSshPacket::minPacketSize() const
-{
- return qMax<quint32>(cipherBlockSize(), 16) + macLength();
-}
-
-void AbstractSshPacket::setLengthField(QByteArray &data)
-{
- const quint32 length = qToBigEndian(data.size() - 4);
- data.replace(0, 4, reinterpret_cast<const char *>(&length), 4);
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshpacket_p.h b/src/libs/ssh/sshpacket_p.h
deleted file mode 100644
index 4a94a432d1..0000000000
--- a/src/libs/ssh/sshpacket_p.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshexception_p.h"
-
-#include <QtEndian>
-#include <QByteArray>
-#include <QList>
-
-namespace Botan { class BigInt; }
-
-namespace QSsh {
-namespace Internal {
-
-enum SshPacketType {
- SSH_MSG_DISCONNECT = 1,
- SSH_MSG_IGNORE = 2,
- SSH_MSG_UNIMPLEMENTED = 3,
- SSH_MSG_DEBUG = 4,
- SSH_MSG_SERVICE_REQUEST = 5,
- SSH_MSG_SERVICE_ACCEPT = 6,
-
- SSH_MSG_KEXINIT = 20,
- SSH_MSG_NEWKEYS = 21,
- SSH_MSG_KEXDH_INIT = 30,
- SSH_MSG_KEX_ECDH_INIT = 30,
- SSH_MSG_KEXDH_REPLY = 31,
- SSH_MSG_KEX_ECDH_REPLY = 31,
-
- SSH_MSG_USERAUTH_REQUEST = 50,
- SSH_MSG_USERAUTH_FAILURE = 51,
- SSH_MSG_USERAUTH_SUCCESS = 52,
- SSH_MSG_USERAUTH_BANNER = 53,
- SSH_MSG_USERAUTH_PK_OK = 60,
- SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60,
- SSH_MSG_USERAUTH_INFO_REQUEST = 60,
- SSH_MSG_USERAUTH_INFO_RESPONSE = 61,
-
- SSH_MSG_GLOBAL_REQUEST = 80,
- SSH_MSG_REQUEST_SUCCESS = 81,
- SSH_MSG_REQUEST_FAILURE = 82,
-
- // TODO: We currently take no precautions against sending these messages
- // during a key re-exchange, which is not allowed.
- SSH_MSG_CHANNEL_OPEN = 90,
- SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91,
- SSH_MSG_CHANNEL_OPEN_FAILURE = 92,
- SSH_MSG_CHANNEL_WINDOW_ADJUST = 93,
- SSH_MSG_CHANNEL_DATA = 94,
- SSH_MSG_CHANNEL_EXTENDED_DATA = 95,
- SSH_MSG_CHANNEL_EOF = 96,
- SSH_MSG_CHANNEL_CLOSE = 97,
- SSH_MSG_CHANNEL_REQUEST = 98,
- SSH_MSG_CHANNEL_SUCCESS = 99,
- SSH_MSG_CHANNEL_FAILURE = 100,
-
- // Not completely safe, since the server may actually understand this
- // message type as an extension. Switch to a different value in that case
- // (between 128 and 191).
- SSH_MSG_INVALID = 128
-};
-
-enum SshOpenFailureType {
- SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1,
- SSH_OPEN_CONNECT_FAILED = 2,
- SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3,
- SSH_OPEN_RESOURCE_SHORTAGE = 4
-};
-
-enum SshExtendedDataType { SSH_EXTENDED_DATA_STDERR = 1 };
-
-class SshAbstractCryptoFacility;
-
-class AbstractSshPacket
-{
-public:
- virtual ~AbstractSshPacket();
-
- void clear();
- bool isComplete() const;
- SshPacketType type() const;
-
- static QByteArray encodeString(const QByteArray &string);
- static QByteArray encodeMpInt(const Botan::BigInt &number);
- template<typename T> static QByteArray encodeInt(T value)
- {
- const T valMsb = qToBigEndian(value);
- return QByteArray(reinterpret_cast<const char *>(&valMsb), sizeof valMsb);
- }
-
- static void setLengthField(QByteArray &data);
-
- void printRawBytes() const; // For Debugging.
-
- const QByteArray &rawData() const { return m_data; }
-
- QByteArray payLoad() const;
-
-protected:
- AbstractSshPacket();
-
- virtual quint32 cipherBlockSize() const = 0;
- virtual quint32 macLength() const = 0;
- virtual void calculateLength() const;
-
- quint32 length() const;
- int paddingLength() const;
- quint32 minPacketSize() const;
- quint32 currentDataSize() const { return m_data.size(); }
- QByteArray generateMac(const SshAbstractCryptoFacility &crypt,
- quint32 seqNr) const;
-
- static const quint32 PaddingLengthOffset;
- static const quint32 PayloadOffset;
- static const quint32 TypeOffset;
- static const quint32 MinPaddingLength;
-
- mutable QByteArray m_data;
- mutable quint32 m_length;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshpacketparser.cpp b/src/libs/ssh/sshpacketparser.cpp
deleted file mode 100644
index 6251f60244..0000000000
--- a/src/libs/ssh/sshpacketparser.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshpacketparser_p.h"
-
-#include <cctype>
-
-namespace QSsh {
-namespace Internal {
-
-namespace { quint32 size(const QByteArray &data) { return data.size(); } }
-
-QString SshPacketParser::asUserString(const QByteArray &rawString)
-{
- QByteArray filteredString;
- filteredString.resize(rawString.size());
- for (int i = 0; i < rawString.size(); ++i) {
- const char c = rawString.at(i);
- filteredString[i]
- = std::isprint(c) || c == '\n' || c == '\r' || c == '\t' ? c : '?';
- }
- return QString::fromUtf8(filteredString);
-}
-
-bool SshPacketParser::asBool(const QByteArray &data, quint32 offset)
-{
- if (size(data) <= offset)
- throw SshPacketParseException();
- return data.at(offset);
-}
-
-bool SshPacketParser::asBool(const QByteArray &data, quint32 *offset)
-{
- bool b = asBool(data, *offset);
- ++(*offset);
- return b;
-}
-
-
-quint32 SshPacketParser::asUint32(const QByteArray &data, quint32 offset)
-{
- if (size(data) < offset + 4)
- throw SshPacketParseException();
- const quint32 value = ((data.at(offset) & 0xff) << 24)
- + ((data.at(offset + 1) & 0xff) << 16)
- + ((data.at(offset + 2) & 0xff) << 8) + (data.at(offset + 3) & 0xff);
- return value;
-}
-
-quint32 SshPacketParser::asUint32(const QByteArray &data, quint32 *offset)
-{
- const quint32 v = asUint32(data, *offset);
- *offset += 4;
- return v;
-}
-
-quint64 SshPacketParser::asUint64(const QByteArray &data, quint32 offset)
-{
- if (size(data) < offset + 8)
- throw SshPacketParseException();
- const quint64 value = (static_cast<quint64>(data.at(offset) & 0xff) << 56)
- + (static_cast<quint64>(data.at(offset + 1) & 0xff) << 48)
- + (static_cast<quint64>(data.at(offset + 2) & 0xff) << 40)
- + (static_cast<quint64>(data.at(offset + 3) & 0xff) << 32)
- + ((data.at(offset + 4) & 0xff) << 24)
- + ((data.at(offset + 5) & 0xff) << 16)
- + ((data.at(offset + 6) & 0xff) << 8)
- + (data.at(offset + 7) & 0xff);
- return value;
-}
-
-quint64 SshPacketParser::asUint64(const QByteArray &data, quint32 *offset)
-{
- const quint64 val = asUint64(data, *offset);
- *offset += 8;
- return val;
-}
-
-QByteArray SshPacketParser::asString(const QByteArray &data, quint32 offset)
-{
- return asString(data, &offset);
-}
-
-QByteArray SshPacketParser::asString(const QByteArray &data, quint32 *offset)
-{
- const quint32 length = asUint32(data, offset);
- if (size(data) < *offset + length)
- throw SshPacketParseException();
- const QByteArray &string = data.mid(*offset, length);
- *offset += length;
- return string;
-}
-
-QString SshPacketParser::asUserString(const QByteArray &data, quint32 *offset)
-{
- return asUserString(asString(data, offset));
-}
-
-SshNameList SshPacketParser::asNameList(const QByteArray &data, quint32 *offset)
-{
- const quint32 length = asUint32(data, offset);
- const int listEndPos = *offset + length;
- if (data.size() < listEndPos)
- throw SshPacketParseException();
- SshNameList names(length + 4);
- int nextNameOffset = *offset;
- int nextCommaOffset = data.indexOf(',', nextNameOffset);
- while (nextNameOffset > 0 && nextNameOffset < listEndPos) {
- const int stringEndPos = nextCommaOffset == -1
- || nextCommaOffset > listEndPos ? listEndPos : nextCommaOffset;
- names.names << QByteArray(data.constData() + nextNameOffset,
- stringEndPos - nextNameOffset);
- nextNameOffset = nextCommaOffset + 1;
- nextCommaOffset = data.indexOf(',', nextNameOffset);
- }
- *offset += length;
- return names;
-}
-
-Botan::BigInt SshPacketParser::asBigInt(const QByteArray &data, quint32 *offset)
-{
- const quint32 length = asUint32(data, offset);
- if (length == 0)
- return Botan::BigInt();
- const Botan::byte *numberStart
- = reinterpret_cast<const Botan::byte *>(data.constData() + *offset);
- *offset += length;
- return Botan::BigInt::decode(numberStart, length);
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshpacketparser_p.h b/src/libs/ssh/sshpacketparser_p.h
deleted file mode 100644
index db63f0a1b9..0000000000
--- a/src/libs/ssh/sshpacketparser_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <botan/bigint.h>
-
-#include <QByteArray>
-#include <QList>
-#include <QString>
-
-namespace QSsh {
-namespace Internal {
-
-struct SshNameList
-{
- SshNameList() : originalLength(0) {}
- SshNameList(quint32 originalLength) : originalLength(originalLength) {}
- quint32 originalLength;
- QList<QByteArray> names;
-};
-
-class SshPacketParseException { };
-
-// This class's functions try to read a byte array at a certain offset
-// as the respective chunk of data as specified in the SSH RFCs.
-// If they succeed, they update the offset, so they can easily
-// be called in succession by client code.
-// For convenience, some have also versions that don't update the offset,
-// so they can be called with rvalues if the new value is not needed.
-// If they fail, they throw an SshPacketParseException.
-class SshPacketParser
-{
-public:
- static bool asBool(const QByteArray &data, quint32 offset);
- static bool asBool(const QByteArray &data, quint32 *offset);
- static quint16 asUint16(const QByteArray &data, quint32 offset);
- static quint16 asUint16(const QByteArray &data, quint32 *offset);
- static quint64 asUint64(const QByteArray &data, quint32 offset);
- static quint64 asUint64(const QByteArray &data, quint32 *offset);
- static quint32 asUint32(const QByteArray &data, quint32 offset);
- static quint32 asUint32(const QByteArray &data, quint32 *offset);
- static QByteArray asString(const QByteArray &data, quint32 offset);
- static QByteArray asString(const QByteArray &data, quint32 *offset);
- static QString asUserString(const QByteArray &data, quint32 *offset);
- static SshNameList asNameList(const QByteArray &data, quint32 *offset);
- static Botan::BigInt asBigInt(const QByteArray &data, quint32 *offset);
-
- static QString asUserString(const QByteArray &rawString);
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshx11displayinfo_p.h b/src/libs/ssh/sshprocess.cpp
index 48ba05218a..9e29f0b88d 100644
--- a/src/libs/ssh/sshx11displayinfo_p.h
+++ b/src/libs/ssh/sshprocess.cpp
@@ -23,27 +23,47 @@
**
****************************************************************************/
-#pragma once
+#include "sshprocess_p.h"
-#include "ssh_global.h"
+#include "sshsettings.h"
-#include <QString>
-#include <QByteArray>
+#include <utils/environment.h>
+
+#ifdef Q_OS_UNIX
+#include <sys/types.h>
+#include <unistd.h>
+#endif
namespace QSsh {
namespace Internal {
-class QSSH_AUTOTEST_EXPORT X11DisplayInfo
+SshProcess::SshProcess()
+{
+ Utils::Environment env = Utils::Environment::systemEnvironment();
+ if (SshSettings::askpassFilePath().exists())
+ env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput());
+ setProcessEnvironment(env.toProcessEnvironment());
+}
+
+SshProcess::~SshProcess()
+{
+ if (state() == QProcess::NotRunning)
+ return;
+ disconnect();
+ terminate();
+ waitForFinished(1000);
+ if (state() == QProcess::NotRunning)
+ return;
+ kill();
+ waitForFinished(1000);
+}
+
+void SshProcess::setupChildProcess()
{
-public:
- QString displayName;
- QString hostName;
- QByteArray protocol;
- QByteArray cookie;
- QByteArray randomCookie;
- int display = 0;
- int screen = 0;
-};
+#ifdef Q_OS_UNIX
+ setsid(); // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
+#endif
+}
} // namespace Internal
} // namespace QSsh
diff --git a/src/libs/ssh/sshkeypasswordretriever_p.h b/src/libs/ssh/sshprocess_p.h
index 7d7bc76e69..836dc62f96 100644
--- a/src/libs/ssh/sshkeypasswordretriever_p.h
+++ b/src/libs/ssh/sshprocess_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,12 +25,20 @@
#pragma once
-#include <string>
+#include <QProcess>
namespace QSsh {
namespace Internal {
-std::string get_passphrase();
+class SshProcess : public QProcess
+{
+public:
+ SshProcess();
+ ~SshProcess() override;
+
+private:
+ void setupChildProcess() override;
+};
} // namespace Internal
} // namespace QSsh
diff --git a/src/libs/ssh/sshpseudoterminal.h b/src/libs/ssh/sshpseudoterminal.h
deleted file mode 100644
index 827d6449e2..0000000000
--- a/src/libs/ssh/sshpseudoterminal.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "ssh_global.h"
-
-#include <QByteArray>
-#include <QHash>
-
-namespace QSsh {
-
-class QSSH_EXPORT SshPseudoTerminal
-{
- public:
- explicit SshPseudoTerminal(const QByteArray &termType = "vt100",
- int rowCount = 24, int columnCount = 80)
- : termType(termType), rowCount(rowCount), columnCount(columnCount) {}
-
- QByteArray termType;
- int rowCount;
- int columnCount;
-
- enum Mode {
- VINTR = 1, // Interrupt character.
- VQUIT = 2, // The quit character (sends SIGQUIT signal on POSIX systems).
- VERASE = 3, // Erase the character to left of the cursor.
- VKILL = 4, // Kill the current input line.
- VEOF = 5, // End-of-file character (sends EOF from the terminal).
- VEOL = 6, // End-of-line character in addition to carriage return and/or linefeed.
- VEOL2 = 7, // Additional end-of-line character.
- VSTART = 8, // Continues paused output (normally control-Q).
- VSTOP = 9, // Pauses output (normally control-S).
- VSUSP = 10, // Suspends the current program.
- VDSUSP = 11, // Another suspend character.
- VREPRINT = 12, // Reprints the current input line.
- VWERASE = 13, // Erases a word left of cursor.
- VLNEXT = 14, // Enter the next character typed literally, even if it is a special character.
- VFLUSH = 15, // Character to flush output.
- VSWTCH = 16, // Switch to a different shell layer.
- VSTATUS = 17, // Prints system status line (load, command, pid, etc).
- VDISCARD = 18, // Toggles the flushing of terminal output.
-
- IGNPAR = 30, // The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE, and 1 if it is TRUE.
- PARMRK = 31, // Mark parity and framing errors.
- INPCK = 32, // Enable checking of parity errors.
- ISTRIP = 33, // Strip 8th bit off characters.
- INLCR = 34, // Map NL into CR on input.
- IGNCR = 35, // Ignore CR on input.
- ICRNL = 36, // Map CR to NL on input.
- IUCLC = 37, // Translate uppercase characters to lowercase.
- IXON = 38, // Enable output flow control.
- IXANY = 39, // Any char will restart after stop.
- IXOFF = 40, // Enable input flow control.
- IMAXBEL = 41, // Ring bell on input queue full.
- ISIG = 50, // Enable signals INTR, QUIT, [D]SUSP.
- ICANON = 51, // Canonicalize input lines.
- XCASE = 52, // Enable input and output of uppercase characters by preceding their lowercase equivalents with "\".
- ECHO = 53, // Enable echoing.
- ECHOE = 54, // Visually erase chars.
- ECHOK = 55, // Kill character discards current line.
- ECHONL = 56, // Echo NL even if ECHO is off.
- NOFLSH = 57, // Don't flush after interrupt.
- TOSTOP = 58, // Stop background jobs from output.
- IEXTEN = 59, // Enable extensions.
- ECHOCTL = 60, // Echo control characters as ^(Char).
- ECHOKE = 61, // Visual erase for line kill.
- PENDIN = 62, // Retype pending input.
- OPOST = 70, // Enable output processing.
- OLCUC = 71, // Convert lowercase to uppercase.
- ONLCR = 72, // Map NL to CR-NL.
- OCRNL = 73, // Translate carriage return to newline (output).
- ONOCR = 74, // Translate newline to carriage return-newline (output).
- ONLRET = 75, // Newline performs a carriage return (output).
- CS7 = 90, // 7 bit mode.
- CS8 = 91, // 8 bit mode.
- PARENB = 92, // Parity enable.
- PARODD = 93, // Odd parity, else even.
-
- TTY_OP_ISPEED = 128, // Specifies the input baud rate in bits per second.
- TTY_OP_OSPEED = 129 // Specifies the output baud rate in bits per second.
- };
-
- typedef QHash<Mode, quint32> ModeMap;
- ModeMap modes;
-};
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp
index f4c43bdce2..22e2813150 100644
--- a/src/libs/ssh/sshremoteprocess.cpp
+++ b/src/libs/ssh/sshremoteprocess.cpp
@@ -24,13 +24,12 @@
****************************************************************************/
#include "sshremoteprocess.h"
-#include "sshremoteprocess_p.h"
-#include "ssh_global.h"
-#include "sshincomingpacket_p.h"
#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-#include "sshx11displayinfo_p.h"
+#include "sshsettings.h"
+
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
#include <QTimer>
@@ -47,362 +46,78 @@
The process is started via the start() member function.
If the process needs a pseudo terminal, you can request one
via requestTerminal() before calling start().
- Note that this class does not support QIODevice's waitFor*() functions, i.e. it has
- no synchronous mode.
*/
namespace QSsh {
+using namespace Internal;
-const struct {
- SshRemoteProcess::Signal signalEnum;
- const char * const signalString;
-} signalMap[] = {
- {SshRemoteProcess::AbrtSignal, "ABRT"}, {SshRemoteProcess::AlrmSignal, "ALRM"},
- {SshRemoteProcess::FpeSignal, "FPE"}, {SshRemoteProcess::HupSignal, "HUP"},
- {SshRemoteProcess::IllSignal, "ILL"}, {SshRemoteProcess::IntSignal, "INT"},
- {SshRemoteProcess::KillSignal, "KILL"}, {SshRemoteProcess::PipeSignal, "PIPE"},
- {SshRemoteProcess::QuitSignal, "QUIT"}, {SshRemoteProcess::SegvSignal, "SEGV"},
- {SshRemoteProcess::TermSignal, "TERM"}, {SshRemoteProcess::Usr1Signal, "USR1"},
- {SshRemoteProcess::Usr2Signal, "USR2"}
-};
-
-SshRemoteProcess::SshRemoteProcess(const QByteArray &command, quint32 channelId,
- Internal::SshSendFacility &sendFacility)
- : d(new Internal::SshRemoteProcessPrivate(command, channelId, sendFacility, this))
+struct SshRemoteProcess::SshRemoteProcessPrivate
{
- init();
-}
+ QByteArray remoteCommand;
+ QStringList connectionArgs;
+ QString displayName;
+ bool useTerminal = false;
+};
-SshRemoteProcess::SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility)
- : d(new Internal::SshRemoteProcessPrivate(channelId, sendFacility, this))
-{
- init();
+SshRemoteProcess::SshRemoteProcess(const QByteArray &command, const QStringList &connectionArgs)
+ : d(new SshRemoteProcessPrivate)
+{
+ d->remoteCommand = command;
+ d->connectionArgs = connectionArgs;
+
+ connect(this,
+ static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
+ [this] {
+ emit done(exitStatus() == QProcess::NormalExit ? QString() : errorString());
+ });
+ connect(this, &QProcess::errorOccurred, [this](QProcess::ProcessError error) {
+ if (error == QProcess::FailedToStart)
+ emit done(errorString());
+ });
+}
+
+void SshRemoteProcess::doStart()
+{
+ QTC_ASSERT(!isRunning(), return);
+ QStringList args = QStringList("-q") << d->connectionArgs;
+ if (d->useTerminal)
+ args.prepend("-tt");
+ if (!d->displayName.isEmpty()) {
+ args.prepend("-X");
+ QProcessEnvironment env = processEnvironment();
+ env.insert("DISPLAY", d->displayName);
+ setProcessEnvironment(env);
+ }
+ if (!d->remoteCommand.isEmpty())
+ args << QLatin1String(d->remoteCommand);
+ qCDebug(sshLog) << "starting remote process:" << SshSettings::sshFilePath().toUserOutput()
+ << args;
+ QProcess::start(SshSettings::sshFilePath().toString(), args);
}
SshRemoteProcess::~SshRemoteProcess()
{
- QSSH_ASSERT(d->channelState() != Internal::AbstractSshChannel::SessionEstablished);
- close();
delete d;
}
-bool SshRemoteProcess::atEnd() const
-{
- return QIODevice::atEnd() && d->data().isEmpty();
-}
-
-qint64 SshRemoteProcess::bytesAvailable() const
-{
- return QIODevice::bytesAvailable() + d->data().count();
-}
-
-bool SshRemoteProcess::canReadLine() const
-{
- return QIODevice::canReadLine() || d->data().contains('\n');
-}
-
-QByteArray SshRemoteProcess::readAllStandardOutput()
+void SshRemoteProcess::requestTerminal()
{
- return readAllFromChannel(QProcess::StandardOutput);
-}
-
-QByteArray SshRemoteProcess::readAllStandardError()
-{
- return readAllFromChannel(QProcess::StandardError);
-}
-
-QByteArray SshRemoteProcess::readAllFromChannel(QProcess::ProcessChannel channel)
-{
- const QProcess::ProcessChannel currentReadChannel = readChannel();
- setReadChannel(channel);
- const QByteArray &data = readAll();
- setReadChannel(currentReadChannel);
- return data;
-}
-
-void SshRemoteProcess::close()
-{
- d->closeChannel();
- QIODevice::close();
-}
-
-qint64 SshRemoteProcess::readData(char *data, qint64 maxlen)
-{
- const qint64 bytesRead = qMin(qint64(d->data().count()), maxlen);
- memcpy(data, d->data().constData(), bytesRead);
- d->data().remove(0, bytesRead);
- return bytesRead;
-}
-
-qint64 SshRemoteProcess::writeData(const char *data, qint64 len)
-{
- if (isRunning()) {
- d->sendData(QByteArray(data, len));
- return len;
- }
- return 0;
-}
-
-QProcess::ProcessChannel SshRemoteProcess::readChannel() const
-{
- return d->m_readChannel;
-}
-
-void SshRemoteProcess::setReadChannel(QProcess::ProcessChannel channel)
-{
- d->m_readChannel = channel;
-}
-
-void SshRemoteProcess::init()
-{
- connect(d, &Internal::SshRemoteProcessPrivate::started,
- this, &SshRemoteProcess::started, Qt::QueuedConnection);
- connect(d, &Internal::SshRemoteProcessPrivate::readyReadStandardOutput,
- this, &SshRemoteProcess::readyReadStandardOutput, Qt::QueuedConnection);
- connect(d, &Internal::SshRemoteProcessPrivate::readyRead,
- this, &SshRemoteProcess::readyRead, Qt::QueuedConnection);
- connect(d, &Internal::SshRemoteProcessPrivate::readyReadStandardError,
- this, &SshRemoteProcess::readyReadStandardError, Qt::QueuedConnection);
- connect(d, &Internal::SshRemoteProcessPrivate::closed,
- this, &SshRemoteProcess::closed, Qt::QueuedConnection);
- connect(d, &Internal::SshRemoteProcessPrivate::eof,
- this, &SshRemoteProcess::readChannelFinished, Qt::QueuedConnection);
-}
-
-void SshRemoteProcess::addToEnvironment(const QByteArray &var, const QByteArray &value)
-{
- if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive)
- d->m_env << qMakePair(var, value); // Cached locally and sent on start()
-}
-
-void SshRemoteProcess::clearEnvironment()
-{
- d->m_env.clear();
-}
-
-void SshRemoteProcess::requestTerminal(const SshPseudoTerminal &terminal)
-{
- QSSH_ASSERT_AND_RETURN(d->channelState() == Internal::SshRemoteProcessPrivate::Inactive);
- d->m_useTerminal = true;
- d->m_terminal = terminal;
+ d->useTerminal = true;
}
void SshRemoteProcess::requestX11Forwarding(const QString &displayName)
{
- QSSH_ASSERT_AND_RETURN(d->channelState() == Internal::SshRemoteProcessPrivate::Inactive);
- d->m_x11DisplayName = displayName;
+ d->displayName = displayName;
}
void SshRemoteProcess::start()
{
- if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive) {
- qCDebug(Internal::sshLog, "process start requested, channel id = %u", d->localChannelId());
- QIODevice::open(QIODevice::ReadWrite);
- d->requestSessionStart();
- }
-}
-
-void SshRemoteProcess::sendSignal(Signal signal)
-{
- try {
- if (isRunning()) {
- const char *signalString = 0;
- for (size_t i = 0; i < sizeof signalMap/sizeof *signalMap && !signalString; ++i) {
- if (signalMap[i].signalEnum == signal)
- signalString = signalMap[i].signalString;
- }
- QSSH_ASSERT_AND_RETURN(signalString);
- d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(), signalString);
- }
- } catch (const std::exception &e) {
- setErrorString(QString::fromLatin1(e.what()));
- d->closeChannel();
- }
+ QTimer::singleShot(0, this, &SshRemoteProcess::doStart);
}
bool SshRemoteProcess::isRunning() const
{
- return d->m_procState == Internal::SshRemoteProcessPrivate::Running;
-}
-
-int SshRemoteProcess::exitCode() const { return d->m_exitCode; }
-
-SshRemoteProcess::Signal SshRemoteProcess::exitSignal() const
-{
- return static_cast<SshRemoteProcess::Signal>(d->m_signal);
-}
-
-namespace Internal {
-
-void SshRemoteProcessPrivate::failToStart(const QString &reason)
-{
- if (m_procState != NotYetStarted)
- return;
- m_proc->setErrorString(reason);
- setProcState(StartFailed);
-}
-
-SshRemoteProcessPrivate::SshRemoteProcessPrivate(const QByteArray &command,
- quint32 channelId, SshSendFacility &sendFacility, SshRemoteProcess *proc)
- : AbstractSshChannel(channelId, sendFacility),
- m_command(command),
- m_isShell(false),
- m_useTerminal(false),
- m_proc(proc)
-{
- init();
-}
-
-SshRemoteProcessPrivate::SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
- SshRemoteProcess *proc)
- : AbstractSshChannel(channelId, sendFacility),
- m_isShell(true),
- m_useTerminal(true),
- m_proc(proc)
-{
- init();
-}
-
-void SshRemoteProcessPrivate::init()
-{
- m_procState = NotYetStarted;
- m_wasRunning = false;
- m_exitCode = 0;
- m_readChannel = QProcess::StandardOutput;
- m_signal = SshRemoteProcess::NoSignal;
-}
-
-void SshRemoteProcessPrivate::setProcState(ProcessState newState)
-{
- qCDebug(sshLog, "channel: old state = %d,new state = %d", m_procState, newState);
- m_procState = newState;
- if (newState == StartFailed) {
- emit closed(SshRemoteProcess::FailedToStart);
- } else if (newState == Running) {
- m_wasRunning = true;
- emit started();
- }
-}
-
-QByteArray &SshRemoteProcessPrivate::data()
-{
- return m_readChannel == QProcess::StandardOutput ? m_stdout : m_stderr;
-}
-
-void SshRemoteProcessPrivate::closeHook()
-{
- if (m_wasRunning) {
- if (m_signal != SshRemoteProcess::NoSignal)
- emit closed(SshRemoteProcess::CrashExit);
- else
- emit closed(SshRemoteProcess::NormalExit);
- }
-}
-
-void SshRemoteProcessPrivate::handleOpenSuccessInternal()
-{
- if (m_x11DisplayName.isEmpty())
- startProcess(X11DisplayInfo());
- else
- emit x11ForwardingRequested(m_x11DisplayName);
-}
-
-void SshRemoteProcessPrivate::startProcess(const X11DisplayInfo &displayInfo)
-{
- if (m_procState != NotYetStarted)
- return;
-
- foreach (const EnvVar &envVar, m_env) {
- m_sendFacility.sendEnvPacket(remoteChannel(), envVar.first,
- envVar.second);
- }
-
- if (!m_x11DisplayName.isEmpty()) {
- m_sendFacility.sendX11ForwardingPacket(remoteChannel(), displayInfo.protocol,
- displayInfo.randomCookie.toHex(), 0);
- }
-
- if (m_useTerminal)
- m_sendFacility.sendPtyRequestPacket(remoteChannel(), m_terminal);
-
- if (m_isShell)
- m_sendFacility.sendShellPacket(remoteChannel());
- else
- m_sendFacility.sendExecPacket(remoteChannel(), m_command);
- setProcState(ExecRequested);
- m_timeoutTimer.start(ReplyTimeout);
-}
-
-void SshRemoteProcessPrivate::handleOpenFailureInternal(const QString &reason)
-{
- failToStart(reason);
-}
-
-void SshRemoteProcessPrivate::handleChannelSuccess()
-{
- if (m_procState != ExecRequested) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_SUCCESS message.");
- }
- m_timeoutTimer.stop();
- setProcState(Running);
-}
-
-void SshRemoteProcessPrivate::handleChannelFailure()
-{
- if (m_procState != ExecRequested) {
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_FAILURE message.");
- }
- m_timeoutTimer.stop();
- setProcState(StartFailed);
- closeChannel();
-}
-
-void SshRemoteProcessPrivate::handleChannelDataInternal(const QByteArray &data)
-{
- m_stdout += data;
- emit readyReadStandardOutput();
- if (m_readChannel == QProcess::StandardOutput)
- emit readyRead();
-}
-
-void SshRemoteProcessPrivate::handleChannelExtendedDataInternal(quint32 type,
- const QByteArray &data)
-{
- if (type != SSH_EXTENDED_DATA_STDERR) {
- qCWarning(sshLog, "Unknown extended data type %u", type);
- } else {
- m_stderr += data;
- emit readyReadStandardError();
- if (m_readChannel == QProcess::StandardError)
- emit readyRead();
- }
-}
-
-void SshRemoteProcessPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus)
-{
- qCDebug(sshLog, "Process exiting with exit code %d", exitStatus.exitStatus);
- m_exitCode = exitStatus.exitStatus;
- m_procState = Exited;
-}
-
-void SshRemoteProcessPrivate::handleExitSignal(const SshChannelExitSignal &signal)
-{
- qCDebug(sshLog, "Exit due to signal %s", signal.signal.data());
-
- for (size_t i = 0; i < sizeof signalMap/sizeof *signalMap; ++i) {
- if (signalMap[i].signalString == signal.signal) {
- m_signal = signalMap[i].signalEnum;
- m_procState = Exited;
- m_proc->setErrorString(tr("Process killed by signal"));
- return;
- }
- }
-
- throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid signal",
- tr("Server sent invalid signal \"%1\"").arg(QString::fromUtf8(signal.signal)));
+ return state() == QProcess::Running;
}
-} // namespace Internal
} // namespace QSsh
diff --git a/src/libs/ssh/sshremoteprocess.h b/src/libs/ssh/sshremoteprocess.h
index 85f8018227..958847fcd8 100644
--- a/src/libs/ssh/sshremoteprocess.h
+++ b/src/libs/ssh/sshremoteprocess.h
@@ -26,97 +26,40 @@
#pragma once
#include "ssh_global.h"
+#include "sshprocess_p.h"
-#include <QProcess>
-#include <QSharedPointer>
+#include <QStringList>
QT_BEGIN_NAMESPACE
class QByteArray;
QT_END_NAMESPACE
namespace QSsh {
-class SshPseudoTerminal;
-namespace Internal {
-class SshChannelManager;
-class SshRemoteProcessPrivate;
-class SshSendFacility;
-} // namespace Internal
+class SshConnection;
-// TODO: ProcessChannel
-class QSSH_EXPORT SshRemoteProcess : public QIODevice
+class QSSH_EXPORT SshRemoteProcess : public Internal::SshProcess
{
Q_OBJECT
- friend class Internal::SshChannelManager;
- friend class Internal::SshRemoteProcessPrivate;
-
+ friend class SshConnection;
public:
- typedef QSharedPointer<SshRemoteProcess> Ptr;
- enum ExitStatus { FailedToStart, CrashExit, NormalExit };
- enum Signal {
- AbrtSignal, AlrmSignal, FpeSignal, HupSignal, IllSignal, IntSignal, KillSignal, PipeSignal,
- QuitSignal, SegvSignal, TermSignal, Usr1Signal, Usr2Signal, NoSignal
- };
-
~SshRemoteProcess();
- // QIODevice stuff
- bool atEnd() const;
- qint64 bytesAvailable() const;
- bool canReadLine() const;
- void close();
- bool isSequential() const { return true; }
-
- QProcess::ProcessChannel readChannel() const;
- void setReadChannel(QProcess::ProcessChannel channel);
-
- /*
- * Note that this is of limited value in practice, because servers are
- * usually configured to ignore such requests for security reasons.
- */
- void addToEnvironment(const QByteArray &var, const QByteArray &value);
- void clearEnvironment();
-
- void requestTerminal(const SshPseudoTerminal &terminal);
+ void requestTerminal();
void requestX11Forwarding(const QString &displayName);
void start();
bool isRunning() const;
- int exitCode() const;
- Signal exitSignal() const;
-
- QByteArray readAllStandardOutput();
- QByteArray readAllStandardError();
-
- // Note: This is ignored by the OpenSSH server.
- void sendSignal(Signal signal);
- void kill() { sendSignal(KillSignal); }
signals:
- void started();
-
- void readyReadStandardOutput();
- void readyReadStandardError();
-
- /*
- * Parameter is of type ExitStatus, but we use int because of
- * signal/slot awkwardness (full namespace required).
- */
- void closed(int exitStatus);
+ void done(const QString &error);
private:
- SshRemoteProcess(const QByteArray &command, quint32 channelId,
- Internal::SshSendFacility &sendFacility);
- SshRemoteProcess(quint32 channelId, Internal::SshSendFacility &sendFacility);
-
- // QIODevice stuff
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
-
- void init();
- QByteArray readAllFromChannel(QProcess::ProcessChannel channel);
+ SshRemoteProcess(const QByteArray &command, const QStringList &connectionArgs);
+ void doStart();
- Internal::SshRemoteProcessPrivate *d;
+ struct SshRemoteProcessPrivate;
+ SshRemoteProcessPrivate * const d;
};
} // namespace QSsh
diff --git a/src/libs/ssh/sshremoteprocess_p.h b/src/libs/ssh/sshremoteprocess_p.h
deleted file mode 100644
index 459da8c593..0000000000
--- a/src/libs/ssh/sshremoteprocess_p.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshpseudoterminal.h"
-
-#include "sshchannel_p.h"
-
-#include <QList>
-#include <QPair>
-#include <QProcess>
-
-namespace QSsh {
-class SshRemoteProcess;
-
-namespace Internal {
-class SshSendFacility;
-class X11DisplayInfo;
-
-class SshRemoteProcessPrivate : public AbstractSshChannel
-{
- Q_OBJECT
- friend class QSsh::SshRemoteProcess;
-public:
- enum ProcessState {
- NotYetStarted, ExecRequested, StartFailed, Running, Exited
- };
-
- void failToStart(const QString &reason);
- void startProcess(const X11DisplayInfo &displayInfo);
-
-signals:
- void started();
- void readyRead();
- void readyReadStandardOutput();
- void readyReadStandardError();
- void closed(int exitStatus);
- void x11ForwardingRequested(const QString &display);
-
-private:
- SshRemoteProcessPrivate(const QByteArray &command, quint32 channelId,
- SshSendFacility &sendFacility, SshRemoteProcess *proc);
- SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
- SshRemoteProcess *proc);
-
- virtual void handleChannelSuccess();
- virtual void handleChannelFailure();
-
- virtual void handleOpenSuccessInternal();
- virtual void handleOpenFailureInternal(const QString &reason);
- virtual void handleChannelDataInternal(const QByteArray &data);
- virtual void handleChannelExtendedDataInternal(quint32 type,
- const QByteArray &data);
- virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
- virtual void handleExitSignal(const SshChannelExitSignal &signal);
-
- virtual void closeHook();
-
- void init();
- void setProcState(ProcessState newState);
- QByteArray &data();
-
- QProcess::ProcessChannel m_readChannel;
-
- ProcessState m_procState;
- bool m_wasRunning;
- int m_signal;
- int m_exitCode;
-
- const QByteArray m_command;
- const bool m_isShell;
-
- typedef QPair<QByteArray, QByteArray> EnvVar;
- QList<EnvVar> m_env;
- bool m_useTerminal;
- SshPseudoTerminal m_terminal;
-
- QString m_x11DisplayName;
-
- QByteArray m_stdout;
- QByteArray m_stderr;
-
- SshRemoteProcess *m_proc;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshremoteprocessrunner.cpp b/src/libs/ssh/sshremoteprocessrunner.cpp
index b3f55257e7..11b75f6a25 100644
--- a/src/libs/ssh/sshremoteprocessrunner.cpp
+++ b/src/libs/ssh/sshremoteprocessrunner.cpp
@@ -26,8 +26,8 @@
#include "sshremoteprocessrunner.h"
#include "sshconnectionmanager.h"
-#include "sshpseudoterminal.h"
+#include <utils/qtcassert.h>
/*!
\class QSsh::SshRemoteProcessRunner
@@ -47,15 +47,12 @@ class SshRemoteProcessRunnerPrivate
public:
SshRemoteProcessRunnerPrivate() : m_state(Inactive) {}
- SshRemoteProcess::Ptr m_process;
+ SshRemoteProcessPtr m_process;
SshConnection *m_connection;
bool m_runInTerminal;
- SshPseudoTerminal m_terminal;
QByteArray m_command;
- QSsh::SshError m_lastConnectionError;
QString m_lastConnectionErrorString;
- SshRemoteProcess::ExitStatus m_exitStatus;
- SshRemoteProcess::Signal m_exitSignal;
+ QProcess::ExitStatus m_exitStatus;
QByteArray m_stdout;
QByteArray m_stderr;
int m_exitCode;
@@ -82,16 +79,15 @@ SshRemoteProcessRunner::~SshRemoteProcessRunner()
void SshRemoteProcessRunner::run(const QByteArray &command,
const SshConnectionParameters &sshParams)
{
- QSSH_ASSERT_AND_RETURN(d->m_state == Inactive);
+ QTC_ASSERT(d->m_state == Inactive, return);
d->m_runInTerminal = false;
runInternal(command, sshParams);
}
void SshRemoteProcessRunner::runInTerminal(const QByteArray &command,
- const SshPseudoTerminal &terminal, const SshConnectionParameters &sshParams)
+ const SshConnectionParameters &sshParams)
{
- d->m_terminal = terminal;
d->m_runInTerminal = true;
runInternal(command, sshParams);
}
@@ -101,14 +97,12 @@ void SshRemoteProcessRunner::runInternal(const QByteArray &command,
{
setState(Connecting);
- d->m_lastConnectionError = SshNoError;
d->m_lastConnectionErrorString.clear();
d->m_processErrorString.clear();
- d->m_exitSignal = SshRemoteProcess::NoSignal;
d->m_exitCode = -1;
d->m_command = command;
d->m_connection = QSsh::acquireConnection(sshParams);
- connect(d->m_connection, &SshConnection::error,
+ connect(d->m_connection, &SshConnection::errorOccurred,
this, &SshRemoteProcessRunner::handleConnectionError);
connect(d->m_connection, &SshConnection::disconnected,
this, &SshRemoteProcessRunner::handleDisconnected);
@@ -123,26 +117,25 @@ void SshRemoteProcessRunner::runInternal(const QByteArray &command,
void SshRemoteProcessRunner::handleConnected()
{
- QSSH_ASSERT_AND_RETURN(d->m_state == Connecting);
+ QTC_ASSERT(d->m_state == Connecting, return);
setState(Connected);
d->m_process = d->m_connection->createRemoteProcess(d->m_command);
- connect(d->m_process.data(), &SshRemoteProcess::started,
+ connect(d->m_process.get(), &SshRemoteProcess::started,
this, &SshRemoteProcessRunner::handleProcessStarted);
- connect(d->m_process.data(), &SshRemoteProcess::closed,
+ connect(d->m_process.get(), &SshRemoteProcess::done,
this, &SshRemoteProcessRunner::handleProcessFinished);
- connect(d->m_process.data(), &SshRemoteProcess::readyReadStandardOutput,
+ connect(d->m_process.get(), &SshRemoteProcess::readyReadStandardOutput,
this, &SshRemoteProcessRunner::handleStdout);
- connect(d->m_process.data(), &SshRemoteProcess::readyReadStandardError,
+ connect(d->m_process.get(), &SshRemoteProcess::readyReadStandardError,
this, &SshRemoteProcessRunner::handleStderr);
if (d->m_runInTerminal)
- d->m_process->requestTerminal(d->m_terminal);
+ d->m_process->requestTerminal();
d->m_process->start();
}
-void SshRemoteProcessRunner::handleConnectionError(QSsh::SshError error)
+void SshRemoteProcessRunner::handleConnectionError()
{
- d->m_lastConnectionError = error;
d->m_lastConnectionErrorString = d->m_connection->errorString();
handleDisconnected();
emit connectionError();
@@ -150,40 +143,26 @@ void SshRemoteProcessRunner::handleConnectionError(QSsh::SshError error)
void SshRemoteProcessRunner::handleDisconnected()
{
- QSSH_ASSERT_AND_RETURN(d->m_state == Connecting || d->m_state == Connected
- || d->m_state == ProcessRunning);
+ QTC_ASSERT(d->m_state == Connecting || d->m_state == Connected || d->m_state == ProcessRunning,
+ return);
setState(Inactive);
}
void SshRemoteProcessRunner::handleProcessStarted()
{
- QSSH_ASSERT_AND_RETURN(d->m_state == Connected);
+ QTC_ASSERT(d->m_state == Connected, return);
setState(ProcessRunning);
emit processStarted();
}
-void SshRemoteProcessRunner::handleProcessFinished(int exitStatus)
+void SshRemoteProcessRunner::handleProcessFinished(const QString &error)
{
- d->m_exitStatus = static_cast<SshRemoteProcess::ExitStatus>(exitStatus);
- switch (d->m_exitStatus) {
- case SshRemoteProcess::FailedToStart:
- QSSH_ASSERT_AND_RETURN(d->m_state == Connected);
- break;
- case SshRemoteProcess::CrashExit:
- QSSH_ASSERT_AND_RETURN(d->m_state == ProcessRunning);
- d->m_exitSignal = d->m_process->exitSignal();
- break;
- case SshRemoteProcess::NormalExit:
- QSSH_ASSERT_AND_RETURN(d->m_state == ProcessRunning);
- d->m_exitCode = d->m_process->exitCode();
- break;
- default:
- Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible exit status.");
- }
- d->m_processErrorString = d->m_process->errorString();
+ d->m_exitStatus = d->m_process->exitStatus();
+ d->m_exitCode = d->m_process->exitCode();
+ d->m_processErrorString = error;
setState(Inactive);
- emit processClosed(exitStatus);
+ emit processClosed(d->m_processErrorString);
}
void SshRemoteProcessRunner::handleStdout()
@@ -206,9 +185,9 @@ void SshRemoteProcessRunner::setState(int newState)
d->m_state = static_cast<State>(newState);
if (d->m_state == Inactive) {
if (d->m_process) {
- disconnect(d->m_process.data(), 0, this, 0);
- d->m_process->close();
- d->m_process.clear();
+ disconnect(d->m_process.get(), nullptr, this, nullptr);
+ d->m_process->terminate();
+ d->m_process.release()->deleteLater();
}
if (d->m_connection) {
disconnect(d->m_connection, 0, this, 0);
@@ -219,7 +198,6 @@ void SshRemoteProcessRunner::setState(int newState)
}
QByteArray SshRemoteProcessRunner::command() const { return d->m_command; }
-SshError SshRemoteProcessRunner::lastConnectionError() const { return d->m_lastConnectionError; }
QString SshRemoteProcessRunner::lastConnectionErrorString() const {
return d->m_lastConnectionErrorString;
}
@@ -231,19 +209,13 @@ bool SshRemoteProcessRunner::isProcessRunning() const
SshRemoteProcess::ExitStatus SshRemoteProcessRunner::processExitStatus() const
{
- QSSH_ASSERT(!isProcessRunning());
+ QTC_CHECK(!isProcessRunning());
return d->m_exitStatus;
}
-SshRemoteProcess::Signal SshRemoteProcessRunner::processExitSignal() const
-{
- QSSH_ASSERT(processExitStatus() == SshRemoteProcess::CrashExit);
- return d->m_exitSignal;
-}
-
int SshRemoteProcessRunner::processExitCode() const
{
- QSSH_ASSERT(processExitStatus() == SshRemoteProcess::NormalExit);
+ QTC_CHECK(processExitStatus() == SshRemoteProcess::NormalExit);
return d->m_exitCode;
}
@@ -268,16 +240,10 @@ QByteArray SshRemoteProcessRunner::readAllStandardError()
void SshRemoteProcessRunner::writeDataToProcess(const QByteArray &data)
{
- QSSH_ASSERT(isProcessRunning());
+ QTC_CHECK(isProcessRunning());
d->m_process->write(data);
}
-void SshRemoteProcessRunner::sendSignalToProcess(SshRemoteProcess::Signal signal)
-{
- QSSH_ASSERT(isProcessRunning());
- d->m_process->sendSignal(signal);
-}
-
void SshRemoteProcessRunner::cancel()
{
setState(Inactive);
diff --git a/src/libs/ssh/sshremoteprocessrunner.h b/src/libs/ssh/sshremoteprocessrunner.h
index 0a2ee578e9..029fb6bb3d 100644
--- a/src/libs/ssh/sshremoteprocessrunner.h
+++ b/src/libs/ssh/sshremoteprocessrunner.h
@@ -40,19 +40,15 @@ public:
~SshRemoteProcessRunner();
void run(const QByteArray &command, const SshConnectionParameters &sshParams);
- void runInTerminal(const QByteArray &command, const SshPseudoTerminal &terminal,
- const SshConnectionParameters &sshParams);
+ void runInTerminal(const QByteArray &command, const SshConnectionParameters &sshParams);
QByteArray command() const;
- QSsh::SshError lastConnectionError() const;
QString lastConnectionErrorString() const;
bool isProcessRunning() const;
void writeDataToProcess(const QByteArray &data);
- void sendSignalToProcess(SshRemoteProcess::Signal signal); // No effect with OpenSSH server.
- void cancel(); // Does not stop remote process, just frees SSH-related process resources.
+ void cancel();
SshRemoteProcess::ExitStatus processExitStatus() const;
- SshRemoteProcess::Signal processExitSignal() const;
int processExitCode() const;
QString processErrorString() const;
QByteArray readAllStandardOutput();
@@ -63,14 +59,14 @@ signals:
void processStarted();
void readyReadStandardOutput();
void readyReadStandardError();
- void processClosed(int exitStatus); // values are of type SshRemoteProcess::ExitStatus
+ void processClosed(const QString &error);
private:
void handleConnected();
- void handleConnectionError(QSsh::SshError error);
+ void handleConnectionError();
void handleDisconnected();
void handleProcessStarted();
- void handleProcessFinished(int exitStatus);
+ void handleProcessFinished(const QString &error);
void handleStdout();
void handleStderr();
void runInternal(const QByteArray &command, const QSsh::SshConnectionParameters &sshParams);
diff --git a/src/libs/ssh/sshsendfacility.cpp b/src/libs/ssh/sshsendfacility.cpp
deleted file mode 100644
index f92a1220fb..0000000000
--- a/src/libs/ssh/sshsendfacility.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshsendfacility_p.h"
-
-#include "sshkeyexchange_p.h"
-#include "sshlogging_p.h"
-#include "sshoutgoingpacket_p.h"
-
-#include <QTcpSocket>
-
-namespace QSsh {
-namespace Internal {
-
-SshSendFacility::SshSendFacility(QTcpSocket *socket)
- : m_clientSeqNr(0), m_socket(socket),
- m_outgoingPacket(m_encrypter, m_clientSeqNr)
-{
-}
-
-void SshSendFacility::sendPacket()
-{
- qCDebug(sshLog, "Sending packet, client seq nr is %u", m_clientSeqNr);
- if (m_socket->isValid()
- && m_socket->state() == QAbstractSocket::ConnectedState) {
- m_socket->write(m_outgoingPacket.rawData());
- ++m_clientSeqNr;
- }
-}
-
-void SshSendFacility::reset()
-{
- m_clientSeqNr = 0;
- m_encrypter.clearKeys();
-}
-
-void SshSendFacility::recreateKeys(const SshKeyExchange &keyExchange)
-{
- m_encrypter.recreateKeys(keyExchange);
-}
-
-void SshSendFacility::createAuthenticationKey(const QByteArray &privKeyFileContents)
-{
- m_encrypter.createAuthenticationKey(privKeyFileContents);
-}
-
-QByteArray SshSendFacility::sendKeyExchangeInitPacket()
-{
- const QByteArray &payLoad = m_outgoingPacket.generateKeyExchangeInitPacket();
- sendPacket();
- return payLoad;
-}
-
-void SshSendFacility::sendKeyDhInitPacket(const Botan::BigInt &e)
-{
- m_outgoingPacket.generateKeyDhInitPacket(e);
- sendPacket();
-}
-
-void SshSendFacility::sendKeyEcdhInitPacket(const QByteArray &clientQ)
-{
- m_outgoingPacket.generateKeyEcdhInitPacket(clientQ);
- sendPacket();
-}
-
-void SshSendFacility::sendNewKeysPacket()
-{
- m_outgoingPacket.generateNewKeysPacket();
- sendPacket();
-}
-
-void SshSendFacility::sendDisconnectPacket(SshErrorCode reason,
- const QByteArray &reasonString)
-{
- m_outgoingPacket.generateDisconnectPacket(reason, reasonString);
- sendPacket();
- }
-
-void SshSendFacility::sendMsgUnimplementedPacket(quint32 serverSeqNr)
-{
- m_outgoingPacket.generateMsgUnimplementedPacket(serverSeqNr);
- sendPacket();
-}
-
-void SshSendFacility::sendUserAuthServiceRequestPacket()
-{
- m_outgoingPacket.generateUserAuthServiceRequestPacket();
- sendPacket();
-}
-
-void SshSendFacility::sendUserAuthByPasswordRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &pwd)
-{
- m_outgoingPacket.generateUserAuthByPasswordRequestPacket(user, service, pwd);
- sendPacket();
- }
-
-void SshSendFacility::sendUserAuthByPublicKeyRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &key, const QByteArray &signature)
-{
- m_outgoingPacket.generateUserAuthByPublicKeyRequestPacket(user, service, key, signature);
- sendPacket();
-}
-
-void SshSendFacility::sendQueryPublicKeyPacket(const QByteArray &user, const QByteArray &service,
- const QByteArray &publicKey)
-{
- m_outgoingPacket.generateQueryPublicKeyPacket(user, service, publicKey);
- sendPacket();
-}
-
-void SshSendFacility::sendUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user,
- const QByteArray &service)
-{
- m_outgoingPacket.generateUserAuthByKeyboardInteractiveRequestPacket(user, service);
- sendPacket();
-}
-
-void SshSendFacility::sendUserAuthInfoResponsePacket(const QStringList &responses)
-{
- m_outgoingPacket.generateUserAuthInfoResponsePacket(responses);
- sendPacket();
-}
-
-void SshSendFacility::sendRequestFailurePacket()
-{
- m_outgoingPacket.generateRequestFailurePacket();
- sendPacket();
-}
-
-void SshSendFacility::sendIgnorePacket()
-{
- m_outgoingPacket.generateIgnorePacket();
- sendPacket();
-}
-
-void SshSendFacility::sendInvalidPacket()
-{
- m_outgoingPacket.generateInvalidMessagePacket();
- sendPacket();
-}
-
-void SshSendFacility::sendSessionPacket(quint32 channelId, quint32 windowSize,
- quint32 maxPacketSize)
-{
- m_outgoingPacket.generateSessionPacket(channelId, windowSize,
- maxPacketSize);
- sendPacket();
-}
-
-void SshSendFacility::sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
- quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
- const QByteArray &localIpAddress, quint32 localPort)
-{
- m_outgoingPacket.generateDirectTcpIpPacket(channelId, windowSize, maxPacketSize, remoteHost,
- remotePort, localIpAddress, localPort);
- sendPacket();
-}
-
-void SshSendFacility::sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
-{
- m_outgoingPacket.generateTcpIpForwardPacket(bindAddress, bindPort);
- sendPacket();
-}
-
-void SshSendFacility::sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
-{
- m_outgoingPacket.generateCancelTcpIpForwardPacket(bindAddress, bindPort);
- sendPacket();
-}
-
-void SshSendFacility::sendPtyRequestPacket(quint32 remoteChannel,
- const SshPseudoTerminal &terminal)
-{
- m_outgoingPacket.generatePtyRequestPacket(remoteChannel, terminal);
- sendPacket();
-}
-
-void SshSendFacility::sendEnvPacket(quint32 remoteChannel,
- const QByteArray &var, const QByteArray &value)
-{
- m_outgoingPacket.generateEnvPacket(remoteChannel, var, value);
- sendPacket();
-}
-
-void SshSendFacility::sendX11ForwardingPacket(quint32 remoteChannel, const QByteArray &protocol,
- const QByteArray &cookie, quint32 screenNumber)
-{
- m_outgoingPacket.generateX11ForwardingPacket(remoteChannel, protocol, cookie, screenNumber);
- sendPacket();
-}
-
-void SshSendFacility::sendExecPacket(quint32 remoteChannel,
- const QByteArray &command)
-{
- m_outgoingPacket.generateExecPacket(remoteChannel, command);
- sendPacket();
-}
-
-void SshSendFacility::sendShellPacket(quint32 remoteChannel)
-{
- m_outgoingPacket.generateShellPacket(remoteChannel);
- sendPacket();
-}
-
-void SshSendFacility::sendSftpPacket(quint32 remoteChannel)
-{
- m_outgoingPacket.generateSftpPacket(remoteChannel);
- sendPacket();
-}
-
-void SshSendFacility::sendWindowAdjustPacket(quint32 remoteChannel,
- quint32 bytesToAdd)
-{
- m_outgoingPacket.generateWindowAdjustPacket(remoteChannel, bytesToAdd);
- sendPacket();
-}
-
-void SshSendFacility::sendChannelDataPacket(quint32 remoteChannel,
- const QByteArray &data)
-{
- m_outgoingPacket.generateChannelDataPacket(remoteChannel, data);
- sendPacket();
-}
-
-void SshSendFacility::sendChannelSignalPacket(quint32 remoteChannel,
- const QByteArray &signalName)
-{
- m_outgoingPacket.generateChannelSignalPacket(remoteChannel, signalName);
- sendPacket();
-}
-
-void SshSendFacility::sendChannelEofPacket(quint32 remoteChannel)
-{
- m_outgoingPacket.generateChannelEofPacket(remoteChannel);
- sendPacket();
-}
-
-void SshSendFacility::sendChannelClosePacket(quint32 remoteChannel)
-{
- m_outgoingPacket.generateChannelClosePacket(remoteChannel);
- sendPacket();
-}
-
-void SshSendFacility::sendChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
- quint32 localWindowSize, quint32 maxPacketSize)
-{
- m_outgoingPacket.generateChannelOpenConfirmationPacket(remoteChannel, localChannel,
- localWindowSize, maxPacketSize);
- sendPacket();
-}
-
-void SshSendFacility::sendChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
- const QByteArray &reasonString)
-{
- m_outgoingPacket.generateChannelOpenFailurePacket(remoteChannel, reason, reasonString);
- sendPacket();
-}
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshsendfacility_p.h b/src/libs/ssh/sshsendfacility_p.h
deleted file mode 100644
index b3e0e44e1f..0000000000
--- a/src/libs/ssh/sshsendfacility_p.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshcryptofacility_p.h"
-#include "sshoutgoingpacket_p.h"
-
-#include <QStringList>
-
-QT_BEGIN_NAMESPACE
-class QTcpSocket;
-QT_END_NAMESPACE
-
-
-namespace QSsh {
-class SshPseudoTerminal;
-
-namespace Internal {
-class SshKeyExchange;
-
-class SshSendFacility
-{
-public:
- SshSendFacility(QTcpSocket *socket);
- void reset();
- void recreateKeys(const SshKeyExchange &keyExchange);
- void createAuthenticationKey(const QByteArray &privKeyFileContents);
-
- QByteArray sessionId() const { return m_encrypter.sessionId(); }
-
- QByteArray sendKeyExchangeInitPacket();
- void sendKeyDhInitPacket(const Botan::BigInt &e);
- void sendKeyEcdhInitPacket(const QByteArray &clientQ);
- void sendNewKeysPacket();
- void sendDisconnectPacket(SshErrorCode reason,
- const QByteArray &reasonString);
- void sendMsgUnimplementedPacket(quint32 serverSeqNr);
- void sendUserAuthServiceRequestPacket();
- void sendUserAuthByPasswordRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &pwd);
- void sendUserAuthByPublicKeyRequestPacket(const QByteArray &user,
- const QByteArray &service, const QByteArray &key, const QByteArray &signature);
- void sendQueryPublicKeyPacket(const QByteArray &user, const QByteArray &service,
- const QByteArray &publicKey);
- void sendUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user,
- const QByteArray &service);
- void sendUserAuthInfoResponsePacket(const QStringList &responses);
- void sendRequestFailurePacket();
- void sendIgnorePacket();
- void sendInvalidPacket();
- void sendSessionPacket(quint32 channelId, quint32 windowSize,
- quint32 maxPacketSize);
- void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize,
- const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress,
- quint32 localPort);
- void sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
- void sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
- void sendPtyRequestPacket(quint32 remoteChannel,
- const SshPseudoTerminal &terminal);
- void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
- const QByteArray &value);
- void sendX11ForwardingPacket(quint32 remoteChannel, const QByteArray &protocol,
- const QByteArray &cookie, quint32 screenNumber);
- void sendExecPacket(quint32 remoteChannel, const QByteArray &command);
- void sendShellPacket(quint32 remoteChannel);
- void sendSftpPacket(quint32 remoteChannel);
- void sendWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd);
- void sendChannelDataPacket(quint32 remoteChannel, const QByteArray &data);
- void sendChannelSignalPacket(quint32 remoteChannel,
- const QByteArray &signalName);
- void sendChannelEofPacket(quint32 remoteChannel);
- void sendChannelClosePacket(quint32 remoteChannel);
- void sendChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
- quint32 localWindowSize, quint32 maxPackeSize);
- void sendChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
- const QByteArray &reasonString);
- quint32 nextClientSeqNr() const { return m_clientSeqNr; }
-
-private:
- void sendPacket();
-
- quint32 m_clientSeqNr;
- SshEncryptionFacility m_encrypter;
- QTcpSocket *m_socket;
- SshOutgoingPacket m_outgoingPacket;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshsettings.cpp b/src/libs/ssh/sshsettings.cpp
new file mode 100644
index 0000000000..d1d9e8c099
--- /dev/null
+++ b/src/libs/ssh/sshsettings.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "sshsettings.h"
+
+#include <utils/environment.h>
+
+#include <QSettings>
+
+using namespace Utils;
+
+namespace QSsh {
+namespace Internal {
+
+struct SshSettings
+{
+ bool useConnectionSharing = true;
+ int connectionSharingTimeOutInMinutes = 10;
+ FileName sshFilePath;
+ FileName sftpFilePath;
+ FileName askpassFilePath;
+ FileName keygenFilePath;
+ QSsh::SshSettings::SearchPathRetriever searchPathRetriever = [] { return FileNameList(); };
+};
+
+} // namespace Internal
+
+Q_GLOBAL_STATIC(QSsh::Internal::SshSettings, sshSettings)
+
+
+class AccessSettingsGroup
+{
+public:
+ AccessSettingsGroup(QSettings *settings) : m_settings(settings)
+ {
+ settings->beginGroup("SshSettings");
+ }
+ ~AccessSettingsGroup() { m_settings->endGroup(); }
+private:
+ QSettings * const m_settings;
+};
+
+static QString connectionSharingKey() { return "UseConnectionSharing"; }
+static QString connectionSharingTimeoutKey() { return "ConnectionSharingTimeout"; }
+static QString sshFilePathKey() { return "SshFilePath"; }
+static QString sftpFilePathKey() { return "SftpFilePath"; }
+static QString askPassFilePathKey() { return "AskpassFilePath"; }
+static QString keygenFilePathKey() { return "KeygenFilePath"; }
+
+void SshSettings::loadSettings(QSettings *settings)
+{
+ AccessSettingsGroup g(settings);
+ QVariant value = settings->value(connectionSharingKey());
+ if (value.isValid())
+ sshSettings->useConnectionSharing = value.toBool();
+ value = settings->value(connectionSharingTimeoutKey());
+ if (value.isValid())
+ sshSettings->connectionSharingTimeOutInMinutes = value.toInt();
+ sshSettings->sshFilePath = FileName::fromString(settings->value(sshFilePathKey()).toString());
+ sshSettings->sftpFilePath = FileName::fromString(settings->value(sftpFilePathKey()).toString());
+ sshSettings->askpassFilePath = FileName::fromString(
+ settings->value(askPassFilePathKey()).toString());
+ sshSettings->keygenFilePath = FileName::fromString(
+ settings->value(keygenFilePathKey()).toString());
+}
+
+void SshSettings::storeSettings(QSettings *settings)
+{
+ AccessSettingsGroup g(settings);
+ settings->setValue(connectionSharingKey(), sshSettings->useConnectionSharing);
+ settings->setValue(connectionSharingTimeoutKey(),
+ sshSettings->connectionSharingTimeOutInMinutes);
+ settings->setValue(sshFilePathKey(), sshSettings->sshFilePath.toString());
+ settings->setValue(sftpFilePathKey(), sshSettings->sftpFilePath.toString());
+ settings->setValue(askPassFilePathKey(), sshSettings->askpassFilePath.toString());
+ settings->setValue(keygenFilePathKey(), sshSettings->keygenFilePath.toString());
+}
+
+void SshSettings::setConnectionSharingEnabled(bool share)
+{
+ sshSettings->useConnectionSharing = share;
+}
+bool SshSettings::connectionSharingEnabled() { return sshSettings->useConnectionSharing; }
+
+void SshSettings::setConnectionSharingTimeout(int timeInMinutes)
+{
+ sshSettings->connectionSharingTimeOutInMinutes = timeInMinutes;
+}
+int SshSettings::connectionSharingTimeout()
+{
+ return sshSettings->connectionSharingTimeOutInMinutes;
+}
+
+static FileName filePathValue(const FileName &value, const QString &defaultFileName)
+{
+ return !value.isEmpty()
+ ? value
+ : Environment::systemEnvironment().searchInPath(defaultFileName,
+ sshSettings->searchPathRetriever());
+}
+
+void SshSettings::setSshFilePath(const FileName &ssh) { sshSettings->sshFilePath = ssh; }
+FileName SshSettings::sshFilePath() { return filePathValue(sshSettings->sshFilePath, "ssh"); }
+
+void SshSettings::setSftpFilePath(const FileName &sftp) { sshSettings->sftpFilePath = sftp; }
+FileName SshSettings::sftpFilePath() { return filePathValue(sshSettings->sftpFilePath, "sftp"); }
+
+void SshSettings::setAskpassFilePath(const FileName &askPass)
+{
+ sshSettings->askpassFilePath = askPass;
+}
+
+FileName SshSettings::askpassFilePath()
+{
+ FileName candidate;
+ candidate = sshSettings->askpassFilePath;
+ if (candidate.isEmpty())
+ candidate = FileName::fromString(Environment::systemEnvironment().value("SSH_ASKPASS"));
+ return filePathValue(candidate, "ssh-askpass");
+}
+
+void SshSettings::setKeygenFilePath(const FileName &keygen)
+{
+ sshSettings->keygenFilePath = keygen;
+}
+
+FileName SshSettings::keygenFilePath()
+{
+ return filePathValue(sshSettings->keygenFilePath, "ssh-keygen");
+}
+
+void SshSettings::setExtraSearchPathRetriever(const SearchPathRetriever &pathRetriever)
+{
+ sshSettings->searchPathRetriever = pathRetriever;
+}
+
+} // namespace QSsh
diff --git a/src/libs/ssh/sshhostkeydatabase.h b/src/libs/ssh/sshsettings.h
index bd58ab86b5..dc29ead606 100644
--- a/src/libs/ssh/sshhostkeydatabase.h
+++ b/src/libs/ssh/sshsettings.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -27,40 +27,42 @@
#include "ssh_global.h"
-#include <QSharedPointer>
+#include <utils/fileutils.h>
+
+#include <functional>
QT_BEGIN_NAMESPACE
-class QByteArray;
-class QString;
+class QSettings;
QT_END_NAMESPACE
namespace QSsh {
-class SshHostKeyDatabase;
-typedef QSharedPointer<SshHostKeyDatabase> SshHostKeyDatabasePtr;
-class QSSH_EXPORT SshHostKeyDatabase
+class QSSH_EXPORT SshSettings
{
- friend class QSharedPointer<SshHostKeyDatabase>; // To give create() access to our constructor.
-
public:
- enum KeyLookupResult {
- KeyLookupMatch,
- KeyLookupNoMatch,
- KeyLookupMismatch
- };
+ static void loadSettings(QSettings *settings);
+ static void storeSettings(QSettings *settings);
+
+ static void setConnectionSharingEnabled(bool share);
+ static bool connectionSharingEnabled();
+
+ static void setConnectionSharingTimeout(int timeInMinutes);
+ static int connectionSharingTimeout();
+
+ static void setSshFilePath(const Utils::FileName &ssh);
+ static Utils::FileName sshFilePath();
- ~SshHostKeyDatabase();
+ static void setSftpFilePath(const Utils::FileName &sftp);
+ static Utils::FileName sftpFilePath();
- bool load(const QString &filePath, QString *error = 0);
- bool store(const QString &filePath, QString *error = 0) const;
- KeyLookupResult matchHostKey(const QString &hostName, const QByteArray &key) const;
- void insertHostKey(const QString &hostName, const QByteArray &key);
+ static void setAskpassFilePath(const Utils::FileName &askPass);
+ static Utils::FileName askpassFilePath();
-private:
- SshHostKeyDatabase();
+ static void setKeygenFilePath(const Utils::FileName &keygen);
+ static Utils::FileName keygenFilePath();
- class SshHostKeyDatabasePrivate;
- SshHostKeyDatabasePrivate * const d;
+ using SearchPathRetriever = std::function<Utils::FileNameList()>;
+ static void setExtraSearchPathRetriever(const SearchPathRetriever &pathRetriever);
};
} // namespace QSsh
diff --git a/src/libs/ssh/sshtcpipforwardserver.cpp b/src/libs/ssh/sshtcpipforwardserver.cpp
deleted file mode 100644
index 5501ea930b..0000000000
--- a/src/libs/ssh/sshtcpipforwardserver.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshtcpipforwardserver.h"
-#include "sshtcpipforwardserver_p.h"
-
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-
-namespace QSsh {
-namespace Internal {
-
-SshTcpIpForwardServerPrivate::SshTcpIpForwardServerPrivate(const QString &bindAddress,
- quint16 bindPort, SshSendFacility &sendFacility)
- : m_sendFacility(sendFacility),
- m_bindAddress(bindAddress),
- m_bindPort(bindPort),
- m_state(SshTcpIpForwardServer::Inactive)
-{
-}
-
-} // namespace Internal
-
-using namespace Internal;
-
-SshTcpIpForwardServer::SshTcpIpForwardServer(const QString &bindAddress, quint16 bindPort,
- SshSendFacility &sendFacility)
- : d(new SshTcpIpForwardServerPrivate(bindAddress, bindPort, sendFacility))
-{
- connect(&d->m_timeoutTimer, &QTimer::timeout, this, &SshTcpIpForwardServer::setClosed);
-}
-
-void SshTcpIpForwardServer::setListening(quint16 port)
-{
- QSSH_ASSERT_AND_RETURN(d->m_state != Listening);
- d->m_bindPort = port;
- d->m_state = Listening;
- emit stateChanged(Listening);
-}
-
-void SshTcpIpForwardServer::setClosed()
-{
- QSSH_ASSERT_AND_RETURN(d->m_state != Inactive);
- d->m_state = Inactive;
- emit stateChanged(Inactive);
-}
-
-void SshTcpIpForwardServer::setNewConnection(const SshForwardedTcpIpTunnel::Ptr &connection)
-{
- d->m_pendingConnections.append(connection);
- emit newConnection();
-}
-
-SshTcpIpForwardServer::~SshTcpIpForwardServer()
-{
- delete d;
-}
-
-void SshTcpIpForwardServer::initialize()
-{
- if (d->m_state == Inactive || d->m_state == Closing) {
- try {
- d->m_state = Initializing;
- emit stateChanged(Initializing);
- d->m_sendFacility.sendTcpIpForwardPacket(d->m_bindAddress.toUtf8(), d->m_bindPort);
- d->m_timeoutTimer.start(d->ReplyTimeout);
- } catch (const std::exception &e) {
- qCWarning(sshLog, "Botan error: %s", e.what());
- d->m_timeoutTimer.stop();
- setClosed();
- }
- }
-}
-
-void SshTcpIpForwardServer::close()
-{
- d->m_timeoutTimer.stop();
-
- if (d->m_state == Initializing || d->m_state == Listening) {
- try {
- d->m_state = Closing;
- emit stateChanged(Closing);
- d->m_sendFacility.sendCancelTcpIpForwardPacket(d->m_bindAddress.toUtf8(),
- d->m_bindPort);
- d->m_timeoutTimer.start(d->ReplyTimeout);
- } catch (const std::exception &e) {
- qCWarning(sshLog, "Botan error: %s", e.what());
- d->m_timeoutTimer.stop();
- setClosed();
- }
- }
-}
-
-const QString &SshTcpIpForwardServer::bindAddress() const
-{
- return d->m_bindAddress;
-}
-
-quint16 SshTcpIpForwardServer::port() const
-{
- return d->m_bindPort;
-}
-
-SshTcpIpForwardServer::State SshTcpIpForwardServer::state() const
-{
- return d->m_state;
-}
-
-SshForwardedTcpIpTunnel::Ptr SshTcpIpForwardServer::nextPendingConnection()
-{
- return d->m_pendingConnections.takeFirst();
-}
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshtcpipforwardserver_p.h b/src/libs/ssh/sshtcpipforwardserver_p.h
deleted file mode 100644
index 9f4775bee7..0000000000
--- a/src/libs/ssh/sshtcpipforwardserver_p.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshtcpipforwardserver.h"
-#include <QList>
-#include <QTimer>
-
-namespace QSsh {
-namespace Internal {
-
-class SshTcpIpForwardServerPrivate
-{
-public:
- static const int ReplyTimeout = 10000; // milli seconds
-
- SshTcpIpForwardServerPrivate(const QString &bindAddress, quint16 bindPort,
- SshSendFacility &sendFacility);
-
- SshSendFacility &m_sendFacility;
- QTimer m_timeoutTimer;
-
- const QString m_bindAddress;
- quint16 m_bindPort;
- SshTcpIpForwardServer::State m_state;
-
- QList<SshForwardedTcpIpTunnel::Ptr> m_pendingConnections;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshtcpiptunnel.cpp b/src/libs/ssh/sshtcpiptunnel.cpp
deleted file mode 100644
index ac7bf5208b..0000000000
--- a/src/libs/ssh/sshtcpiptunnel.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshsendfacility_p.h"
-#include "sshtcpiptunnel_p.h"
-
-#include "sshincomingpacket_p.h"
-#include "sshexception_p.h"
-#include "sshlogging_p.h"
-
-namespace QSsh {
-
-namespace Internal {
-SshTcpIpTunnelPrivate::SshTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility)
- : AbstractSshChannel(channelId, sendFacility)
-{
- connect(this, &AbstractSshChannel::eof, this, &SshTcpIpTunnelPrivate::handleEof);
-}
-
-SshTcpIpTunnelPrivate::~SshTcpIpTunnelPrivate()
-{
- closeChannel();
-}
-
-
-
-void SshTcpIpTunnelPrivate::handleChannelSuccess()
-{
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_SUCCESS message.");
-}
-
-void SshTcpIpTunnelPrivate::handleChannelFailure()
-{
- throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
- "Unexpected SSH_MSG_CHANNEL_FAILURE message.");
-}
-
-void SshTcpIpTunnelPrivate::handleOpenFailureInternal(const QString &reason)
-{
- emit error(reason);
- closeChannel();
-}
-
-void SshTcpIpTunnelPrivate::handleChannelDataInternal(const QByteArray &data)
-{
- m_data += data;
- emit readyRead();
-}
-
-void SshTcpIpTunnelPrivate::handleChannelExtendedDataInternal(quint32 type,
- const QByteArray &data)
-{
- qCWarning(sshLog, "%s: Unexpected extended channel data. Type is %u, content is '%s'.",
- Q_FUNC_INFO, type, data.constData());
-}
-
-void SshTcpIpTunnelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus)
-{
- qCWarning(sshLog, "%s: Unexpected exit status %d.", Q_FUNC_INFO, exitStatus.exitStatus);
-}
-
-void SshTcpIpTunnelPrivate::handleExitSignal(const SshChannelExitSignal &signal)
-{
- qCWarning(sshLog, "%s: Unexpected exit signal %s.", Q_FUNC_INFO, signal.signal.constData());
-}
-
-void SshTcpIpTunnelPrivate::closeHook()
-{
- emit closed();
-}
-
-void SshTcpIpTunnelPrivate::handleEof()
-{
- /*
- * For some reason, the OpenSSH server only sends EOF when the remote port goes away,
- * but does not close the channel, even though it becomes useless in that case.
- * So we close it ourselves.
- */
- closeChannel();
-}
-
-qint64 SshTcpIpTunnelPrivate::readData(char *data, qint64 maxlen)
-{
- const qint64 bytesRead = qMin(qint64(m_data.count()), maxlen);
- memcpy(data, m_data.constData(), bytesRead);
- m_data.remove(0, bytesRead);
- return bytesRead;
-}
-
-qint64 SshTcpIpTunnelPrivate::writeData(const char *data, qint64 len)
-{
- QSSH_ASSERT_AND_RETURN_VALUE(channelState() == AbstractSshChannel::SessionEstablished, 0);
-
- sendData(QByteArray(data, len));
- return len;
-}
-
-} // namespace Internal
-
-} // namespace QSsh
diff --git a/src/libs/ssh/sshtcpiptunnel_p.h b/src/libs/ssh/sshtcpiptunnel_p.h
deleted file mode 100644
index a9f2844cbc..0000000000
--- a/src/libs/ssh/sshtcpiptunnel_p.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshchannel_p.h"
-#include <QIODevice>
-#include <QByteArray>
-
-namespace QSsh {
-namespace Internal {
-
-class SshTcpIpTunnelPrivate : public AbstractSshChannel
-{
- Q_OBJECT
-
-public:
- SshTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility);
- ~SshTcpIpTunnelPrivate();
-
- template<class SshTcpIpTunnel>
- void init(SshTcpIpTunnel *q)
- {
- connect(this, &SshTcpIpTunnelPrivate::closed,
- q, &SshTcpIpTunnel::close, Qt::QueuedConnection);
- connect(this, &SshTcpIpTunnelPrivate::readyRead,
- q, &SshTcpIpTunnel::readyRead, Qt::QueuedConnection);
- connect(this, &SshTcpIpTunnelPrivate::error, q, [q](const QString &reason) {
- q->setErrorString(reason);
- emit q->error(reason);
- }, Qt::QueuedConnection);
- }
-
- void handleChannelSuccess() override;
- void handleChannelFailure() override;
-
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
-
-signals:
- void readyRead();
- void error(const QString &reason);
- void closed();
-
-protected:
- void handleOpenFailureInternal(const QString &reason) override;
- void handleChannelDataInternal(const QByteArray &data) override;
- void handleChannelExtendedDataInternal(quint32 type, const QByteArray &data) override;
- void handleExitStatus(const SshChannelExitStatus &exitStatus) override;
- void handleExitSignal(const SshChannelExitSignal &signal) override;
- void closeHook() override;
-
- QByteArray m_data;
-
-private:
- void handleEof();
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshx11channel.cpp b/src/libs/ssh/sshx11channel.cpp
deleted file mode 100644
index d531142ceb..0000000000
--- a/src/libs/ssh/sshx11channel.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshx11channel_p.h"
-
-#include "sshincomingpacket_p.h"
-#include "sshlogging_p.h"
-#include "sshsendfacility_p.h"
-
-#include <QFileInfo>
-#include <QLocalSocket>
-#include <QTcpSocket>
-
-namespace QSsh {
-namespace Internal {
-
-class X11Socket : public QObject
-{
- Q_OBJECT
-public:
- X11Socket(QObject *parent) : QObject(parent) { }
-
- void establishConnection(const X11DisplayInfo &displayInfo)
- {
- const bool hostNameIsPath = displayInfo.hostName.startsWith('/'); // macOS
- const bool hasActualHostName = !displayInfo.hostName.isEmpty()
- && displayInfo.hostName != "unix" && !displayInfo.hostName.endsWith("/unix")
- && !hostNameIsPath;
- if (hasActualHostName) {
- QTcpSocket * const socket = new QTcpSocket(this);
- connect(socket, &QTcpSocket::connected, this, &X11Socket::connected);
- connect(socket,
- static_cast<void(QTcpSocket::*)(QTcpSocket::SocketError)>(&QTcpSocket::error),
- [this, socket] {
- emit error(socket->errorString());
- });
- socket->connectToHost(displayInfo.hostName, 6000 + displayInfo.display);
- m_socket = socket;
- } else {
- const QString serverBasePath = hostNameIsPath ? QString(displayInfo.hostName + ':')
- : "/tmp/.X11-unix/X";
- QLocalSocket * const socket = new QLocalSocket(this);
- connect(socket, &QLocalSocket::connected, this, &X11Socket::connected);
- connect(socket,
- static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error),
- [this, socket] {
- emit error(socket->errorString());
- });
- socket->connectToServer(serverBasePath + QString::number(displayInfo.display));
- m_socket = socket;
- }
- connect(m_socket, &QIODevice::readyRead,
- [this] { emit dataAvailable(m_socket->readAll()); });
- }
-
- void closeConnection()
- {
- m_socket->disconnect();
- if (localSocket())
- localSocket()->disconnectFromServer();
- else
- tcpSocket()->disconnectFromHost();
- }
-
- void write(const QByteArray &data)
- {
- m_socket->write(data);
- }
-
- bool hasError() const
- {
- return (localSocket() && localSocket()->error() != QLocalSocket::UnknownSocketError)
- || (tcpSocket() && tcpSocket()->error() != QTcpSocket::UnknownSocketError);
- }
-
- bool isConnected() const
- {
- return (localSocket() && localSocket()->state() == QLocalSocket::ConnectedState)
- || (tcpSocket() && tcpSocket()->state() == QTcpSocket::ConnectedState);
- }
-
-signals:
- void connected();
- void error(const QString &message);
- void dataAvailable(const QByteArray &data);
-
-private:
- QLocalSocket *localSocket() const { return qobject_cast<QLocalSocket *>(m_socket); }
- QTcpSocket *tcpSocket() const { return qobject_cast<QTcpSocket *>(m_socket); }
-
- QIODevice *m_socket = nullptr;
-};
-
-SshX11Channel::SshX11Channel(const X11DisplayInfo &displayInfo, quint32 channelId,
- SshSendFacility &sendFacility)
- : AbstractSshChannel (channelId, sendFacility),
- m_x11Socket(new X11Socket(this)),
- m_displayInfo(displayInfo)
-{
- setChannelState(SessionRequested); // Invariant for parent class.
-}
-
-void SshX11Channel::handleChannelSuccess()
-{
- qCWarning(sshLog) << "unexpected channel success message for X11 channel";
-}
-
-void SshX11Channel::handleChannelFailure()
-{
- qCWarning(sshLog) << "unexpected channel failure message for X11 channel";
-}
-
-void SshX11Channel::handleOpenSuccessInternal()
-{
- m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(),
- initialWindowSize(), maxPacketSize());
- connect(m_x11Socket, &X11Socket::connected, [this] {
- qCDebug(sshLog) << "x11 socket connected for channel" << localChannelId();
- if (!m_queuedRemoteData.isEmpty())
- handleRemoteData(QByteArray());
- });
- connect(m_x11Socket, &X11Socket::error,
- [this](const QString &msg) { emit error(tr("X11 socket error: %1").arg(msg)); });
- connect(m_x11Socket, &X11Socket::dataAvailable, [this](const QByteArray &data) {
- qCDebug(sshLog) << "sending " << data.size() << "bytes from x11 socket to remote side "
- "in channel" << localChannelId();
- sendData(data);
- });
- m_x11Socket->establishConnection(m_displayInfo);
-}
-
-void SshX11Channel::handleOpenFailureInternal(const QString &reason)
-{
- qCWarning(sshLog) << "unexpected channel open failure message for X11 channel:" << reason;
-}
-
-void SshX11Channel::handleChannelDataInternal(const QByteArray &data)
-{
- handleRemoteData(data);
-}
-
-void SshX11Channel::handleChannelExtendedDataInternal(quint32 type, const QByteArray &data)
-{
- qCWarning(sshLog) << "unexpected extended data for X11 channel" << type << data;
-}
-
-void SshX11Channel::handleExitStatus(const SshChannelExitStatus &exitStatus)
-{
- qCWarning(sshLog) << "unexpected exit status message on X11 channel" << exitStatus.exitStatus;
- closeChannel();
-}
-
-void SshX11Channel::handleExitSignal(const SshChannelExitSignal &signal)
-{
- qCWarning(sshLog) << "unexpected exit signal message on X11 channel" << signal.error;
- closeChannel();
-}
-
-void SshX11Channel::closeHook()
-{
- m_x11Socket->disconnect();
- m_x11Socket->closeConnection();
-}
-
-void SshX11Channel::handleRemoteData(const QByteArray &data)
-{
- if (m_x11Socket->hasError())
- return;
- qCDebug(sshLog) << "received" << data.size() << "bytes from remote side in x11 channel"
- << localChannelId();
- if (!m_x11Socket->isConnected()) {
- qCDebug(sshLog) << "x11 socket not yet connected, queueing data";
- m_queuedRemoteData += data;
- return;
- }
- if (m_haveReplacedRandomCookie) {
- qCDebug(sshLog) << "forwarding data to x11 socket";
- m_x11Socket->write(data);
- return;
- }
- m_queuedRemoteData += data;
- const int randomCookieOffset = m_queuedRemoteData.indexOf(m_displayInfo.randomCookie);
- if (randomCookieOffset == -1) {
- qCDebug(sshLog) << "random cookie has not appeared in remote data yet, queueing data";
- return;
- }
- m_queuedRemoteData.replace(randomCookieOffset, m_displayInfo.cookie.size(),
- m_displayInfo.cookie);
- qCDebug(sshLog) << "found and replaced random cookie, forwarding data to x11 socket";
- m_x11Socket->write(m_queuedRemoteData);
- m_queuedRemoteData.clear();
- m_haveReplacedRandomCookie = true;
-}
-
-} // namespace Internal
-} // namespace QSsh
-
-#include <sshx11channel.moc>
diff --git a/src/libs/ssh/sshx11channel_p.h b/src/libs/ssh/sshx11channel_p.h
deleted file mode 100644
index 918129172e..0000000000
--- a/src/libs/ssh/sshx11channel_p.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "sshchannel_p.h"
-
-#include "sshx11displayinfo_p.h"
-
-#include <QByteArray>
-
-namespace QSsh {
-namespace Internal {
-class SshChannelManager;
-class SshSendFacility;
-class X11Socket;
-
-class SshX11Channel : public AbstractSshChannel
-{
- Q_OBJECT
-
- friend class Internal::SshChannelManager;
-
-signals:
- void error(const QString &message);
-
-private:
- SshX11Channel(const X11DisplayInfo &displayInfo, quint32 channelId,
- SshSendFacility &sendFacility);
-
- void handleChannelSuccess() override;
- void handleChannelFailure() override;
-
- void handleOpenSuccessInternal() override;
- void handleOpenFailureInternal(const QString &reason) override;
- void handleChannelDataInternal(const QByteArray &data) override;
- void handleChannelExtendedDataInternal(quint32 type, const QByteArray &data) override;
- void handleExitStatus(const SshChannelExitStatus &exitStatus) override;
- void handleExitSignal(const SshChannelExitSignal &signal) override;
- void closeHook() override;
-
- void handleRemoteData(const QByteArray &data);
-
- X11Socket * const m_x11Socket;
- const X11DisplayInfo m_displayInfo;
- QByteArray m_queuedRemoteData;
- bool m_haveReplacedRandomCookie = false;
-};
-
-} // namespace Internal
-} // namespace QSsh
diff --git a/src/libs/ssh/sshx11inforetriever.cpp b/src/libs/ssh/sshx11inforetriever.cpp
deleted file mode 100644
index 819ad428af..0000000000
--- a/src/libs/ssh/sshx11inforetriever.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "sshx11inforetriever_p.h"
-
-#include "sshlogging_p.h"
-#include "sshx11displayinfo_p.h"
-
-#include <QByteArrayList>
-#include <QProcess>
-#include <QTemporaryFile>
-#include <QTimer>
-
-#include <botan/auto_rng.h>
-
-namespace QSsh {
-namespace Internal {
-
-static QByteArray xauthProtocol() { return "MIT-MAGIC-COOKIE-1"; }
-
-SshX11InfoRetriever::SshX11InfoRetriever(const QString &displayName, QObject *parent)
- : QObject(parent),
- m_displayName(displayName),
- m_xauthProc(new QProcess(this)),
- m_xauthFile(new QTemporaryFile(this))
-{
- connect(m_xauthProc, &QProcess::errorOccurred, [this] {
- if (m_xauthProc->error() == QProcess::FailedToStart) {
- emitFailure(tr("Could not start xauth: %1").arg(m_xauthProc->errorString()));
- }
- });
- connect(m_xauthProc,
- static_cast<void (QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
- [this] {
- if (m_xauthProc->exitStatus() != QProcess::NormalExit) {
- emitFailure(tr("xauth crashed: %1").arg(m_xauthProc->errorString()));
- return;
- }
- if (m_xauthProc->exitCode() != 0) {
- emitFailure(tr("xauth failed with exit code %1.").arg(m_xauthProc->exitCode()));
- return;
- }
- switch (m_state) {
- case State::RunningGenerate:
- m_state = State::RunningList;
- m_xauthProc->start("xauth", QStringList{"-f", m_xauthFile->fileName(), "list",
- m_displayName});
- break;
- case State::RunningList: {
- const QByteArrayList outputLines = m_xauthProc->readAllStandardOutput().split('\n');
- if (outputLines.empty()) {
- emitFailure(tr("Unexpected xauth output."));
- return;
- }
- const QByteArrayList data = outputLines.first().simplified().split(' ');
- if (data.size() < 3 || data.at(1) != xauthProtocol() || data.at(2).isEmpty()) {
- emitFailure(tr("Unexpected xauth output."));
- return;
- }
- X11DisplayInfo displayInfo;
- displayInfo.displayName = m_displayName;
- const int colonIndex = m_displayName.indexOf(':');
- if (colonIndex == -1) {
- emitFailure(tr("Invalid display name \"%1\"").arg(m_displayName));
- return;
- }
- displayInfo.hostName = m_displayName.mid(0, colonIndex);
- const int dotIndex = m_displayName.indexOf('.', colonIndex + 1);
- const QString display = m_displayName.mid(colonIndex + 1,
- dotIndex == -1 ? -1
- : dotIndex - colonIndex - 1);
- if (display.isEmpty()) {
- emitFailure(tr("Invalid display name \"%1\"").arg(m_displayName));
- return;
- }
- bool ok;
- displayInfo.display = display.toInt(&ok);
- if (!ok) {
- emitFailure(tr("Invalid display name \"%1\"").arg(m_displayName));
- return;
- }
- if (dotIndex != -1) {
- displayInfo.screen = m_displayName.mid(dotIndex + 1).toInt(&ok);
- if (!ok) {
- emitFailure(tr("Invalid display name \"%1\"").arg(m_displayName));
- return;
- }
- }
- displayInfo.protocol = data.at(1);
- displayInfo.cookie = QByteArray::fromHex(data.at(2));
- displayInfo.randomCookie.resize(displayInfo.cookie.size());
- try {
- Botan::AutoSeeded_RNG rng;
- rng.randomize(reinterpret_cast<Botan::uint8_t *>(displayInfo.randomCookie.data()),
- displayInfo.randomCookie.size());
- } catch (const std::exception &ex) {
- emitFailure(tr("Failed to generate random cookie: %1")
- .arg(QLatin1String(ex.what())));
- return;
- }
- emit success(displayInfo);
- deleteLater();
- break;
- }
- default:
- emitFailure(tr("Internal error"));
- }
- });
-}
-
-void SshX11InfoRetriever::start()
-{
- if (!m_xauthFile->open()) {
- emitFailure(tr("Could not create temporary file: %1").arg(m_xauthFile->errorString()));
- return;
- }
- m_state = State::RunningGenerate;
- m_xauthProc->start("xauth", QStringList{"-f", m_xauthFile->fileName(), "generate",
- m_displayName, QString::fromLatin1(xauthProtocol())});
-}
-
-void SshX11InfoRetriever::emitFailure(const QString &reason)
-{
- QTimer::singleShot(0, this, [this, reason] {
- emit failure(tr("Could not retrieve X11 authentication cookie: %1").arg(reason));
- deleteLater();
- });
-}
-
-} // namespace Internal
-} // namespace QSsh