[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>&amp;Check host key</string>
++       </property>
++      </widget>
++     </item>
+     </layout>
+    </item>
+    <item row="3" column="0">


More information about the scm-commits mailing list