[qt-creator/f20] Add SSH host key verification to built-in SSH client (#1161655)
Sandro Mani
smani at fedoraproject.org
Mon Mar 9 21:51:46 UTC 2015
commit 7616f9359bc0e4b6cd1cd8486cb9fc7c6f94c54e
Author: Sandro Mani <manisandro at gmail.com>
Date: Mon Mar 9 22:51:32 2015 +0100
Add SSH host key verification to built-in SSH client (#1161655)
qt-creator.spec | 8 +-
..._62a83f911365eab71e7260484517ef6c739d5192.patch | 636 +++++++++++++++++++++
2 files changed, 643 insertions(+), 1 deletion(-)
---
diff --git a/qt-creator.spec b/qt-creator.spec
index 96b7ae5..39d1433 100644
--- a/qt-creator.spec
+++ b/qt-creator.spec
@@ -2,7 +2,7 @@
Name: qt-creator
Version: 3.2.2
-Release: 1%{?pre:.%pre}%{?dist}
+Release: 2%{?pre:.%pre}%{?dist}
Summary: Cross-platform IDE for Qt
Group: Development/Tools
@@ -12,6 +12,8 @@ Source0: http://download.qt-project.org/%{?pre:development}%{!?pre:offici
# Fix doc dir (Fedora package is called qt-creator, not qtcreator)
Patch0: qt-creator_docdir.patch
+# Add SSH host key verification to built-in SSH client (#1161655)
+Patch1: qt-creator_62a83f911365eab71e7260484517ef6c739d5192.patch
Source1: qtcreator.desktop
Source2: qt-creator-Fedora-privlibs
@@ -59,6 +61,7 @@ tailored to the needs of Qt developers.
%prep
%setup -q -n qt-creator-opensource-src-%{version}%{?pre:-%pre}
%patch0 -p1
+%patch1 -p1
%build
export QTDIR="%{_qt4_prefix}"
@@ -137,6 +140,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%changelog
+* Mon Mar 09 2015 Sandro Mani <manisandro at gmail.com> - 3.2.2-2
+- Add SSH host key verification to built-in SSH client (#1161655)
+
* Mon Oct 13 2014 Sandro Mani <manisandro at gmail.com> - 3.2.2-1
- 3.2.2 release
diff --git a/qt-creator_62a83f911365eab71e7260484517ef6c739d5192.patch b/qt-creator_62a83f911365eab71e7260484517ef6c739d5192.patch
new file mode 100644
index 0000000..85a55e9
--- /dev/null
+++ b/qt-creator_62a83f911365eab71e7260484517ef6c739d5192.patch
@@ -0,0 +1,636 @@
+diff -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/sshconnection.cpp qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshconnection.cpp
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/sshconnection.cpp 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshconnection.cpp 2015-03-09 14:57:06.409045144 +0100
+@@ -65,7 +65,8 @@ namespace QSsh {
+ const QByteArray ClientId("SSH-2.0-QtCreator\r\n");
+
+ SshConnectionParameters::SshConnectionParameters() :
+- timeout(0), authenticationType(AuthenticationTypePublicKey), port(0)
++ timeout(0), authenticationType(AuthenticationTypePublicKey), port(0),
++ hostKeyCheckingMode(SshHostKeyCheckingNone)
+ {
+ options |= SshIgnoreDefaultProxy;
+ options |= SshEnableStrictConformanceChecks;
+@@ -77,6 +78,7 @@ static inline bool equals(const SshConne
+ && p1.authenticationType == p2.authenticationType
+ && (p1.authenticationType == SshConnectionParameters::AuthenticationTypePassword ?
+ p1.password == p2.password : p1.privateKeyFile == p2.privateKeyFile)
++ && p1.hostKeyCheckingMode == p2.hostKeyCheckingMode
+ && p1.timeout == p2.timeout && p1.port == p2.port;
+ }
+
+@@ -90,7 +92,6 @@ bool operator!=(const SshConnectionParam
+ return !equals(p1, p2);
+ }
+
+-// TODO: Mechanism for checking the host key. First connection to host: save, later: compare
+
+ SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent)
+ : QObject(parent)
+@@ -411,7 +412,7 @@ void SshConnectionPrivate::handleServerI
+ }
+ }
+
+- m_keyExchange.reset(new SshKeyExchange(m_sendFacility));
++ m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility));
+ m_keyExchange->sendKexInitPacket(m_serverId);
+ m_keyExchangeState = KexInitSent;
+ }
+@@ -460,7 +461,7 @@ void SshConnectionPrivate::handleKeyExch
+
+ // Server-initiated re-exchange.
+ if (m_keyExchangeState == NoKeyExchange) {
+- m_keyExchange.reset(new SshKeyExchange(m_sendFacility));
++ m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility));
+ m_keyExchange->sendKexInitPacket(m_serverId);
+ }
+
+diff -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/sshconnection.h qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshconnection.h
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/sshconnection.h 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshconnection.h 2015-03-09 14:57:06.410045167 +0100
+@@ -32,6 +32,7 @@
+ #define SSHCONNECTION_H
+
+ #include "ssherrors.h"
++#include "sshhostkeydatabase.h"
+
+ #include "ssh_global.h"
+
+@@ -56,6 +57,13 @@ enum SshConnectionOption {
+
+ Q_DECLARE_FLAGS(SshConnectionOptions, SshConnectionOption)
+
++enum SshHostKeyCheckingMode {
++ SshHostKeyCheckingNone,
++ SshHostKeyCheckingStrict,
++ SshHostKeyCheckingAllowNoMatch,
++ SshHostKeyCheckingAllowMismatch
++};
++
+ class QSSH_EXPORT SshConnectionParameters
+ {
+ public:
+@@ -78,6 +86,8 @@ public:
+ AuthenticationType authenticationType;
+ quint16 port;
+ SshConnectionOptions options;
++ SshHostKeyCheckingMode hostKeyCheckingMode;
++ SshHostKeyDatabasePtr hostKeyDatabase;
+ };
+
+ QSSH_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
+diff -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/sshhostkeydatabase.cpp qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshhostkeydatabase.cpp
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/sshhostkeydatabase.cpp 1970-01-01 01:00:00.000000000 +0100
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshhostkeydatabase.cpp 2015-03-09 14:57:06.410045167 +0100
+@@ -0,0 +1,120 @@
++/****************************************************************************
++**
++** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
++** Contact: http://www.qt-project.org/legal
++**
++** 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 Digia. For licensing terms and
++** conditions see http://www.qt.io/licensing. For further information
++** use the contact form at http://www.qt.io/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 2.1 or version 3 as published by the Free
++** Software Foundation and appearing in the file LICENSE.LGPLv21 and
++** LICENSE.LGPLv3 included in the packaging of this file. Please review the
++** following information to ensure the GNU Lesser General Public License
++** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
++** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
++**
++** In addition, as a special exception, Digia gives you certain additional
++** rights. These rights are described in the Digia Qt LGPL Exception
++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
++**
++****************************************************************************/
++#include "sshhostkeydatabase.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) {
++ qDebug("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.find(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 -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/sshhostkeydatabase.h qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshhostkeydatabase.h
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/sshhostkeydatabase.h 1970-01-01 01:00:00.000000000 +0100
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshhostkeydatabase.h 2015-03-09 14:57:06.410045167 +0100
+@@ -0,0 +1,73 @@
++/****************************************************************************
++**
++** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
++** Contact: http://www.qt-project.org/legal
++**
++** 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 Digia. For licensing terms and
++** conditions see http://www.qt.io/licensing. For further information
++** use the contact form at http://www.qt.io/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 2.1 or version 3 as published by the Free
++** Software Foundation and appearing in the file LICENSE.LGPLv21 and
++** LICENSE.LGPLv3 included in the packaging of this file. Please review the
++** following information to ensure the GNU Lesser General Public License
++** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
++** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
++**
++** In addition, as a special exception, Digia gives you certain additional
++** rights. These rights are described in the Digia Qt LGPL Exception
++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
++**
++****************************************************************************/
++#ifndef SSHHOSTKEYDATABASE_H
++#define SSHHOSTKEYDATABASE_H
++
++#include "ssh_global.h"
++
++#include <QSharedPointer>
++
++QT_BEGIN_NAMESPACE
++class QByteArray;
++class QString;
++QT_END_NAMESPACE
++
++namespace QSsh {
++class SshHostKeyDatabase;
++typedef QSharedPointer<SshHostKeyDatabase> SshHostKeyDatabasePtr;
++
++class QSSH_EXPORT SshHostKeyDatabase
++{
++ friend class QSharedPointer<SshHostKeyDatabase>; // To give create() access to our constructor.
++
++public:
++ enum KeyLookupResult {
++ KeyLookupMatch,
++ KeyLookupNoMatch,
++ KeyLookupMismatch
++ };
++
++ ~SshHostKeyDatabase();
++
++ 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);
++
++private:
++ SshHostKeyDatabase();
++
++ class SshHostKeyDatabasePrivate;
++ SshHostKeyDatabasePrivate * const d;
++};
++
++} // namespace QSsh
++
++#endif // Include guard.
+diff -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/sshkeyexchange.cpp qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshkeyexchange.cpp
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/sshkeyexchange.cpp 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshkeyexchange.cpp 2015-03-09 14:57:06.411045190 +0100
+@@ -76,8 +76,9 @@ namespace {
+
+ } // anonymous namespace
+
+-SshKeyExchange::SshKeyExchange(SshSendFacility &sendFacility)
+- : m_sendFacility(sendFacility)
++SshKeyExchange::SshKeyExchange(const SshConnectionParameters &connParams,
++ SshSendFacility &sendFacility)
++ : m_connParams(connParams), m_sendFacility(sendFacility)
+ {
+ }
+
+@@ -210,8 +211,46 @@ void SshKeyExchange::sendNewKeysPacket(c
+ "Invalid signature in SSH_MSG_KEXDH_REPLY packet.");
+ }
+
++ checkHostKey(reply.k_s);
++
+ m_sendFacility.sendNewKeysPacket();
+ }
+
++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 -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/sshkeyexchange_p.h qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshkeyexchange_p.h
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/sshkeyexchange_p.h 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/sshkeyexchange_p.h 2015-03-09 14:57:06.411045190 +0100
+@@ -31,6 +31,8 @@
+ #ifndef SSHKEYEXCHANGE_P_H
+ #define SSHKEYEXCHANGE_P_H
+
++#include "sshconnection.h"
++
+ #include <QByteArray>
+ #include <QScopedPointer>
+
+@@ -48,7 +50,7 @@ class SshIncomingPacket;
+ class SshKeyExchange
+ {
+ public:
+- SshKeyExchange(SshSendFacility &sendFacility);
++ SshKeyExchange(const SshConnectionParameters &connParams, SshSendFacility &sendFacility);
+ ~SshKeyExchange();
+
+ void sendKexInitPacket(const QByteArray &serverId);
+@@ -68,6 +70,9 @@ public:
+ QByteArray hMacAlgoServerToClient() const { return m_s2cHMacAlgo; }
+
+ private:
++ void checkHostKey(const QByteArray &hostKey);
++ Q_NORETURN void throwHostKeyException();
++
+ QByteArray m_serverId;
+ QByteArray m_clientKexInitPayload;
+ QByteArray m_serverKexInitPayload;
+@@ -80,6 +85,7 @@ private:
+ QByteArray m_c2sHMacAlgo;
+ QByteArray m_s2cHMacAlgo;
+ QScopedPointer<Botan::HashFunction> m_hash;
++ const SshConnectionParameters m_connParams;
+ SshSendFacility &m_sendFacility;
+ };
+
+diff -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/ssh.pro qt-creator-opensource-src-3.2.2-new/src/libs/ssh/ssh.pro
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/ssh.pro 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/ssh.pro 2015-03-09 14:57:06.408045121 +0100
+@@ -28,7 +28,8 @@ SOURCES = $$PWD/sshsendfacility.cpp \
+ $$PWD/sftpfilesystemmodel.cpp \
+ $$PWD/sshkeycreationdialog.cpp \
+ $$PWD/sshinit.cpp \
+- $$PWD/sshdirecttcpiptunnel.cpp
++ $$PWD/sshdirecttcpiptunnel.cpp \
++ $$PWD/sshhostkeydatabase.cpp
+
+ HEADERS = $$PWD/sshsendfacility_p.h \
+ $$PWD/sshremoteprocess.h \
+@@ -64,7 +65,8 @@ HEADERS = $$PWD/sshsendfacility_p.h \
+ $$PWD/ssh_global.h \
+ $$PWD/sshdirecttcpiptunnel_p.h \
+ $$PWD/sshinit_p.h \
+- $$PWD/sshdirecttcpiptunnel.h
++ $$PWD/sshdirecttcpiptunnel.h \
++ $$PWD/sshhostkeydatabase.h
+
+ FORMS = $$PWD/sshkeycreationdialog.ui
+
+diff -rupN qt-creator-opensource-src-3.2.2/src/libs/ssh/ssh.qbs qt-creator-opensource-src-3.2.2-new/src/libs/ssh/ssh.qbs
+--- qt-creator-opensource-src-3.2.2/src/libs/ssh/ssh.qbs 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/libs/ssh/ssh.qbs 2015-03-09 14:57:06.409045144 +0100
+@@ -28,6 +28,8 @@ QtcLibrary {
+ "sshdirecttcpiptunnel.h", "sshdirecttcpiptunnel_p.h", "sshdirecttcpiptunnel.cpp",
+ "ssherrors.h",
+ "sshexception_p.h",
++ "sshhostkeydatabase.cpp",
++ "sshhostkeydatabase.h",
+ "sshincomingpacket_p.h", "sshincomingpacket.cpp",
+ "sshinit_p.h", "sshinit.cpp",
+ "sshkeycreationdialog.cpp", "sshkeycreationdialog.h", "sshkeycreationdialog.ui",
+diff -rupN qt-creator-opensource-src-3.2.2/src/plugins/projectexplorer/devicesupport/devicemanager.cpp qt-creator-opensource-src-3.2.2-new/src/plugins/projectexplorer/devicesupport/devicemanager.cpp
+--- qt-creator-opensource-src-3.2.2/src/plugins/projectexplorer/devicesupport/devicemanager.cpp 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/plugins/projectexplorer/devicesupport/devicemanager.cpp 2015-03-09 14:57:06.411045190 +0100
+@@ -32,9 +32,11 @@
+ #include "idevicefactory.h"
+
+ #include <coreplugin/icore.h>
++#include <coreplugin/messagemanager.h>
+ #include <extensionsystem/pluginmanager.h>
+ #include <projectexplorer/project.h>
+ #include <projectexplorer/projectexplorerconstants.h>
++#include <ssh/sshhostkeydatabase.h>
+ #include <utils/qtcassert.h>
+ #include <utils/fileutils.h>
+ #include <utils/persistentsettings.h>
+@@ -74,6 +76,7 @@ public:
+ static DeviceManager *clonedInstance;
+ QList<IDevice::Ptr> devices;
+ QHash<Core::Id, Core::Id> defaultDevices;
++ QSsh::SshHostKeyDatabasePtr hostKeyDatabase;
+
+ Utils::PersistentSettingsWriter *writer;
+ };
+@@ -135,6 +138,7 @@ void DeviceManager::save()
+ QVariantMap data;
+ data.insert(QLatin1String(DeviceManagerKey), toMap());
+ d->writer->save(data, Core::ICore::mainWindow());
++ d->hostKeyDatabase->store(hostKeysFilePath());
+ }
+
+ void DeviceManager::load()
+@@ -307,6 +311,11 @@ bool DeviceManager::isLoaded() const
+ return d->writer;
+ }
+
++QSsh::SshHostKeyDatabasePtr DeviceManager::hostKeyDatabase() const
++{
++ return d->hostKeyDatabase;
++}
++
+ void DeviceManager::setDefaultDevice(Core::Id id)
+ {
+ QTC_ASSERT(this != instance(), return);
+@@ -342,6 +351,13 @@ DeviceManager::DeviceManager(bool isInst
+ if (isInstance) {
+ QTC_ASSERT(!m_instance, return);
+ m_instance = this;
++ d->hostKeyDatabase = QSsh::SshHostKeyDatabasePtr::create();
++ const QString keyFilePath = hostKeysFilePath();
++ if (QFileInfo(keyFilePath).exists()) {
++ QString error;
++ if (!d->hostKeyDatabase->load(keyFilePath, &error))
++ Core::MessageManager::write(error);
++ }
+ connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), SLOT(save()));
+ }
+ }
+@@ -416,6 +432,11 @@ IDevice::ConstPtr DeviceManager::fromRaw
+ return fromRawPointer(const_cast<IDevice *>(device));
+ }
+
++QString DeviceManager::hostKeysFilePath()
++{
++ return settingsFilePath(QLatin1String("/ssh-hostkeys")).toString();
++}
++
+ } // namespace ProjectExplorer
+
+
+diff -rupN qt-creator-opensource-src-3.2.2/src/plugins/projectexplorer/devicesupport/devicemanager.h qt-creator-opensource-src-3.2.2-new/src/plugins/projectexplorer/devicesupport/devicemanager.h
+--- qt-creator-opensource-src-3.2.2/src/plugins/projectexplorer/devicesupport/devicemanager.h 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/plugins/projectexplorer/devicesupport/devicemanager.h 2015-03-09 14:57:06.412045213 +0100
+@@ -36,6 +36,7 @@
+
+ #include <QObject>
+
++namespace QSsh { class SshHostKeyDatabase; }
+ namespace Utils { class FileName; }
+
+ namespace ProjectExplorer {
+@@ -105,6 +106,8 @@ private:
+ IDevice::Ptr fromRawPointer(IDevice *device) const;
+ IDevice::ConstPtr fromRawPointer(const IDevice *device) const;
+
++ static QString hostKeysFilePath();
++ QSharedPointer<QSsh::SshHostKeyDatabase> hostKeyDatabase() const;
+ static Utils::FileName settingsFilePath(const QString &extension);
+ static Utils::FileName systemSettingsFilePath(const QString &deviceFileRelativePath);
+ static void copy(const DeviceManager *source, DeviceManager *target, bool deep);
+diff -rupN qt-creator-opensource-src-3.2.2/src/plugins/projectexplorer/devicesupport/idevice.cpp qt-creator-opensource-src-3.2.2-new/src/plugins/projectexplorer/devicesupport/idevice.cpp
+--- qt-creator-opensource-src-3.2.2/src/plugins/projectexplorer/devicesupport/idevice.cpp 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/plugins/projectexplorer/devicesupport/idevice.cpp 2015-03-09 14:57:06.412045213 +0100
+@@ -120,6 +120,7 @@ const char AuthKey[] = "Authentication";
+ const char KeyFileKey[] = "KeyFile";
+ const char PasswordKey[] = "Password";
+ const char TimeoutKey[] = "Timeout";
++const char HostKeyCheckingKey[] = "HostKeyChecking";
+
+ const char DebugServerKey[] = "DebugServerKey";
+
+@@ -158,7 +159,9 @@ PortsGatheringMethod::~PortsGatheringMet
+ DeviceTester::DeviceTester(QObject *parent) : QObject(parent) { }
+
+ IDevice::IDevice() : d(new Internal::IDevicePrivate)
+-{ }
++{
++ d->sshParameters.hostKeyDatabase = DeviceManager::instance()->hostKeyDatabase();
++}
+
+ IDevice::IDevice(Core::Id type, Origin origin, MachineType machineType, Core::Id id)
+ : d(new Internal::IDevicePrivate)
+@@ -168,6 +171,7 @@ IDevice::IDevice(Core::Id type, Origin o
+ d->machineType = machineType;
+ QTC_CHECK(origin == ManuallyAdded || id.isValid());
+ d->id = id.isValid() ? id : newId();
++ d->sshParameters.hostKeyDatabase = DeviceManager::instance()->hostKeyDatabase();
+ }
+
+ IDevice::IDevice(const IDevice &other) : d(new Internal::IDevicePrivate)
+@@ -309,6 +313,8 @@ void IDevice::fromMap(const QVariantMap
+ d->sshParameters.password = map.value(QLatin1String(PasswordKey)).toString();
+ d->sshParameters.privateKeyFile = map.value(QLatin1String(KeyFileKey), defaultPrivateKeyFilePath()).toString();
+ d->sshParameters.timeout = map.value(QLatin1String(TimeoutKey), DefaultTimeout).toInt();
++ d->sshParameters.hostKeyCheckingMode = static_cast<QSsh::SshHostKeyCheckingMode>
++ (map.value(QLatin1String(HostKeyCheckingKey), QSsh::SshHostKeyCheckingNone).toInt());
+
+ d->freePorts = Utils::PortList::fromString(map.value(QLatin1String(PortsSpecKey),
+ QLatin1String("10000-10100")).toString());
+@@ -340,6 +346,7 @@ QVariantMap IDevice::toMap() const
+ map.insert(QLatin1String(PasswordKey), d->sshParameters.password);
+ map.insert(QLatin1String(KeyFileKey), d->sshParameters.privateKeyFile);
+ map.insert(QLatin1String(TimeoutKey), d->sshParameters.timeout);
++ map.insert(QLatin1String(HostKeyCheckingKey), d->sshParameters.hostKeyCheckingMode);
+
+ map.insert(QLatin1String(PortsSpecKey), d->freePorts.toString());
+ map.insert(QLatin1String(VersionKey), d->version);
+@@ -379,6 +386,7 @@ QSsh::SshConnectionParameters IDevice::s
+ void IDevice::setSshParameters(const QSsh::SshConnectionParameters &sshParameters)
+ {
+ d->sshParameters = sshParameters;
++ d->sshParameters.hostKeyDatabase = DeviceManager::instance()->hostKeyDatabase();
+ }
+
+ QString IDevice::qmlProfilerHost() const
+diff -rupN qt-creator-opensource-src-3.2.2/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp qt-creator-opensource-src-3.2.2-new/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp
+--- qt-creator-opensource-src-3.2.2/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp 2015-03-09 14:57:06.412045213 +0100
+@@ -63,6 +63,8 @@ GenericLinuxDeviceConfigurationWidget::G
+ connect(m_ui->portsLineEdit, SIGNAL(editingFinished()), this, SLOT(handleFreePortsChanged()));
+ connect(m_ui->createKeyButton, SIGNAL(clicked()), SLOT(createNewKey()));
+ connect(m_ui->gdbServerLineEdit, SIGNAL(editingFinished()), SLOT(gdbServerEditingFinished()));
++ connect(m_ui->hostKeyCheckBox, &QCheckBox::toggled, this,
++ &GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged);
+
+ initGui();
+ }
+@@ -158,6 +160,14 @@ void GenericLinuxDeviceConfigurationWidg
+ setPrivateKey(dialog.privateKeyFilePath());
+ }
+
++void GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged(bool doCheck)
++{
++ SshConnectionParameters sshParams = device()->sshParameters();
++ sshParams.hostKeyCheckingMode
++ = doCheck ? QSsh::SshHostKeyCheckingAllowNoMatch : QSsh::SshHostKeyCheckingNone;
++ device()->setSshParameters(sshParams);
++}
++
+ void GenericLinuxDeviceConfigurationWidget::updateDeviceFromUi()
+ {
+ hostNameEditingFinished();
+@@ -200,6 +210,7 @@ void GenericLinuxDeviceConfigurationWidg
+ m_ui->timeoutSpinBox->setValue(sshParams.timeout);
+ m_ui->hostLineEdit->setEnabled(!device()->isAutoDetected());
+ m_ui->sshPortSpinBox->setEnabled(!device()->isAutoDetected());
++ m_ui->hostKeyCheckBox->setChecked(sshParams.hostKeyCheckingMode != SshHostKeyCheckingNone);
+
+ m_ui->hostLineEdit->setText(sshParams.host);
+ m_ui->sshPortSpinBox->setValue(sshParams.port);
+diff -rupN qt-creator-opensource-src-3.2.2/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h qt-creator-opensource-src-3.2.2-new/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h
+--- qt-creator-opensource-src-3.2.2/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h 2015-03-09 14:57:06.413045237 +0100
+@@ -62,6 +62,7 @@ private slots:
+ void handleFreePortsChanged();
+ void setPrivateKey(const QString &path);
+ void createNewKey();
++ void hostKeyCheckingChanged(bool doCheck);
+
+ private:
+ void updateDeviceFromUi();
+diff -rupN qt-creator-opensource-src-3.2.2/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui qt-creator-opensource-src-3.2.2-new/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui
+--- qt-creator-opensource-src-3.2.2/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui 2014-10-10 09:47:07.000000000 +0200
++++ qt-creator-opensource-src-3.2.2-new/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.ui 2015-03-09 14:57:06.413045237 +0100
+@@ -6,8 +6,8 @@
+ <rect>
+ <x>0</x>
+ <y>0</y>
+- <width>393</width>
+- <height>321</height>
++ <width>556</width>
++ <height>309</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+@@ -123,6 +123,13 @@
+ </property>
+ </widget>
+ </item>
++ <item>
++ <widget class="QCheckBox" name="hostKeyCheckBox">
++ <property name="text">
++ <string>&Check host key</string>
++ </property>
++ </widget>
++ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
More information about the scm-commits
mailing list