From 94548a1e1fbaf245da440bdf57a40e0c34bc88b9 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 14 Feb 2011 16:34:17 +0100 Subject: move src/plugins/coreplugin/ssh to src/lib/utils/ssh Merge-request: 253 Reviewed-by: hjk --- src/libs/libs.pro | 4 +- src/libs/utils/ssh/sftpchannel.cpp | 885 +++++++++++++++++++++ src/libs/utils/ssh/sftpchannel.h | 128 +++ src/libs/utils/ssh/sftpchannel_p.h | 133 ++++ src/libs/utils/ssh/sftpdefs.cpp | 36 + src/libs/utils/ssh/sftpdefs.h | 52 ++ src/libs/utils/ssh/sftpincomingpacket.cpp | 234 ++++++ src/libs/utils/ssh/sftpincomingpacket_p.h | 115 +++ src/libs/utils/ssh/sftpoperation.cpp | 187 +++++ src/libs/utils/ssh/sftpoperation_p.h | 232 ++++++ src/libs/utils/ssh/sftpoutgoingpacket.cpp | 206 +++++ src/libs/utils/ssh/sftpoutgoingpacket_p.h | 87 ++ src/libs/utils/ssh/sftppacket.cpp | 58 ++ src/libs/utils/ssh/sftppacket_p.h | 112 +++ src/libs/utils/ssh/sshbotanconversions_p.h | 101 +++ src/libs/utils/ssh/sshcapabilities.cpp | 107 +++ src/libs/utils/ssh/sshcapabilities_p.h | 76 ++ src/libs/utils/ssh/sshchannel.cpp | 264 ++++++ src/libs/utils/ssh/sshchannel_p.h | 129 +++ src/libs/utils/ssh/sshchannelmanager.cpp | 192 +++++ src/libs/utils/ssh/sshchannelmanager_p.h | 97 +++ src/libs/utils/ssh/sshconnection.cpp | 645 +++++++++++++++ src/libs/utils/ssh/sshconnection.h | 112 +++ src/libs/utils/ssh/sshconnection_p.h | 168 ++++ src/libs/utils/ssh/sshcryptofacility.cpp | 373 +++++++++ src/libs/utils/ssh/sshcryptofacility_p.h | 158 ++++ src/libs/utils/ssh/ssherrors.h | 47 ++ src/libs/utils/ssh/sshexception_p.h | 93 +++ src/libs/utils/ssh/sshincomingpacket.cpp | 462 +++++++++++ src/libs/utils/ssh/sshincomingpacket_p.h | 196 +++++ src/libs/utils/ssh/sshkeyexchange.cpp | 201 +++++ src/libs/utils/ssh/sshkeyexchange_p.h | 91 +++ src/libs/utils/ssh/sshkeygenerator.cpp | 150 ++++ src/libs/utils/ssh/sshkeygenerator.h | 79 ++ src/libs/utils/ssh/sshoutgoingpacket.cpp | 298 +++++++ src/libs/utils/ssh/sshoutgoingpacket_p.h | 104 +++ src/libs/utils/ssh/sshpacket.cpp | 171 ++++ src/libs/utils/ssh/sshpacket_p.h | 146 ++++ src/libs/utils/ssh/sshpacketparser.cpp | 157 ++++ src/libs/utils/ssh/sshpacketparser_p.h | 85 ++ src/libs/utils/ssh/sshremoteprocess.cpp | 237 ++++++ src/libs/utils/ssh/sshremoteprocess.h | 134 ++++ src/libs/utils/ssh/sshremoteprocess_p.h | 98 +++ src/libs/utils/ssh/sshremoteprocessrunner.cpp | 210 +++++ src/libs/utils/ssh/sshremoteprocessrunner.h | 44 + src/libs/utils/ssh/sshsendfacility.cpp | 210 +++++ src/libs/utils/ssh/sshsendfacility_p.h | 97 +++ src/libs/utils/utils-lib.pri | 50 +- src/libs/utils/utils.pro | 1 + src/plugins/coreplugin/coreplugin.pro | 46 -- src/plugins/coreplugin/ssh/sftpchannel.cpp | 885 --------------------- src/plugins/coreplugin/ssh/sftpchannel.h | 128 --- src/plugins/coreplugin/ssh/sftpchannel_p.h | 133 ---- src/plugins/coreplugin/ssh/sftpdefs.cpp | 36 - src/plugins/coreplugin/ssh/sftpdefs.h | 52 -- src/plugins/coreplugin/ssh/sftpincomingpacket.cpp | 234 ------ src/plugins/coreplugin/ssh/sftpincomingpacket_p.h | 115 --- src/plugins/coreplugin/ssh/sftpoperation.cpp | 187 ----- src/plugins/coreplugin/ssh/sftpoperation_p.h | 232 ------ src/plugins/coreplugin/ssh/sftpoutgoingpacket.cpp | 206 ----- src/plugins/coreplugin/ssh/sftpoutgoingpacket_p.h | 87 -- src/plugins/coreplugin/ssh/sftppacket.cpp | 58 -- src/plugins/coreplugin/ssh/sftppacket_p.h | 112 --- src/plugins/coreplugin/ssh/sshbotanconversions_p.h | 101 --- src/plugins/coreplugin/ssh/sshcapabilities.cpp | 107 --- src/plugins/coreplugin/ssh/sshcapabilities_p.h | 76 -- src/plugins/coreplugin/ssh/sshchannel.cpp | 264 ------ src/plugins/coreplugin/ssh/sshchannel_p.h | 129 --- src/plugins/coreplugin/ssh/sshchannelmanager.cpp | 192 ----- src/plugins/coreplugin/ssh/sshchannelmanager_p.h | 97 --- src/plugins/coreplugin/ssh/sshconnection.cpp | 645 --------------- src/plugins/coreplugin/ssh/sshconnection.h | 112 --- src/plugins/coreplugin/ssh/sshconnection_p.h | 168 ---- src/plugins/coreplugin/ssh/sshcryptofacility.cpp | 373 --------- src/plugins/coreplugin/ssh/sshcryptofacility_p.h | 158 ---- src/plugins/coreplugin/ssh/ssherrors.h | 47 -- src/plugins/coreplugin/ssh/sshexception_p.h | 93 --- src/plugins/coreplugin/ssh/sshincomingpacket.cpp | 462 ----------- src/plugins/coreplugin/ssh/sshincomingpacket_p.h | 196 ----- src/plugins/coreplugin/ssh/sshkeyexchange.cpp | 201 ----- src/plugins/coreplugin/ssh/sshkeyexchange_p.h | 91 --- src/plugins/coreplugin/ssh/sshkeygenerator.cpp | 150 ---- src/plugins/coreplugin/ssh/sshkeygenerator.h | 79 -- src/plugins/coreplugin/ssh/sshoutgoingpacket.cpp | 298 ------- src/plugins/coreplugin/ssh/sshoutgoingpacket_p.h | 104 --- src/plugins/coreplugin/ssh/sshpacket.cpp | 171 ---- src/plugins/coreplugin/ssh/sshpacket_p.h | 146 ---- src/plugins/coreplugin/ssh/sshpacketparser.cpp | 157 ---- src/plugins/coreplugin/ssh/sshpacketparser_p.h | 85 -- src/plugins/coreplugin/ssh/sshremoteprocess.cpp | 237 ------ src/plugins/coreplugin/ssh/sshremoteprocess.h | 134 ---- src/plugins/coreplugin/ssh/sshremoteprocess_p.h | 98 --- .../coreplugin/ssh/sshremoteprocessrunner.cpp | 210 ----- .../coreplugin/ssh/sshremoteprocessrunner.h | 44 - src/plugins/coreplugin/ssh/sshsendfacility.cpp | 210 ----- src/plugins/coreplugin/ssh/sshsendfacility_p.h | 97 --- src/plugins/debugger/debuggerplugin.cpp | 4 +- src/plugins/debugger/debuggerstartparameters.h | 6 +- src/plugins/debugger/gdb/remotegdbprocess.cpp | 26 +- src/plugins/debugger/gdb/remotegdbprocess.h | 16 +- src/plugins/debugger/lldb/lldbenginehost.cpp | 12 +- src/plugins/debugger/lldb/lldbenginehost.h | 18 +- .../qt-maemo/maemoconfigtestdialog.cpp | 6 +- .../qt-maemo/maemoconfigtestdialog.h | 6 +- .../qt-maemo/maemodebugsupport.cpp | 10 +- .../qt4projectmanager/qt-maemo/maemodebugsupport.h | 8 +- .../qt4projectmanager/qt-maemo/maemodeploystep.cpp | 15 +- .../qt4projectmanager/qt-maemo/maemodeploystep.h | 16 +- .../qt-maemo/maemodeviceconfigurations.cpp | 18 +- .../qt-maemo/maemodeviceconfigurations.h | 10 +- .../maemodeviceconfigurationssettingswidget.cpp | 5 +- .../maemodeviceconfigurationssettingswidget.h | 2 +- .../qt-maemo/maemodeviceconfigwizard.cpp | 12 +- .../qt-maemo/maemodeviceenvreader.cpp | 16 +- .../qt-maemo/maemodeviceenvreader.h | 4 +- .../qt4projectmanager/qt-maemo/maemoglobal.cpp | 10 +- .../qt4projectmanager/qt-maemo/maemoglobal.h | 4 +- .../qt-maemo/maemokeydeployer.cpp | 6 +- .../qt4projectmanager/qt-maemo/maemokeydeployer.h | 6 +- .../qt-maemo/maemopublisherfremantlefree.cpp | 3 +- .../qt-maemo/maemopublisherfremantlefree.h | 6 +- .../qt-maemo/maemoremotemounter.cpp | 6 +- .../qt-maemo/maemoremotemounter.h | 10 +- .../qt-maemo/maemoremoteprocesslist.cpp | 6 +- .../qt-maemo/maemoremoteprocesslist.h | 4 +- .../qt-maemo/maemosshconfigdialog.cpp | 4 +- .../qt-maemo/maemosshconfigdialog.h | 4 +- .../qt4projectmanager/qt-maemo/maemosshrunner.cpp | 8 +- .../qt4projectmanager/qt-maemo/maemosshrunner.h | 10 +- .../qt-maemo/maemousedportsgatherer.cpp | 8 +- .../qt-maemo/maemousedportsgatherer.h | 6 +- 131 files changed, 8405 insertions(+), 8401 deletions(-) create mode 100644 src/libs/utils/ssh/sftpchannel.cpp create mode 100644 src/libs/utils/ssh/sftpchannel.h create mode 100644 src/libs/utils/ssh/sftpchannel_p.h create mode 100644 src/libs/utils/ssh/sftpdefs.cpp create mode 100644 src/libs/utils/ssh/sftpdefs.h create mode 100644 src/libs/utils/ssh/sftpincomingpacket.cpp create mode 100644 src/libs/utils/ssh/sftpincomingpacket_p.h create mode 100644 src/libs/utils/ssh/sftpoperation.cpp create mode 100644 src/libs/utils/ssh/sftpoperation_p.h create mode 100644 src/libs/utils/ssh/sftpoutgoingpacket.cpp create mode 100644 src/libs/utils/ssh/sftpoutgoingpacket_p.h create mode 100644 src/libs/utils/ssh/sftppacket.cpp create mode 100644 src/libs/utils/ssh/sftppacket_p.h create mode 100644 src/libs/utils/ssh/sshbotanconversions_p.h create mode 100644 src/libs/utils/ssh/sshcapabilities.cpp create mode 100644 src/libs/utils/ssh/sshcapabilities_p.h create mode 100644 src/libs/utils/ssh/sshchannel.cpp create mode 100644 src/libs/utils/ssh/sshchannel_p.h create mode 100644 src/libs/utils/ssh/sshchannelmanager.cpp create mode 100644 src/libs/utils/ssh/sshchannelmanager_p.h create mode 100644 src/libs/utils/ssh/sshconnection.cpp create mode 100644 src/libs/utils/ssh/sshconnection.h create mode 100644 src/libs/utils/ssh/sshconnection_p.h create mode 100644 src/libs/utils/ssh/sshcryptofacility.cpp create mode 100644 src/libs/utils/ssh/sshcryptofacility_p.h create mode 100644 src/libs/utils/ssh/ssherrors.h create mode 100644 src/libs/utils/ssh/sshexception_p.h create mode 100644 src/libs/utils/ssh/sshincomingpacket.cpp create mode 100644 src/libs/utils/ssh/sshincomingpacket_p.h create mode 100644 src/libs/utils/ssh/sshkeyexchange.cpp create mode 100644 src/libs/utils/ssh/sshkeyexchange_p.h create mode 100644 src/libs/utils/ssh/sshkeygenerator.cpp create mode 100644 src/libs/utils/ssh/sshkeygenerator.h create mode 100644 src/libs/utils/ssh/sshoutgoingpacket.cpp create mode 100644 src/libs/utils/ssh/sshoutgoingpacket_p.h create mode 100644 src/libs/utils/ssh/sshpacket.cpp create mode 100644 src/libs/utils/ssh/sshpacket_p.h create mode 100644 src/libs/utils/ssh/sshpacketparser.cpp create mode 100644 src/libs/utils/ssh/sshpacketparser_p.h create mode 100644 src/libs/utils/ssh/sshremoteprocess.cpp create mode 100644 src/libs/utils/ssh/sshremoteprocess.h create mode 100644 src/libs/utils/ssh/sshremoteprocess_p.h create mode 100644 src/libs/utils/ssh/sshremoteprocessrunner.cpp create mode 100644 src/libs/utils/ssh/sshremoteprocessrunner.h create mode 100644 src/libs/utils/ssh/sshsendfacility.cpp create mode 100644 src/libs/utils/ssh/sshsendfacility_p.h delete mode 100644 src/plugins/coreplugin/ssh/sftpchannel.cpp delete mode 100644 src/plugins/coreplugin/ssh/sftpchannel.h delete mode 100644 src/plugins/coreplugin/ssh/sftpchannel_p.h delete mode 100644 src/plugins/coreplugin/ssh/sftpdefs.cpp delete mode 100644 src/plugins/coreplugin/ssh/sftpdefs.h delete mode 100644 src/plugins/coreplugin/ssh/sftpincomingpacket.cpp delete mode 100644 src/plugins/coreplugin/ssh/sftpincomingpacket_p.h delete mode 100644 src/plugins/coreplugin/ssh/sftpoperation.cpp delete mode 100644 src/plugins/coreplugin/ssh/sftpoperation_p.h delete mode 100644 src/plugins/coreplugin/ssh/sftpoutgoingpacket.cpp delete mode 100644 src/plugins/coreplugin/ssh/sftpoutgoingpacket_p.h delete mode 100644 src/plugins/coreplugin/ssh/sftppacket.cpp delete mode 100644 src/plugins/coreplugin/ssh/sftppacket_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshbotanconversions_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshcapabilities.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshcapabilities_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshchannel.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshchannel_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshchannelmanager.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshchannelmanager_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshconnection.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshconnection.h delete mode 100644 src/plugins/coreplugin/ssh/sshconnection_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshcryptofacility.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshcryptofacility_p.h delete mode 100644 src/plugins/coreplugin/ssh/ssherrors.h delete mode 100644 src/plugins/coreplugin/ssh/sshexception_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshincomingpacket.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshincomingpacket_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshkeyexchange.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshkeyexchange_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshkeygenerator.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshkeygenerator.h delete mode 100644 src/plugins/coreplugin/ssh/sshoutgoingpacket.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshoutgoingpacket_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshpacket.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshpacket_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshpacketparser.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshpacketparser_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshremoteprocess.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshremoteprocess.h delete mode 100644 src/plugins/coreplugin/ssh/sshremoteprocess_p.h delete mode 100644 src/plugins/coreplugin/ssh/sshremoteprocessrunner.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshremoteprocessrunner.h delete mode 100644 src/plugins/coreplugin/ssh/sshsendfacility.cpp delete mode 100644 src/plugins/coreplugin/ssh/sshsendfacility_p.h diff --git a/src/libs/libs.pro b/src/libs/libs.pro index 719cbe10fe..f33e687774 100644 --- a/src/libs/libs.pro +++ b/src/libs/libs.pro @@ -3,6 +3,7 @@ CONFIG += ordered QT += core gui SUBDIRS = \ + 3rdparty \ qtconcurrent \ aggregation \ extensionsystem \ @@ -13,8 +14,7 @@ SUBDIRS = \ qmljs \ glsl \ qmleditorwidgets \ - symbianutils \ - 3rdparty + symbianutils # Windows: Compile Qt Creator CDB extension if Debugging tools can be detected. win32 { diff --git a/src/libs/utils/ssh/sftpchannel.cpp b/src/libs/utils/ssh/sftpchannel.cpp new file mode 100644 index 0000000000..1fb19e0740 --- /dev/null +++ b/src/libs/utils/ssh/sftpchannel.cpp @@ -0,0 +1,885 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sftpchannel.h" +#include "sftpchannel_p.h" + +#include "sshexception_p.h" +#include "sshincomingpacket_p.h" +#include "sshsendfacility_p.h" + +#include +#include + +namespace Utils { + +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, SIGNAL(initialized()), this, SIGNAL(initialized()), + Qt::QueuedConnection); + connect(d, SIGNAL(initializationFailed(QString)), this, + SIGNAL(initializationFailed(QString)), Qt::QueuedConnection); + connect(d, SIGNAL(dataAvailable(Utils::SftpJobId, QString)), this, + SIGNAL(dataAvailable(Utils::SftpJobId, QString)), Qt::QueuedConnection); + connect(d, SIGNAL(finished(Utils::SftpJobId,QString)), this, + SIGNAL(finished(Utils::SftpJobId,QString)), Qt::QueuedConnection); + connect(d, SIGNAL(closed()), this, SIGNAL(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::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::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 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 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; +#ifdef CREATOR_SSH_DEBUG + qDebug("sftp subsystem initialized"); +#endif + 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 initializationFailed(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) +{ + qWarning("Unexpected extended data '%s' of type %d on SFTP channel.", + data.data(), type); +} + +void SftpChannelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) +{ + const char * const message = "Remote SFTP service exited with exit code %d"; +#ifdef CREATOR_SSH_DEBUG + qDebug(message, exitStatus.exitStatus); +#else + if (exitStatus.exitStatus != 0) + qWarning(message, exitStatus.exitStatus); +#endif +} + +void SftpChannelPrivate::handleExitSignal(const SshChannelExitSignal &signal) +{ + qWarning("Remote SFTP service killed; signal was %s", signal.signal.data()); +} + +void SftpChannelPrivate::handleCurrentPacket() +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("Handling SFTP packet of type %d", m_incomingPacket.type()); +#endif + 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."); + } + +#ifdef CREATOR_SSH_DEBUG + qDebug("sftp init received"); +#endif + const quint32 serverVersion = m_incomingPacket.extractServerVersion(); + if (serverVersion != ProtocolVersion) { + emit initializationFailed(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 job + = it.value().dynamicCast(); + 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(); + sendData(m_outgoingPacket.generateReadDir(op->remoteHandle, + op->jobId).rawData()); +} + +void SftpChannelPrivate::handleCreateFileHandle(const JobMap::Iterator &it) +{ + SftpCreateFile::Ptr op = it.value().staticCast(); + sendData(m_outgoingPacket.generateCloseHandle(op->remoteHandle, + op->jobId).rawData()); +} + +void SftpChannelPrivate::handleGetHandle(const JobMap::Iterator &it) +{ + SftpDownload::Ptr op = it.value().staticCast(); + 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(); + 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(); +#ifdef CREATOR_SSH_DEBUG + qDebug("%s: status = %d", Q_FUNC_INFO, response.status); +#endif + 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::RmDir: + case AbstractSftpOperation::Rm: + case AbstractSftpOperation::Rename: + case AbstractSftpOperation::CreateFile: + 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(); + if (op->parentJob == SftpUploadDir::Ptr()) { + handleStatusGeneric(it, response); + return; + } + if (op->parentJob->hasError) { + m_jobs.erase(it); + return; + } + + typedef QMap::Iterator DirIt; + DirIt dirIt = op->parentJob->mkdirsInProgress.find(op); + Q_ASSERT(dirIt != op->parentJob->mkdirsInProgress.end()); + const QString &remoteDir = dirIt.value().remoteDir; + if (response.status == SSH_FX_OK) { + emit dataAvailable(op->parentJob->jobId, + tr("Created remote directory '%1'.").arg(remoteDir)); + } else if (response.status == SSH_FX_FAILURE) { + emit dataAvailable(op->parentJob->jobId, + tr("Remote directory '%1' already exists.").arg(remoteDir)); + } else { + op->parentJob->setError(); + emit finished(op->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 + '/' + dirInfo.fileName(); + const SftpMakeDir::Ptr mkdirOp( + new SftpMakeDir(++m_nextJobId, remoteSubDir, op->parentJob)); + op->parentJob->mkdirsInProgress.insert(mkdirOp, + SftpUploadDir::Dir(dirInfo.absoluteFilePath(), remoteSubDir)); + createJob(mkdirOp); + } + + const QFileInfoList &fileInfos = localDir.entryInfoList(QDir::Files); + foreach (const QFileInfo &fileInfo, fileInfos) { + QSharedPointer localFile(new QFile(fileInfo.absoluteFilePath())); + if (!localFile->open(QIODevice::ReadOnly)) { + op->parentJob->setError(); + emit finished(op->parentJob->jobId, + tr("Could not open local file '%1': %2") + .arg(fileInfo.absoluteFilePath(), localFile->error())); + m_jobs.erase(it); + return; + } + + const QString remoteFilePath = remoteDir + '/' + fileInfo.fileName(); + SftpUploadFile::Ptr uploadFileOp(new SftpUploadFile(++m_nextJobId, + remoteFilePath, localFile, SftpOverwriteExisting, op->parentJob)); + createJob(uploadFileOp); + op->parentJob->uploadsInProgress.append(uploadFileOp); + } + + op->parentJob->mkdirsInProgress.erase(dirIt); + if (op->parentJob->mkdirsInProgress.isEmpty() + && op->parentJob->uploadsInProgress.isEmpty()) + emit finished(op->parentJob->jobId); + m_jobs.erase(it); +} + +void SftpChannelPrivate::handleLsStatus(const JobMap::Iterator &it, + const SftpStatusResponse &response) +{ + SftpListDir::Ptr op = it.value().staticCast(); + 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(); + 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 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(); + 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(); + if (op->state != SftpListDir::Open) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_FXP_NAME packet."); + } + + for (int i = 0; i < response.files.count(); ++i) { + const SftpFile &file = response.files.at(i); + emit dataAvailable(op->jobId, file.fileName); + } + 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(); + 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); + AbstractSftpTransfer::Ptr transfer + = it.value().dynamicCast(); + 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(); + 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(); + 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() +{ + m_jobs.clear(); + m_incomingData.clear(); + m_incomingPacket.clear(); + emit closed(); +} + +void SftpChannelPrivate::handleOpenSuccessInternal() +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("SFTP session started"); +#endif + m_sendFacility.sendSftpPacket(remoteChannel()); + m_sftpState = SubsystemRequested; +} + +void SftpChannelPrivate::handleOpenFailureInternal() +{ + if (channelState() != SessionRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet."); + } + emit initializationFailed(tr("Server could not start session.")); +} + +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(); + 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::removeTransferRequest(const JobMap::Iterator &it) +{ + --it.value().staticCast()->inFlightCount; + m_jobs.erase(it); +} + +void SftpChannelPrivate::sendWriteRequest(const JobMap::Iterator &it) +{ + SftpUploadFile::Ptr job = it.value().staticCast(); + 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(); + 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 Utils diff --git a/src/libs/utils/ssh/sftpchannel.h b/src/libs/utils/ssh/sftpchannel.h new file mode 100644 index 0000000000..d347f9ed68 --- /dev/null +++ b/src/libs/utils/ssh/sftpchannel.h @@ -0,0 +1,128 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTCHANNEL_H +#define SFTCHANNEL_H + +#include "sftpdefs.h" +#include "sftpincomingpacket_p.h" + +#include + +#include +#include +#include +#include + +namespace Utils { + +namespace Internal { +class SftpChannelPrivate; +class SshChannelManager; +class SshSendFacility; +} // namespace Internal + +/* + * This 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. + */ +class QTCREATOR_UTILS_EXPORT SftpChannel : public QObject +{ + Q_OBJECT + + friend class Internal::SftpChannelPrivate; + friend class Internal::SshChannelManager; +public: + typedef QSharedPointer Ptr; + + enum State { Uninitialized, Initializing, Initialized, Closing, Closed }; + State state() const; + + void initialize(); + void closeChannel(); + + 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 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 initializationFailed(const QString &reason); + void closed(); + + // error.isEmpty <=> finished successfully + void finished(Utils::SftpJobId job, const QString &error = QString()); + + /* + * This signal is only emitted by the "List Directory" operation, + * one file at a time. + // TODO: Also emit for each file copied by uploadDir(). + */ + void dataAvailable(Utils::SftpJobId job, const QString &data); + +private: + SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility); + + Internal::SftpChannelPrivate *d; +}; + +} // namespace Utils + +#endif // SFTPCHANNEL_H diff --git a/src/libs/utils/ssh/sftpchannel_p.h b/src/libs/utils/ssh/sftpchannel_p.h new file mode 100644 index 0000000000..13c8a1d0ae --- /dev/null +++ b/src/libs/utils/ssh/sftpchannel_p.h @@ -0,0 +1,133 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTCHANNEL_P_H +#define SFTCHANNEL_P_H + +#include "sftpdefs.h" +#include "sftpincomingpacket_p.h" +#include "sftpoperation_p.h" +#include "sftpoutgoingpacket_p.h" +#include "sshchannel_p.h" + +#include +#include + +namespace Utils { +class SftpChannel; +namespace Internal { + +class SftpChannelPrivate : public AbstractSshChannel +{ + Q_OBJECT + friend class Utils::SftpChannel; +public: + + enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized }; + + virtual void handleChannelSuccess(); + virtual void handleChannelFailure(); + + virtual void closeHook(); + +signals: + void initialized(); + void initializationFailed(const QString &reason); + void closed(); + void finished(Utils::SftpJobId job, const QString &error = QString()); + void dataAvailable(Utils::SftpJobId job, const QString &data); + +private: + typedef QMap JobMap; + + SftpChannelPrivate(quint32 channelId, SshSendFacility &sendFacility, + SftpChannel *sftp); + SftpJobId createJob(const AbstractSftpOperation::Ptr &job); + + virtual void handleOpenSuccessInternal(); + virtual void handleOpenFailureInternal(); + 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); + + 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); + + 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 Utils + +#endif // SFTPCHANNEL_P_H diff --git a/src/libs/utils/ssh/sftpdefs.cpp b/src/libs/utils/ssh/sftpdefs.cpp new file mode 100644 index 0000000000..61c810e53b --- /dev/null +++ b/src/libs/utils/ssh/sftpdefs.cpp @@ -0,0 +1,36 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sftpdefs.h" + +namespace Utils { const SftpJobId SftpInvalidJob = 0; } diff --git a/src/libs/utils/ssh/sftpdefs.h b/src/libs/utils/ssh/sftpdefs.h new file mode 100644 index 0000000000..4a268ebf37 --- /dev/null +++ b/src/libs/utils/ssh/sftpdefs.h @@ -0,0 +1,52 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTPDEFS_H +#define SFTPDEFS_H + +#include + +#include + +namespace Utils { + +typedef quint32 SftpJobId; +QTCREATOR_UTILS_EXPORT extern const SftpJobId SftpInvalidJob; + +enum SftpOverwriteMode { + SftpOverwriteExisting, SftpAppendToExisting, SftpSkipExisting +}; + +} // namespace Utils + +#endif // SFTPDEFS_H diff --git a/src/libs/utils/ssh/sftpincomingpacket.cpp b/src/libs/utils/ssh/sftpincomingpacket.cpp new file mode 100644 index 0000000000..72ca814ade --- /dev/null +++ b/src/libs/utils/ssh/sftpincomingpacket.cpp @@ -0,0 +1,234 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sftpincomingpacket_p.h" + +#include "sshexception_p.h" +#include "sshpacketparser_p.h" + +namespace Utils { +namespace Internal { + +namespace { + const int SSH_FILEXFER_ATTR_SIZE = 0x00000001; + const int SSH_FILEXFER_ATTR_UIDGID = 0x00000002; + const int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004; + const int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; + const int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000; +} // anonymous namespace + +SftpIncomingPacket::SftpIncomingPacket() : m_length(0) +{ +} + +void SftpIncomingPacket::consumeData(QByteArray &newData) +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("%s: current data size = %d, new data size = %d", Q_FUNC_INFO, + m_data.size(), newData.size()); +#endif + + 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(0)); + if (m_length < static_cast(TypeOffset + 1) + || m_length > MaxPacketSize) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid length field in SFTP packet."); + } + } + + moveFirstBytes(m_data, newData, + qMin(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 (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 (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(SshPacketParser::asUint32(m_data, &offset)); + response.errorString = SshPacketParser::asUserString(m_data, &offset); + response.language = SshPacketParser::asString(m_data, &offset); + return response; + } catch (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 (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 (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 (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 Utils diff --git a/src/libs/utils/ssh/sftpincomingpacket_p.h b/src/libs/utils/ssh/sftpincomingpacket_p.h new file mode 100644 index 0000000000..ab8defcaff --- /dev/null +++ b/src/libs/utils/ssh/sftpincomingpacket_p.h @@ -0,0 +1,115 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTPINCOMINGPACKET_P_H +#define SFTPINCOMINGPACKET_P_H + +#include "sftppacket_p.h" + +namespace Utils { +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 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 Utils + +#endif // SFTPINCOMINGPACKET_P_H diff --git a/src/libs/utils/ssh/sftpoperation.cpp b/src/libs/utils/ssh/sftpoperation.cpp new file mode 100644 index 0000000000..81a32c72fb --- /dev/null +++ b/src/libs/utils/ssh/sftpoperation.cpp @@ -0,0 +1,187 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sftpoperation_p.h" + +#include "sftpoutgoingpacket_p.h" + +#include + +namespace Utils { +namespace Internal { + +AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId) +{ +} + +AbstractSftpOperation::~AbstractSftpOperation() { } + + +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, const QString &path) + : AbstractSftpOperation(jobId), 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); +} + + +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, jobId); +} + + +const int AbstractSftpTransfer::MaxInFlightCount = 10; // Experimentally found to be enough. + +AbstractSftpTransfer::AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &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 &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 &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; + return packet.generateOpenFileForWriting(remotePath, mode, jobId); +} + + +SftpUploadDir::~SftpUploadDir() {} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sftpoperation_p.h b/src/libs/utils/ssh/sftpoperation_p.h new file mode 100644 index 0000000000..0cda2ac843 --- /dev/null +++ b/src/libs/utils/ssh/sftpoperation_p.h @@ -0,0 +1,232 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTPOPERATION_P_H +#define SFTPOPERATION_P_H + +#include "sftpdefs.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QFile; +QT_END_NAMESPACE + +namespace Utils { +namespace Internal { + +class SftpOutgoingPacket; + +struct AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + enum Type { + ListDir, MakeDir, RmDir, Rm, Rename, 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 SftpMakeDir : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpMakeDir(SftpJobId jobId, const QString &path, + const QSharedPointer &parentJob = QSharedPointer()); + virtual Type type() const { return MakeDir; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QSharedPointer parentJob; + const QString remoteDir; +}; + +struct SftpRmDir : public AbstractSftpOperation +{ + typedef QSharedPointer Ptr; + + SftpRmDir(SftpJobId jobId, const QString &path); + virtual Type type() const { return RmDir; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QString remoteDir; +}; + +struct SftpRm : public AbstractSftpOperation +{ + typedef QSharedPointer 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 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 AbstractSftpOperationWithHandle : public AbstractSftpOperation +{ + typedef QSharedPointer 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 Ptr; + + SftpListDir(SftpJobId jobId, const QString &path); + virtual Type type() const { return ListDir; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); +}; + + +struct SftpCreateFile : public AbstractSftpOperationWithHandle +{ + typedef QSharedPointer 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 Ptr; + + AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile); + ~AbstractSftpTransfer(); + void calculateInFlightCount(quint32 chunkSize); + + static const int MaxInFlightCount; + + const QSharedPointer localFile; + quint64 fileSize; + quint64 offset; + int inFlightCount; + bool statRequested; +}; + +struct SftpDownload : public AbstractSftpTransfer +{ + typedef QSharedPointer Ptr; + SftpDownload(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile); + virtual Type type() const { return Download; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + QMap offsets; + SftpJobId eofId; +}; + +struct SftpUploadFile : public AbstractSftpTransfer +{ + typedef QSharedPointer Ptr; + + SftpUploadFile(SftpJobId jobId, const QString &remotePath, + const QSharedPointer &localFile, SftpOverwriteMode mode, + const QSharedPointer &parentJob = QSharedPointer()); + virtual Type type() const { return UploadFile; } + virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); + + const QSharedPointer parentJob; + SftpOverwriteMode mode; +}; + +// Composite operation. +struct SftpUploadDir +{ + typedef QSharedPointer 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 uploadsInProgress; + QMap mkdirsInProgress; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SFTPOPERATION_P_H diff --git a/src/libs/utils/ssh/sftpoutgoingpacket.cpp b/src/libs/utils/ssh/sftpoutgoingpacket.cpp new file mode 100644 index 0000000000..21b29b67c4 --- /dev/null +++ b/src/libs/utils/ssh/sftpoutgoingpacket.cpp @@ -0,0 +1,206 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sftpoutgoingpacket_p.h" + +#include "sshpacket_p.h" + +#include + +namespace Utils { +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::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 requestId) +{ + return generateOpenFile(path, Write, mode, requestId); +} + +SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForReading(const QString &path, + quint32 requestId) +{ + // Note: Overwrite mode is irrelevant and will be ignored. + return generateOpenFile(path, Read, SftpSkipExisting, 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::generateOpenFile(const QString &path, + OpenType openType, SftpOverwriteMode mode, quint32 requestId) +{ + quint32 pFlags; + 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; + } + return init(SSH_FXP_OPEN, requestId).appendString(path).appendInt(pFlags) + .appendInt(DefaultAttributes).finalize(); +} + +SftpOutgoingPacket &SftpOutgoingPacket::init(SftpPacketType type, + quint32 requestId) +{ + m_data.resize(TypeOffset + 1); + m_data[TypeOffset] = type; + if (type != SSH_FXP_INIT) { + appendInt(requestId); +#ifdef CREATOR_SSH_DEBUG + qDebug("Generating SFTP packet of type %d with request id %u", type, + requestId); +#endif + } + 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; +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sftpoutgoingpacket_p.h b/src/libs/utils/ssh/sftpoutgoingpacket_p.h new file mode 100644 index 0000000000..b074da3d02 --- /dev/null +++ b/src/libs/utils/ssh/sftpoutgoingpacket_p.h @@ -0,0 +1,87 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTPOUTGOINGPACKET_P_H +#define SFTPOUTGOINGPACKET_P_H + +#include "sftppacket_p.h" +#include "sftpdefs.h" + +namespace Utils { +namespace Internal { + +class SftpOutgoingPacket : public AbstractSftpPacket +{ +public: + SftpOutgoingPacket(); + SftpOutgoingPacket &generateInit(quint32 version); + 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 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); + +private: + static QByteArray encodeString(const QString &string); + + enum OpenType { Read, Write }; + SftpOutgoingPacket &generateOpenFile(const QString &path, OpenType openType, + SftpOverwriteMode mode, 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 Utils + +#endif // SFTPOUTGOINGPACKET_P_H diff --git a/src/libs/utils/ssh/sftppacket.cpp b/src/libs/utils/ssh/sftppacket.cpp new file mode 100644 index 0000000000..271f96973a --- /dev/null +++ b/src/libs/utils/ssh/sftppacket.cpp @@ -0,0 +1,58 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sftppacket_p.h" + +#include "sshpacketparser_p.h" + +namespace Utils { +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 Utils diff --git a/src/libs/utils/ssh/sftppacket_p.h b/src/libs/utils/ssh/sftppacket_p.h new file mode 100644 index 0000000000..21bd26b68c --- /dev/null +++ b/src/libs/utils/ssh/sftppacket_p.h @@ -0,0 +1,112 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SFTPPACKET_P_H +#define SFTPPACKET_P_H + +#include +#include +#include + +namespace Utils { +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 +}; + +class AbstractSftpPacket +{ +public: + AbstractSftpPacket(); + quint32 requestId() const; + const QByteArray &rawData() const { return m_data; } + SftpPacketType type() const { return static_cast(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(m_data.size()); } + + static const int TypeOffset; + static const int RequestIdOffset; + static const int PayloadOffset; + + QByteArray m_data; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SFTPPACKET_P_H diff --git a/src/libs/utils/ssh/sshbotanconversions_p.h b/src/libs/utils/ssh/sshbotanconversions_p.h new file mode 100644 index 0000000000..517769d1b2 --- /dev/null +++ b/src/libs/utils/ssh/sshbotanconversions_p.h @@ -0,0 +1,101 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef BYTEARRAYCONVERSIONS_P_H +#define BYTEARRAYCONVERSIONS_P_H + +#include "sshcapabilities_p.h" + +#include +#include + +namespace Utils { +namespace Internal { + +inline const Botan::byte *convertByteArray(const QByteArray &a) +{ + return reinterpret_cast(a.constData()); +} + +inline Botan::byte *convertByteArray(QByteArray &a) +{ + return reinterpret_cast(a.data()); +} + +inline QByteArray convertByteArray(const Botan::SecureVector &v) +{ + return QByteArray(reinterpret_cast(v.begin()), v.size()); +} + +inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName) +{ + Q_ASSERT(rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1 + || rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1); + return rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1 + ? "modp/ietf/1024" : "modp/ietf/2048"; +} + +inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName) +{ + Q_ASSERT(rfcAlgoName == SshCapabilities::CryptAlgo3Des + || rfcAlgoName == SshCapabilities::CryptAlgoAes128); + return rfcAlgoName == SshCapabilities::CryptAlgo3Des + ? "TripleDES" : "AES-128"; +} + +inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName) +{ + Q_ASSERT(rfcAlgoName == SshCapabilities::PubKeyDss + || rfcAlgoName == SshCapabilities::PubKeyRsa); + return rfcAlgoName == SshCapabilities::PubKeyDss + ? "EMSA1(SHA-1)" : "EMSA3(SHA-1)"; +} + +inline const char *botanSha1Name() { return "SHA-1"; } + +inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName) +{ + Q_ASSERT(rfcAlgoName == SshCapabilities::HMacSha1); + return botanSha1Name(); +} + +inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName) +{ + Q_ASSERT(rfcAlgoName == SshCapabilities::HMacSha1); + return 20; +} + +} // namespace Internal +} // namespace Utils + +#endif // BYTEARRAYCONVERSIONS_P_H diff --git a/src/libs/utils/ssh/sshcapabilities.cpp b/src/libs/utils/ssh/sshcapabilities.cpp new file mode 100644 index 0000000000..389058c134 --- /dev/null +++ b/src/libs/utils/ssh/sshcapabilities.cpp @@ -0,0 +1,107 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshcapabilities_p.h" + +#include "sshexception_p.h" + +#include +#include + +namespace Utils { +namespace Internal { + +namespace { + QByteArray listAsByteArray(const QList &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 QList SshCapabilities::KeyExchangeMethods + = QList() << SshCapabilities::DiffieHellmanGroup1Sha1 + << SshCapabilities::DiffieHellmanGroup14Sha1; + +const QByteArray SshCapabilities::PubKeyDss("ssh-dss"); +const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa"); +const QList SshCapabilities::PublicKeyAlgorithms + = QList() << SshCapabilities::PubKeyRsa + << SshCapabilities::PubKeyDss; + +const QByteArray SshCapabilities::CryptAlgo3Des("3des-cbc"); +const QByteArray SshCapabilities::CryptAlgoAes128("aes128-cbc"); +const QList SshCapabilities::EncryptionAlgorithms + = QList() << SshCapabilities::CryptAlgoAes128 + << SshCapabilities::CryptAlgo3Des; + +const QByteArray SshCapabilities::HMacSha1("hmac-sha1"); +const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96"); +const QList SshCapabilities::MacAlgorithms + = QList() /* << SshCapabilities::HMacSha196 */ + << SshCapabilities::HMacSha1; + +const QList SshCapabilities::CompressionAlgorithms + = QList() << "none"; + +const QByteArray SshCapabilities::SshConnectionService("ssh-connection"); + +const QByteArray SshCapabilities::PublicKeyAuthMethod("publickey"); +const QByteArray SshCapabilities::PasswordAuthMethod("password"); + + +QByteArray SshCapabilities::findBestMatch(const QList &myCapabilities, + const QList &serverCapabilities) +{ + foreach (const QByteArray &myCapability, myCapabilities) { + if (serverCapabilities.contains(myCapability)) + return myCapability; + } + + 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(listAsByteArray(myCapabilities).data()) + .arg(listAsByteArray(serverCapabilities).data())); +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshcapabilities_p.h b/src/libs/utils/ssh/sshcapabilities_p.h new file mode 100644 index 0000000000..142ced7aea --- /dev/null +++ b/src/libs/utils/ssh/sshcapabilities_p.h @@ -0,0 +1,76 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CAPABILITIES_P_H +#define CAPABILITIES_P_H + +#include +#include + +namespace Utils { +namespace Internal { + +class SshCapabilities +{ +public: + static const QByteArray DiffieHellmanGroup1Sha1; + static const QByteArray DiffieHellmanGroup14Sha1; + static const QList KeyExchangeMethods; + + static const QByteArray PubKeyDss; + static const QByteArray PubKeyRsa; + static const QList PublicKeyAlgorithms; + + static const QByteArray CryptAlgo3Des; + static const QByteArray CryptAlgoAes128; + static const QList EncryptionAlgorithms; + + static const QByteArray HMacSha1; + static const QByteArray HMacSha196; + static const QList MacAlgorithms; + + static const QList CompressionAlgorithms; + + static const QByteArray SshConnectionService; + + static const QByteArray PublicKeyAuthMethod; + static const QByteArray PasswordAuthMethod; + + static QByteArray findBestMatch(const QList &myCapabilities, + const QList &serverCapabilities); +}; + +} // namespace Internal +} // namespace Utils + +#endif // CAPABILITIES_P_H diff --git a/src/libs/utils/ssh/sshchannel.cpp b/src/libs/utils/ssh/sshchannel.cpp new file mode 100644 index 0000000000..ebd22afe6e --- /dev/null +++ b/src/libs/utils/ssh/sshchannel.cpp @@ -0,0 +1,264 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshchannel_p.h" + +#include "sshincomingpacket_p.h" +#include "sshsendfacility_p.h" + +#include + +#include + +namespace Utils { +namespace Internal { + +namespace { + const quint32 MinMaxPacketSize = 32768; + const quint32 MaxPacketSize = 16 * 1024 * 1024; + const quint32 InitialWindowSize = MaxPacketSize; + const quint32 NoChannel = 0xffffffffu; +} // anonymous namespace + +AbstractSshChannel::AbstractSshChannel(quint32 channelId, + SshSendFacility &sendFacility) + : m_sendFacility(sendFacility), m_timeoutTimer(new QTimer(this)), + m_localChannel(channelId), m_remoteChannel(NoChannel), + m_localWindowSize(InitialWindowSize), m_remoteWindowSize(0), + m_state(Inactive) +{ + m_timeoutTimer->setSingleShot(true); + connect(m_timeoutTimer, SIGNAL(timeout()), this, SIGNAL(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 (Botan::Exception &e) { + m_errorString = QString::fromAscii(e.what()); + closeChannel(); + } +} + +void AbstractSshChannel::sendData(const QByteArray &data) +{ + try { + m_sendBuffer += data; + flushSendBuffer(); + } catch (Botan::Exception &e) { + m_errorString = QString::fromAscii(e.what()); + closeChannel(); + } +} + +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() +{ + const quint32 bytesToSend + = qMin(m_remoteWindowSize, m_sendBuffer.size()); + if (bytesToSend > 0) { + 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) +{ + if (m_state != SessionRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet."); + } + m_timeoutTimer->stop(); + + if (remoteMaxPacketSize < MinMaxPacketSize) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Maximum packet size too low."); + } + +#ifdef CREATOR_SSH_DEBUG + qDebug("Channel opened. remote channel id: %u, remote window size: %u, " + "remote max packet size: %u", + remoteChannelId, remoteWindowSize, remoteMaxPacketSize); +#endif + m_remoteChannel = remoteChannelId; + m_remoteWindowSize = remoteWindowSize; + m_remoteMaxPacketSize = remoteMaxPacketSize; + setChannelState(SessionEstablished); + handleOpenSuccessInternal(); +} + +void AbstractSshChannel::handleOpenFailure(const QString &reason) +{ + if (m_state != SessionRequested) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_OPEN_FAILURE packet."); + } + m_timeoutTimer->stop(); + +#ifdef CREATOR_SSH_DEBUG + qDebug("Channel open request failed for channel %u", m_localChannel); +#endif + m_errorString = reason; + handleOpenFailureInternal(); +} + +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; +} + +void AbstractSshChannel::handleChannelClose() +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("Receiving CLOSE for channel %u", m_localChannel); +#endif + 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. + qWarning("Ignoring unknown request type '%s'", requestType.data()); +} + +int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &data) +{ + checkChannelActive(); + + const int bytesToDeliver = qMin(data.size(), maxDataSize()); + if (bytesToDeliver != data.size()) + qWarning("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 { + setChannelState(CloseRequested); + m_sendFacility.sendChannelEofPacket(m_remoteChannel); + m_sendFacility.sendChannelClosePacket(m_remoteChannel); + } + } +} + +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 Utils diff --git a/src/libs/utils/ssh/sshchannel_p.h b/src/libs/utils/ssh/sshchannel_p.h new file mode 100644 index 0000000000..9dccc6819c --- /dev/null +++ b/src/libs/utils/ssh/sshchannel_p.h @@ -0,0 +1,129 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHCHANNEL_P_H +#define SSHCHANNEL_P_H + +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QTimer) + +namespace Utils { +namespace Internal { + +struct SshChannelExitSignal; +struct SshChannelExitStatus; +class SshIncomingPacket; +class SshSendFacility; + +class AbstractSshChannel : public QObject +{ + Q_OBJECT +public: + enum ChannelState { + Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed + }; + + ChannelState channelState() const { return m_state; } + void setChannelState(ChannelState state); + + void setError(const QString &error) { m_errorString = error; } + QString errorString() const { return m_errorString; } + + quint32 localChannelId() const { return m_localChannel; } + quint32 remoteChannel() const { return m_remoteChannel; } + + virtual void handleChannelSuccess()=0; + virtual void handleChannelFailure()=0; + + virtual void closeHook()=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 requestSessionStart(); + void sendData(const QByteArray &data); + void closeChannel(); + + virtual ~AbstractSshChannel(); + + static const int ReplyTimeout = 10000; // milli seconds + +signals: + void timeout(); + +protected: + AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility); + + quint32 maxDataSize() const; + void checkChannelActive(); + + SshSendFacility &m_sendFacility; + QTimer * const m_timeoutTimer; + +private: + virtual void handleOpenSuccessInternal()=0; + virtual void handleOpenFailureInternal()=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; + + void setState(ChannelState newState); + 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; + QString m_errorString; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHCHANNEL_P_H diff --git a/src/libs/utils/ssh/sshchannelmanager.cpp b/src/libs/utils/ssh/sshchannelmanager.cpp new file mode 100644 index 0000000000..a610d6815d --- /dev/null +++ b/src/libs/utils/ssh/sshchannelmanager.cpp @@ -0,0 +1,192 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshchannelmanager_p.h" + +#include "sftpchannel.h" +#include "sftpchannel_p.h" +#include "sshincomingpacket_p.h" +#include "sshremoteprocess.h" +#include "sshremoteprocess_p.h" +#include "sshsendfacility_p.h" + +#include + +namespace Utils { +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 &) +{ + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Server tried to open channel on client."); +} + +void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet) +{ + const SshChannelOpenFailure &failure = packet.extractChannelOpenFailure(); + ChannelIterator it = lookupChannelAsIterator(failure.localChannel); + try { + it.value()->handleOpenFailure(failure.reasonString); + } catch (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); + } +} + +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(); +} + +Utils::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteArray &command) +{ + SshRemoteProcess::Ptr proc(new SshRemoteProcess(command, m_nextLocalChannelId++, m_sendFacility)); + insertChannel(proc->d, proc); + return proc; +} + +Utils::SftpChannel::Ptr SshChannelManager::createSftpChannel() +{ + SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility)); + insertChannel(sftp->d, sftp); + return sftp; +} + +void SshChannelManager::insertChannel(AbstractSshChannel *priv, + const QSharedPointer &pub) +{ + connect(priv, SIGNAL(timeout()), this, SIGNAL(timeout())); + m_channels.insert(priv->localChannelId(), priv); + m_sessions.insert(priv, pub); +} + +void SshChannelManager::closeAllChannels() +{ + for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) + it.value()->closeChannel(); + m_channels.clear(); + m_sessions.clear(); +} + +void SshChannelManager::removeChannel(ChannelIterator it) +{ + Q_ASSERT(it != m_channels.end() && "Unexpected channel lookup failure."); + const int removeCount = m_sessions.remove(it.value()); + Q_ASSERT(removeCount == 1 && "Session for channel not found."); + m_channels.erase(it); +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshchannelmanager_p.h b/src/libs/utils/ssh/sshchannelmanager_p.h new file mode 100644 index 0000000000..ef7ed5a4fa --- /dev/null +++ b/src/libs/utils/ssh/sshchannelmanager_p.h @@ -0,0 +1,97 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHCHANNELLAYER_P_H +#define SSHCHANNELLAYER_P_H + +#include +#include +#include + +namespace Utils { + +class SftpChannel; +class SshRemoteProcess; + +namespace Internal { + +class AbstractSshChannel; +class SshIncomingPacket; +class SshSendFacility; + +class SshChannelManager : public QObject +{ + Q_OBJECT +public: + SshChannelManager(SshSendFacility &sendFacility, QObject *parent); + + QSharedPointer createRemoteProcess(const QByteArray &command); + QSharedPointer createSftpChannel(); + void closeAllChannels(); + + 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); + +signals: + void timeout(); + +private: + typedef QHash::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 &pub); + + SshSendFacility &m_sendFacility; + QHash m_channels; + QHash > m_sessions; + quint32 m_nextLocalChannelId; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHCHANNELLAYER_P_H diff --git a/src/libs/utils/ssh/sshconnection.cpp b/src/libs/utils/ssh/sshconnection.cpp new file mode 100644 index 0000000000..f749f1da63 --- /dev/null +++ b/src/libs/utils/ssh/sshconnection.cpp @@ -0,0 +1,645 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshconnection.h" +#include "sshconnection_p.h" + +#include "sftpchannel.h" +#include "sshcapabilities_p.h" +#include "sshchannelmanager_p.h" +#include "sshcryptofacility_p.h" +#include "sshexception_p.h" +#include "sshkeyexchange_p.h" + +#include + +#include +#include + +#include +#include +#include +#include + +namespace Utils { + +namespace { + const QByteArray ClientId("SSH-2.0-QtCreator\r\n"); + + bool staticInitializationsDone = false; + QMutex staticInitMutex; + + void doStaticInitializationsIfNecessary() + { + if (!staticInitializationsDone) { + staticInitMutex.lock(); + if (!staticInitializationsDone) { + Botan::LibraryInitializer::initialize("thread_safe=true"); + qRegisterMetaType("Utils::SshError"); + qRegisterMetaType("Utils::SftpJobId"); + staticInitializationsDone = true; + } + staticInitMutex.unlock(); + } + } +} // anonymous namespace + + +SshConnectionParameters::SshConnectionParameters(ProxyType proxyType) : + timeout(0), authType(AuthByKey), port(0), proxyType(proxyType) +{ +} + +static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2) +{ + return p1.host == p2.host && p1.uname == p2.uname + && p1.authType == p2.authType + && (p1.authType == SshConnectionParameters::AuthByPwd ? + p1.pwd == p2.pwd : p1.privateKeyFile == p2.privateKeyFile) + && p1.timeout == p2.timeout && p1.port == p2.port; +} + +QTCREATOR_UTILS_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2) +{ + return equals(p1, p2); +} + +QTCREATOR_UTILS_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2) +{ + return !equals(p1, p2); +} + +// TODO: Mechanism for checking the host key. First connection to host: save, later: compare + +SshConnection::Ptr SshConnection::create() +{ + doStaticInitializationsIfNecessary(); + return Ptr(new SshConnection); +} + +SshConnection::SshConnection() : d(new Internal::SshConnectionPrivate(this)) +{ + connect(d, SIGNAL(connected()), this, SIGNAL(connected()), + Qt::QueuedConnection); + connect(d, SIGNAL(dataAvailable(QString)), this, + SIGNAL(dataAvailable(QString)), Qt::QueuedConnection); + connect(d, SIGNAL(disconnected()), this, SIGNAL(disconnected()), + Qt::QueuedConnection); + connect(d, SIGNAL(error(Utils::SshError)), this, + SIGNAL(error(Utils::SshError)), Qt::QueuedConnection); +} + +void SshConnection::connectToHost(const SshConnectionParameters &serverInfo) +{ + d->connectToHost(serverInfo); +} + +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->error(); +} + +QString SshConnection::errorString() const +{ + return d->errorString(); +} + +SshConnectionParameters SshConnection::connectionParameters() const +{ + return d->m_connParams; +} + +SshConnection::~SshConnection() +{ + disconnect(); + disconnectFromHost(); + delete d; +} + +QSharedPointer SshConnection::createRemoteProcess(const QByteArray &command) +{ + QTC_ASSERT(state() == Connected, return QSharedPointer()); + return d->createRemoteProcess(command); +} + +QSharedPointer SshConnection::createSftpChannel() +{ + QTC_ASSERT(state() == Connected, return QSharedPointer()); + return d->createSftpChannel(); +} + + +namespace Internal { + +SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn) + : m_socket(new QTcpSocket(this)), m_state(SocketUnconnected), + m_sendFacility(m_socket), + m_channelManager(new SshChannelManager(m_sendFacility, this)), + m_connParams(SshConnectionParameters::DefaultProxy), + m_error(SshNoError), m_ignoreNextPacket(false), m_conn(conn) +{ + setupPacketHandlers(); + m_timeoutTimer.setSingleShot(true); + m_keepAliveTimer.setSingleShot(true); + m_keepAliveTimer.setInterval(10000); + connect(m_channelManager, SIGNAL(timeout()), this, SLOT(handleTimeout())); +} + +SshConnectionPrivate::~SshConnectionPrivate() +{ + disconnect(); +} + +void SshConnectionPrivate::setupPacketHandlers() +{ + typedef SshConnectionPrivate This; + + setupPacketHandler(SSH_MSG_KEXINIT, StateList() << SocketConnected, + &This::handleKeyExchangeInitPacket); + setupPacketHandler(SSH_MSG_KEXDH_REPLY, StateList() << KeyExchangeStarted, + &This::handleKeyExchangeReplyPacket); + + setupPacketHandler(SSH_MSG_NEWKEYS, StateList() << KeyExchangeSuccess, + &This::handleNewKeysPacket); + setupPacketHandler(SSH_MSG_SERVICE_ACCEPT, + StateList() << UserAuthServiceRequested, + &This::handleServiceAcceptPacket); + 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); + + 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 + << KeyExchangeStarted << KeyExchangeSuccess + << UserAuthServiceRequested << UserAuthRequested + << ConnectionEstablished, &This::handleDisconnect); + + setupPacketHandler(SSH_MSG_UNIMPLEMENTED, + StateList() << ConnectionEstablished, &This::handleUnimplementedPacket); +} + +void SshConnectionPrivate::setupPacketHandler(SshPacketType type, + const SshConnectionPrivate::StateList &states, + SshConnectionPrivate::PacketHandler handler) +{ + m_packetHandlers.insert(type, HandlerInStates(states, handler)); +} + +void SshConnectionPrivate::handleSocketConnected() +{ + m_state = SocketConnected; + sendData(ClientId); +} + +void SshConnectionPrivate::handleIncomingData() +{ + if (m_state == SocketUnconnected) + return; // For stuff queued in the event loop after we've called closeConnection(); + + try { + if (!canUseSocket()) + return; + m_incomingData += m_socket->readAll(); +#ifdef CREATOR_SSH_DEBUG + qDebug("state = %d, remote data size = %d", m_state, + m_incomingData.count()); +#endif + if (m_state == SocketConnected) + handleServerId(); + handlePackets(); + } catch (SshServerException &e) { + closeConnection(e.error, SshProtocolError, e.errorStringServer, + tr("SSH Protocol error: %1").arg(e.errorStringUser)); + } catch (SshClientException &e) { + closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "", + e.errorString); + } catch (Botan::Exception &e) { + closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "", + tr("Botan library exception: %1").arg(e.what())); + } +} + +void SshConnectionPrivate::handleServerId() +{ + const int idOffset = m_incomingData.indexOf("SSH-"); + if (idOffset == -1) + return; + m_incomingData.remove(0, idOffset); + if (m_incomingData.size() < 7) + return; + const QByteArray &version = m_incomingData.mid(4, 3); + if (version != "2.0") { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, + "Invalid protocol version.", + tr("Invalid protocol version: Expected '2.0', got '%1'.") + .arg(SshPacketParser::asUserString(version))); + } + const int endOffset = m_incomingData.indexOf("\r\n"); + if (endOffset == -1) + return; + if (m_incomingData.at(7) != '-') { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid server id.", tr("Invalid server id '%1'.") + .arg(SshPacketParser::asUserString(m_incomingData))); + } + + m_keyExchange.reset(new SshKeyExchange(m_sendFacility)); + m_keyExchange->sendKexInitPacket(m_incomingData.left(endOffset)); + m_incomingData.remove(0, endOffset + 2); +} + +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_state == KeyExchangeStarted || !m_ignoreNextPacket); + + if (m_ignoreNextPacket) { + m_ignoreNextPacket = false; + return; + } + + QHash::ConstIterator it + = m_packetHandlers.find(m_incomingPacket.type()); + if (it == m_packetHandlers.end()) { + m_sendFacility.sendMsgUnimplementedPacket(m_incomingPacket.serverSeqNr()); + return; + } + if (!it.value().first.contains(m_state)) { + throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, + "Unexpected packet.", tr("Unexpected packet of type %1.") + .arg(m_incomingPacket.type())); + } + (this->*it.value().second)(); +} + +void SshConnectionPrivate::handleKeyExchangeInitPacket() +{ + // If the server sends a guessed packet, the guess must be wrong, + // because the algorithms we support requires us to initiate the + // key exchange. + if (m_keyExchange->sendDhInitPacket(m_incomingPacket)) + m_ignoreNextPacket = true; + m_state = KeyExchangeStarted; +} + +void SshConnectionPrivate::handleKeyExchangeReplyPacket() +{ + m_keyExchange->sendNewKeysPacket(m_incomingPacket, + ClientId.left(ClientId.size() - 2)); + m_sendFacility.recreateKeys(*m_keyExchange); + m_state = KeyExchangeSuccess; +} + +void SshConnectionPrivate::handleNewKeysPacket() +{ + m_incomingPacket.recreateKeys(*m_keyExchange); + m_keyExchange.reset(); + m_sendFacility.sendUserAuthServiceRequestPacket(); + m_state = UserAuthServiceRequested; +} + +void SshConnectionPrivate::handleServiceAcceptPacket() +{ + if (m_connParams.authType == SshConnectionParameters::AuthByPwd) { + m_sendFacility.sendUserAuthByPwdRequestPacket(m_connParams.uname.toUtf8(), + SshCapabilities::SshConnectionService, m_connParams.pwd.toUtf8()); + } else { + QFile privKeyFile(m_connParams.privateKeyFile); + bool couldOpen = privKeyFile.open(QIODevice::ReadOnly); + QByteArray contents; + if (couldOpen) + contents = privKeyFile.readAll(); + if (!couldOpen || privKeyFile.error() != QFile::NoError) { + throw SshClientException(SshKeyFileError, + tr("Could not read private key file: %1") + .arg(privKeyFile.errorString())); + } + + m_sendFacility.createAuthenticationKey(contents); + m_sendFacility.sendUserAuthByKeyRequestPacket(m_connParams.uname.toUtf8(), + SshCapabilities::SshConnectionService); + } + m_state = UserAuthRequested; +} + +void SshConnectionPrivate::handlePasswordExpiredPacket() +{ + if (m_connParams.authType == SshConnectionParameters::AuthByKey) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Got SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, but did not use password."); + } + + throw SshClientException(SshAuthenticationError, tr("Password expired.")); +} + +void SshConnectionPrivate::handleUserAuthBannerPacket() +{ + emit dataAvailable(m_incomingPacket.extractUserAuthBanner().message); +} + +void SshConnectionPrivate::handleGlobalRequest() +{ + m_sendFacility.sendRequestFailurePacket(); +} + +void SshConnectionPrivate::handleUserAuthSuccessPacket() +{ + m_state = ConnectionEstablished; + m_timeoutTimer.stop(); + emit connected(); + m_lastInvalidMsgSeqNr = InvalidSeqNr; + connect(&m_keepAliveTimer, SIGNAL(timeout()), SLOT(sendKeepAlivePacket())); + m_keepAliveTimer.start(); +} + +void SshConnectionPrivate::handleUserAuthFailurePacket() +{ + m_timeoutTimer.stop(); + const QString errorMsg = m_connParams.authType == SshConnectionParameters::AuthByPwd + ? tr("Server rejected password.") : tr("Server rejected key."); + throw SshClientException(SshAuthenticationError, errorMsg); +} +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.")); + } + 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); +} + +void SshConnectionPrivate::handleChannelData() +{ + m_channelManager->handleChannelData(m_incomingPacket); +} + +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::sendData(const QByteArray &data) +{ + if (canUseSocket()) + m_socket->write(data); +} + +void SshConnectionPrivate::handleSocketDisconnected() +{ + closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshClosedByServerError, + "Connection closed unexpectedly.", + tr("Connection closed unexpectedly.")); +} + +void SshConnectionPrivate::handleSocketError() +{ + if (m_error == SshNoError) { + closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshSocketError, + "Network error", m_socket->errorString()); + } +} + +void SshConnectionPrivate::handleTimeout() +{ + closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshTimeoutError, "", + tr("Timeout waiting for reply from server.")); +} + +void SshConnectionPrivate::sendKeepAlivePacket() +{ + Q_ASSERT(m_lastInvalidMsgSeqNr == InvalidSeqNr); + m_lastInvalidMsgSeqNr = m_sendFacility.nextClientSeqNr(); + m_sendFacility.sendInvalidPacket(); + m_timeoutTimer.start(5000); +} + +void SshConnectionPrivate::connectToHost(const SshConnectionParameters &serverInfo) +{ + m_incomingData.clear(); + m_incomingPacket.reset(); + m_sendFacility.reset(); + m_error = SshNoError; + m_ignoreNextPacket = false; + m_errorString.clear(); + connect(m_socket, SIGNAL(connected()), this, SLOT(handleSocketConnected())); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(handleIncomingData())); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(handleSocketError())); + connect(m_socket, SIGNAL(disconnected()), this, + SLOT(handleSocketDisconnected())); + connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(handleTimeout())); + this->m_connParams = serverInfo; + m_state = SocketConnecting; + m_timeoutTimer.start(m_connParams.timeout * 1000); + m_socket->setProxy(m_connParams.proxyType == SshConnectionParameters::DefaultProxy + ? QNetworkProxy::DefaultProxy : QNetworkProxy::NoProxy); + m_socket->connectToHost(serverInfo.host, serverInfo.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) + 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); + try { + m_channelManager->closeAllChannels(); + m_sendFacility.sendDisconnectPacket(sshError, serverErrorString); + } catch (Botan::Exception &) {} // 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; +} + +bool SshConnectionPrivate::canUseSocket() const +{ + return m_socket->isValid() + && m_socket->state() == QAbstractSocket::ConnectedState; +} + +QSharedPointer SshConnectionPrivate::createRemoteProcess(const QByteArray &command) +{ + return m_channelManager->createRemoteProcess(command); +} + +QSharedPointer SshConnectionPrivate::createSftpChannel() +{ + return m_channelManager->createSftpChannel(); +} + +const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast(-1); + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshconnection.h b/src/libs/utils/ssh/sshconnection.h new file mode 100644 index 0000000000..986ff776fe --- /dev/null +++ b/src/libs/utils/ssh/sshconnection.h @@ -0,0 +1,112 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHCONNECTION_H +#define SSHCONNECTION_H + +#include "ssherrors.h" + +#include + +#include +#include +#include +#include + +namespace Utils { +class SftpChannel; +class SshRemoteProcess; + +namespace Internal { +class SshConnectionPrivate; +} // namespace Internal + +struct QTCREATOR_UTILS_EXPORT SshConnectionParameters +{ + enum ProxyType { DefaultProxy, NoProxy }; + SshConnectionParameters(ProxyType proxyType); + + QString host; + QString uname; + QString pwd; + QString privateKeyFile; + int timeout; + enum AuthType { AuthByPwd, AuthByKey } authType; + quint16 port; + ProxyType proxyType; +}; + +QTCREATOR_UTILS_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2); +QTCREATOR_UTILS_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2); + +/* + * This class provides an SSH connection, implementing protocol version 2.0 + * It can spawn channels for remote execution and SFTP operations (version 3). + * It operates asynchronously (non-blocking) and is not thread-safe. + */ +class QTCREATOR_UTILS_EXPORT SshConnection : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(SshConnection) +public: + enum State { Unconnected, Connecting, Connected }; + typedef QSharedPointer Ptr; + + static Ptr create(); + + void connectToHost(const SshConnectionParameters &serverInfo); + void disconnectFromHost(); + State state() const; + SshError errorState() const; + QString errorString() const; + SshConnectionParameters connectionParameters() const; + ~SshConnection(); + + QSharedPointer createRemoteProcess(const QByteArray &command); + QSharedPointer createSftpChannel(); + +signals: + void connected(); + void disconnected(); + void dataAvailable(const QString &message); + void error(Utils::SshError); + +private: + SshConnection(); + + Internal::SshConnectionPrivate *d; +}; + +} // namespace Internal + +#endif // SSHCONNECTION_H diff --git a/src/libs/utils/ssh/sshconnection_p.h b/src/libs/utils/ssh/sshconnection_p.h new file mode 100644 index 0000000000..629db9a01d --- /dev/null +++ b/src/libs/utils/ssh/sshconnection_p.h @@ -0,0 +1,168 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHCONNECTION_P_H +#define SSHCONNECTION_P_H + +#include "sshconnection.h" +#include "sshexception_p.h" +#include "sshincomingpacket_p.h" +#include "sshremoteprocess.h" +#include "sshsendfacility_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QTcpSocket; +QT_END_NAMESPACE + +namespace Botan { class Exception; } + +namespace Utils { +class SftpChannel; + +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 + KeyExchangeStarted, // After server's KEXINIT message + KeyExchangeSuccess, // After server's DH_REPLY message + UserAuthServiceRequested, + UserAuthRequested, + + ConnectionEstablished // After service has been started + // ... +}; + +class SshConnectionPrivate : public QObject +{ + Q_OBJECT + friend class Utils::SshConnection; +public: + SshConnectionPrivate(SshConnection *conn); + ~SshConnectionPrivate(); + + void connectToHost(const SshConnectionParameters &serverInfo); + void closeConnection(SshErrorCode sshError, SshError userError, + const QByteArray &serverErrorString, const QString &userErrorString); + QSharedPointer createRemoteProcess(const QByteArray &command); + QSharedPointer createSftpChannel(); + SshStateInternal state() const { return m_state; } + SshError error() const { return m_error; } + QString errorString() const { return m_errorString; } + +signals: + void connected(); + void disconnected(); + void dataAvailable(const QString &message); + void error(Utils::SshError); + +private: + Q_SLOT void handleSocketConnected(); + Q_SLOT void handleIncomingData(); + Q_SLOT void handleSocketError(); + Q_SLOT void handleSocketDisconnected(); + Q_SLOT void handleTimeout(); + Q_SLOT void sendKeepAlivePacket(); + + void handleServerId(); + void handlePackets(); + void handleCurrentPacket(); + void handleKeyExchangeInitPacket(); + void handleKeyExchangeReplyPacket(); + void handleNewKeysPacket(); + void handleServiceAcceptPacket(); + void handlePasswordExpiredPacket(); + void handleUserAuthSuccessPacket(); + void handleUserAuthFailurePacket(); + void handleUserAuthBannerPacket(); + 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(); + bool canUseSocket() const; + + void sendData(const QByteArray &data); + + typedef void (SshConnectionPrivate::*PacketHandler)(); + typedef QList StateList; + void setupPacketHandlers(); + void setupPacketHandler(SshPacketType type, const StateList &states, + PacketHandler handler); + + typedef QPair HandlerInStates; + QHash m_packetHandlers; + + static const quint64 InvalidSeqNr; + + QTcpSocket *m_socket; + SshStateInternal m_state; + SshIncomingPacket m_incomingPacket; + SshSendFacility m_sendFacility; + SshChannelManager * const m_channelManager; + SshConnectionParameters m_connParams; + QByteArray m_incomingData; + SshError m_error; + QString m_errorString; + QScopedPointer m_keyExchange; + QTimer m_timeoutTimer; + QTimer m_keepAliveTimer; + bool m_ignoreNextPacket; + SshConnection *m_conn; + quint64 m_lastInvalidMsgSeqNr; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHCONNECTION_P_H diff --git a/src/libs/utils/ssh/sshcryptofacility.cpp b/src/libs/utils/ssh/sshcryptofacility.cpp new file mode 100644 index 0000000000..e2a9495e41 --- /dev/null +++ b/src/libs/utils/ssh/sshcryptofacility.cpp @@ -0,0 +1,373 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshcryptofacility_p.h" + +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "sshexception_p.h" +#include "sshkeyexchange_p.h" +#include "sshpacket_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace Botan; + +namespace Utils { +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); +} + +void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex) +{ + checkInvariant(); + + if (m_sessionId.isEmpty()) + m_sessionId = kex.h(); + Algorithm_Factory &af = global_state().algorithm_factory(); + const std::string &cryptAlgo = botanCryptAlgoName(cryptAlgoName(kex)); + BlockCipher * const cipher = af.prototype_block_cipher(cryptAlgo)->clone(); + + m_cipherBlockSize = cipher->BLOCK_SIZE; + const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize); + const InitializationVector iv(convertByteArray(ivData), m_cipherBlockSize); + + const quint32 keySize = max_keylength_of(cryptAlgo); + const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize); + SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize); + + BlockCipherMode * const cipherMode + = makeCipherMode(cipher, new Null_Padding, 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()); + const HashFunction * const hMacProto + = af.prototype_hash_function(botanHMacAlgoName(hMacAlgoName(kex))); + m_hMac.reset(new HMAC(hMacProto->clone())); + m_hMac->set_key(hMacKey); +} + +void SshAbstractCryptoFacility::convert(QByteArray &data, quint32 offset, + quint32 dataSize) const +{ + Q_ASSERT(offset + dataSize <= static_cast(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(data.constData()) + offset, + dataSize); + quint32 bytesRead = m_pipe->read(reinterpret_cast(data.data()) + offset, + dataSize, m_pipe->message_count() - 1); // Can't use Pipe::LAST_MESSAGE because of a VC bug. + Q_ASSERT(bytesRead == dataSize); +} + +QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data, + quint32 dataSize) const +{ + return m_sessionId.isEmpty() + ? QByteArray() + : convertByteArray(m_hMac->process(reinterpret_cast(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 key + = kex.hash()->process(convertByteArray(data), data.size()); + while (key.size() < length) { + SecureVector tmpKey; + tmpKey.append(convertByteArray(k), k.size()); + tmpKey.append(convertByteArray(h), h.size()); + tmpKey.append(key); + key.append(kex.hash()->process(tmpKey)); + } + return QByteArray(reinterpret_cast(key.begin()), 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-----"); + +QByteArray SshEncryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const +{ + return kex.encryptionAlgo(); +} + +QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const +{ + return kex.hMacAlgoClientToServer(); +} + +BlockCipherMode *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, + BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv, + const SymmetricKey &key) +{ + return new CBC_Encryption(cipher, paddingMethod, key, iv); +} + +void SshEncryptionFacility::encrypt(QByteArray &data) const +{ + convert(data, 0, data.size()); +} + +void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFileContents) +{ + if (privKeyFileContents == m_cachedPrivKeyContents) + return; + +#ifdef CREATOR_SSH_DEBUG + qDebug("%s: Key not cached, reading", Q_FUNC_INFO); +#endif + QList pubKeyParams; + QList allKeyParams; + try { + createAuthenticationKeyFromPKCS8(privKeyFileContents, pubKeyParams, + allKeyParams); + } catch (Botan::Exception &) { + createAuthenticationKeyFromOpenSSL(privKeyFileContents, pubKeyParams, + allKeyParams); + } + + foreach (const BigInt &b, allKeyParams) { + if (b.is_zero()) { + throw SshClientException(SshKeyFileError, + SSH_TR("Decoding of private key file failed.")); + } + } + + m_authPubKeyBlob = AbstractSshPacket::encodeString(m_authKeyAlgoName); + foreach (const BigInt &b, pubKeyParams) + m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b); + m_cachedPrivKeyContents = privKeyFileContents; +} + +void SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams) +{ + Pipe pipe; + pipe.process_msg(convertByteArray(privKeyFileContents), + privKeyFileContents.size()); + Private_Key * const key = PKCS8::load_key(pipe, m_rng); + if (DSA_PrivateKey * const dsaKey = dynamic_cast(key)) { + m_authKey.reset(dsaKey); + pubKeyParams << dsaKey->group_p() << dsaKey->group_q() + << dsaKey->group_g() << dsaKey->get_y(); + allKeyParams << pubKeyParams << dsaKey->get_x(); + } else if (RSA_PrivateKey * const rsaKey = dynamic_cast(key)) { + m_authKey.reset(rsaKey); + pubKeyParams << rsaKey->get_e() << rsaKey->get_n(); + allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q() + << rsaKey->get_d(); + } else { + throw Botan::Exception(); + } +} + +void SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams) +{ + bool syntaxOk = true; + QList 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 { + syntaxOk = false; + } + if (!syntaxOk) { + throw SshClientException(SshKeyFileError, + SSH_TR("Private key file has unexpected format.")); + } + + 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); + quint32 version; + sequence.decode (version); + if (version != 0) { + throw SshClientException(SshKeyFileError, + SSH_TR("Private key encoding has version %1, expected 0.") + .arg(version)); + } + + 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 { + BigInt p, q, e, d, n; + sequence.decode (n).decode (e).decode (d).decode (p).decode (q); + RSA_PrivateKey * const rsaKey + = new RSA_PrivateKey (m_rng, p, q, e, d, n); + m_authKey.reset(rsaKey); + pubKeyParams << e << n; + allKeyParams << pubKeyParams << p << q << d; + } + + sequence.discard_remaining(); + sequence.verify_end(); +} + +QByteArray SshEncryptionFacility::authenticationAlgorithmName() const +{ + Q_ASSERT(m_authKey); + return m_authKeyAlgoName; +} + +QByteArray SshEncryptionFacility::authenticationKeySignature(const QByteArray &data) const +{ + Q_ASSERT(m_authKey); + + QScopedPointer signer(get_pk_signer (*m_authKey, + botanEmsaAlgoName(m_authKeyAlgoName))); + QByteArray dataToSign = AbstractSshPacket::encodeString(sessionId()) + data; + QByteArray signature + = convertByteArray(signer->sign_message(convertByteArray(dataToSign), + dataToSign.size(), m_rng)); + 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(); +} + +BlockCipherMode *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, + BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv, + const SymmetricKey &key) +{ + return new CBC_Decryption(cipher, paddingMethod, key, iv); +} + +void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset, + quint32 dataSize) const +{ + convert(data, offset, dataSize); +#ifdef CREATOR_SSH_DEBUG + qDebug("Decrypted data:"); + const char * const start = data.constData() + offset; + const char * const end = start + dataSize; + for (const char *c = start; c < end; ++c) + qDebug() << "'" << *c << "' (0x" << (static_cast(*c) & 0xff) << ")"; +#endif +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshcryptofacility_p.h b/src/libs/utils/ssh/sshcryptofacility_p.h new file mode 100644 index 0000000000..494b3681e3 --- /dev/null +++ b/src/libs/utils/ssh/sshcryptofacility_p.h @@ -0,0 +1,158 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHABSTRACTCRYPTOFACILITY_P_H +#define SSHABSTRACTCRYPTOFACILITY_P_H + +#include +#include + +#include +#include + +namespace Botan { + class BigInt; + class BlockCipher; + class BlockCipherMode; + class BlockCipherModePaddingMethod; + class HashFunction; + class HMAC; + class Pipe; + class PK_Signing_Key; +} + +namespace Utils { +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; } + +protected: + SshAbstractCryptoFacility(); + void convert(QByteArray &data, quint32 offset, quint32 dataSize) const; + QByteArray sessionId() const { return m_sessionId; } + +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::BlockCipherMode *makeCipherMode(Botan::BlockCipher *cipher, + Botan::BlockCipherModePaddingMethod *paddingMethod, + 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; + + QByteArray m_sessionId; + QScopedPointer m_pipe; + QScopedPointer 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::BlockCipherMode *makeCipherMode(Botan::BlockCipher *cipher, + Botan::BlockCipherModePaddingMethod *paddingMethod, + 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'; } + + void createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams); + void createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, + QList &pubKeyParams, QList &allKeyParams); + + static const QByteArray PrivKeyFileStartLineRsa; + static const QByteArray PrivKeyFileStartLineDsa; + static const QByteArray PrivKeyFileEndLineRsa; + static const QByteArray PrivKeyFileEndLineDsa; + + QByteArray m_authKeyAlgoName; + QByteArray m_authPubKeyBlob; + QByteArray m_cachedPrivKeyContents; + QScopedPointer 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::BlockCipherMode *makeCipherMode(Botan::BlockCipher *cipher, + Botan::BlockCipherModePaddingMethod *paddingMethod, + 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 Utils + +#endif // SSHABSTRACTCRYPTOFACILITY_P_H diff --git a/src/libs/utils/ssh/ssherrors.h b/src/libs/utils/ssh/ssherrors.h new file mode 100644 index 0000000000..8fff4dc270 --- /dev/null +++ b/src/libs/utils/ssh/ssherrors.h @@ -0,0 +1,47 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHERRORS_P_H +#define SSHERRORS_P_H + +namespace Utils { + +enum SshError { + SshNoError, SshSocketError, SshTimeoutError, SshProtocolError, + SshHostKeyError, SshKeyFileError, SshAuthenticationError, + SshClosedByServerError, SshInternalError +}; + +} // namespace Utils + +#endif // SSHERRORS_P_H diff --git a/src/libs/utils/ssh/sshexception_p.h b/src/libs/utils/ssh/sshexception_p.h new file mode 100644 index 0000000000..7265db362a --- /dev/null +++ b/src/libs/utils/ssh/sshexception_p.h @@ -0,0 +1,93 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHEXCEPTION_P_H +#define SSHEXCEPTION_P_H + +#include "ssherrors.h" + +#include +#include +#include + +namespace Utils { +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 +{ + SshServerException(SshErrorCode error, const QByteArray &errorStringServer, + const QString &errorStringUser) + : error(error), errorStringServer(errorStringServer), + errorStringUser(errorStringUser) {} + + const SshErrorCode error; + const QByteArray errorStringServer; + const QString errorStringUser; +}; + +struct SshClientException +{ + SshClientException(SshError error, const QString &errorString) + : error(error), errorString(errorString) {} + + const SshError error; + const QString errorString; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHEXCEPTION_P_H diff --git a/src/libs/utils/ssh/sshincomingpacket.cpp b/src/libs/utils/ssh/sshincomingpacket.cpp new file mode 100644 index 0000000000..c64ffd4f0e --- /dev/null +++ b/src/libs/utils/ssh/sshincomingpacket.cpp @@ -0,0 +1,462 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshincomingpacket_p.h" + +#include "sshcapabilities_p.h" + +namespace Utils { +namespace Internal { + +const QByteArray SshIncomingPacket::ExitStatusType("exit-status"); +const QByteArray SshIncomingPacket::ExitSignalType("exit-signal"); + +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) +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("%s: current data size = %d, new data size = %d", + Q_FUNC_INFO, m_data.size(), newData.size()); +#endif + + 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(minSize - currentDataSize(), newData.size()); + moveFirstBytes(m_data, newData, bytesToTake); +#ifdef CREATOR_SSH_DEBUG + qDebug("Took %d bytes from new data", bytesToTake); +#endif + if (currentDataSize() < minSize) + return; + } + + const int bytesToTake + = qMin(length() + 4 + macLength() - currentDataSize(), + newData.size()); + moveFirstBytes(m_data, newData, bytesToTake); +#ifdef CREATOR_SSH_DEBUG + qDebug("Took %d bytes from new data", bytesToTake); +#endif + if (isComplete()) { +#ifdef CREATOR_SSH_DEBUG + qDebug("Message complete. Overall size: %u, payload size: %u", + m_data.size(), m_length - paddingLength() - 1); +#endif + 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 (SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet."); + } + return exchangeData; +} + +SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &pubKeyAlgo) const +{ + Q_ASSERT(isComplete()); + Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY); + + try { + SshKeyExchangeReply replyData; + quint32 offset = TypeOffset + 1; + const quint32 k_sLength + = SshPacketParser::asUint32(m_data, &offset); + if (offset + k_sLength > currentDataSize()) + throw SshPacketParseException(); + replyData.k_s = m_data.mid(offset - 4, k_sLength + 4); + if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) + throw SshPacketParseException(); + + // DSS: p and q, RSA: e and n + replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); + replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); + + // g and y + if (pubKeyAlgo == SshCapabilities::PubKeyDss) { + replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); + replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); + } + + replyData.f = SshPacketParser::asBigInt(m_data, &offset); + offset += 4; + if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) + throw SshPacketParseException(); + replyData.signatureBlob = SshPacketParser::asString(m_data, &offset); + return replyData; + } catch (SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Key exchange failed: " + "Server sent invalid SSH_MSG_KEXDH_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 (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 (SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_USERAUTH_BANNER."); + } +} + +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 (SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_DEBUG."); + } +} + +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 (SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_UNIMPLEMENTED."); + } +} + +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 = SshPacketParser::asString(m_data, &offset); + openFailure.language = SshPacketParser::asString(m_data, &offset); + } catch (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 (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 (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 (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 (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); + if (SshPacketParser::asBool(m_data, &offset)) + throw SshPacketParseException(); + exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset); + } catch (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); + 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 (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 (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 (SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Invalid SSH_MSG_CHANNEL_REQUEST packet."); + } +} + +void SshIncomingPacket::calculateLength() const +{ + Q_ASSERT(currentDataSize() >= minPacketSize()); +#ifdef CREATOR_SSH_DEBUG + qDebug("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); +#endif + m_decrypter.decrypt(m_data, 0, cipherBlockSize()); +#ifdef CREATOR_SSH_DEBUG + qDebug("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); + qDebug("message type = %d", m_data.at(TypeOffset)); +#endif + m_length = SshPacketParser::asUint32(m_data, static_cast(0)); +#ifdef CREATOR_SSH_DEBUG + qDebug("decrypted length is %u", m_length); +#endif +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshincomingpacket_p.h b/src/libs/utils/ssh/sshincomingpacket_p.h new file mode 100644 index 0000000000..d9028d7ec2 --- /dev/null +++ b/src/libs/utils/ssh/sshincomingpacket_p.h @@ -0,0 +1,196 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHINCOMINGPACKET_P_H +#define SSHINCOMINGPACKET_P_H + +#include "sshpacket_p.h" + +#include "sshcryptofacility_p.h" +#include "sshpacketparser_p.h" + +#include +#include + +namespace Utils { +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 parameters; // DSS: p, q, g, y. RSA: e, n. + Botan::BigInt f; + QByteArray signatureBlob; +}; + +struct SshDisconnect +{ + quint32 reasonCode; + QString description; + QByteArray language; +}; + +struct SshUserAuthBanner +{ + QString message; + QByteArray language; +}; + +struct SshDebug +{ + bool display; + QString message; + QByteArray language; +}; + +struct SshUnimplemented +{ + quint32 invalidMsgSeqNr; +}; + +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 &pubKeyAlgo) const; + SshDisconnect extractDisconnect() const; + SshUserAuthBanner extractUserAuthBanner() const; + SshDebug extractDebug() const; + SshUnimplemented extractUnimplemented() const; + + 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; + +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 Utils + +#endif // SSHINCOMINGPACKET_P_H diff --git a/src/libs/utils/ssh/sshkeyexchange.cpp b/src/libs/utils/ssh/sshkeyexchange.cpp new file mode 100644 index 0000000000..68c850bdd8 --- /dev/null +++ b/src/libs/utils/ssh/sshkeyexchange.cpp @@ -0,0 +1,201 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshkeyexchange_p.h" + +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "sshsendfacility_p.h" +#include "sshexception_p.h" +#include "sshincomingpacket_p.h" + +#include +#include +#include +#include +#include + +#include + +using namespace Botan; + +namespace Utils { +namespace Internal { + +namespace { + + // For debugging + void printNameList(const char *listName, const SshNameList &list) + { +#ifdef CREATOR_SSH_DEBUG + qDebug("%s:", listName); + foreach (const QByteArray &name, list.names) + qDebug("%s", name.constData()); +#else + Q_UNUSED(listName); + Q_UNUSED(list); +#endif + } +} // anonymous namespace + +SshKeyExchange::SshKeyExchange(SshSendFacility &sendFacility) + : m_sendFacility(sendFacility) +{ +} + +SshKeyExchange::~SshKeyExchange() {} + +void SshKeyExchange::sendKexInitPacket(const QByteArray &serverId) +{ + m_serverId = serverId; + const AbstractSshPacket::Payload &payload + = m_sendFacility.sendKeyExchangeInitPacket(); + m_clientKexInitPayload = QByteArray(payload.data, payload.size); +} + +bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit) +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("server requests key exchange"); +#endif + 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); +#ifdef CREATOR_SSH_DEBUG + qDebug("First packet follows: %d", kexInitParams.firstKexPacketFollows); +#endif + + const QByteArray &keyAlgo + = SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods, + kexInitParams.keyAlgorithms.names); + m_serverHostKeyAlgo + = SshCapabilities::findBestMatch(SshCapabilities::PublicKeyAlgorithms, + kexInitParams.serverHostKeyAlgorithms.names); + m_encryptionAlgo + = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms, + kexInitParams.encryptionAlgorithmsClientToServer.names); + m_decryptionAlgo + = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms, + kexInitParams.encryptionAlgorithmsServerToClient.names); + m_c2sHMacAlgo + = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms, + kexInitParams.macAlgorithmsClientToServer.names); + m_s2cHMacAlgo + = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms, + kexInitParams.macAlgorithmsServerToClient.names); + SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms, + kexInitParams.compressionAlgorithmsClientToServer.names); + SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms, + kexInitParams.compressionAlgorithmsServerToClient.names); + + AutoSeeded_RNG rng; + m_dhKey.reset(new DH_PrivateKey(rng, + DL_Group(botanKeyExchangeAlgoName(keyAlgo)))); + + const AbstractSshPacket::Payload &payload = serverKexInit.payLoad(); + m_serverKexInitPayload = QByteArray(payload.data, payload.size); + m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y()); + return kexInitParams.firstKexPacketFollows; +} + +void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply, + const QByteArray &clientId) +{ + const SshKeyExchangeReply &reply + = dhReply.extractKeyExchangeReply(m_serverHostKeyAlgo); + if (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; + concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y()); + concatenatedData += AbstractSshPacket::encodeMpInt(reply.f); + SymmetricKey k = m_dhKey->derive_key(reply.f); + m_k = AbstractSshPacket::encodeMpInt(BigInt(k.begin(), k.length())); + concatenatedData += m_k; + + m_hash.reset(get_hash(botanSha1Name())); + const SecureVector &hashResult + = m_hash->process(convertByteArray(concatenatedData), + concatenatedData.size()); + m_h = convertByteArray(hashResult); + + QScopedPointer sigKey; + QScopedPointer verifier; + if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) { + const DL_Group group(reply.parameters.at(0), reply.parameters.at(1), + reply.parameters.at(2)); + DSA_PublicKey * const dsaKey + = new DSA_PublicKey(group, reply.parameters.at(3)); + sigKey.reset(dsaKey); + verifier.reset(get_pk_verifier(*dsaKey, + botanEmsaAlgoName(SshCapabilities::PubKeyDss))); + } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) { + RSA_PublicKey * const rsaKey + = new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0)); + sigKey.reset(rsaKey); + verifier.reset(get_pk_verifier(*rsaKey, + botanEmsaAlgoName(SshCapabilities::PubKeyRsa))); + } else { + Q_ASSERT(!"Impossible: Neither DSS nor RSA!"); + } + const byte * const botanH = convertByteArray(m_h); + const Botan::byte * const botanSig + = convertByteArray(reply.signatureBlob); + if (!verifier->verify_message(botanH, m_h.size(), botanSig, + reply.signatureBlob.size())) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + "Invalid signature in SSH_MSG_KEXDH_REPLY packet."); + } + + m_sendFacility.sendNewKeysPacket(); +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshkeyexchange_p.h b/src/libs/utils/ssh/sshkeyexchange_p.h new file mode 100644 index 0000000000..6a685eb0af --- /dev/null +++ b/src/libs/utils/ssh/sshkeyexchange_p.h @@ -0,0 +1,91 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHKEYEXCHANGE_P_H +#define SSHKEYEXCHANGE_P_H + +#include + +#include +#include + +namespace Botan { class HashFunction; } + +namespace Utils { +namespace Internal { + +class SshSendFacility; +class SshIncomingPacket; + +class SshKeyExchange +{ +public: + SshKeyExchange(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.data(); } + 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 m_serverId; + QByteArray m_clientKexInitPayload; + QByteArray m_serverKexInitPayload; + QScopedPointer m_dhKey; + QByteArray m_k; + QByteArray m_h; + QByteArray m_serverHostKeyAlgo; + QByteArray m_encryptionAlgo; + QByteArray m_decryptionAlgo; + QByteArray m_c2sHMacAlgo; + QByteArray m_s2cHMacAlgo; + QScopedPointer m_hash; + SshSendFacility &m_sendFacility; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHKEYEXCHANGE_P_H diff --git a/src/libs/utils/ssh/sshkeygenerator.cpp b/src/libs/utils/ssh/sshkeygenerator.cpp new file mode 100644 index 0000000000..689b6d48b1 --- /dev/null +++ b/src/libs/utils/ssh/sshkeygenerator.cpp @@ -0,0 +1,150 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshkeygenerator.h" + +#include "sshbotanconversions_p.h" +#include "sshcapabilities_p.h" +#include "sshpacket_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Utils { + +using namespace Botan; +using namespace Internal; + +SshKeyGenerator::SshKeyGenerator() + : m_type(Rsa) + , m_format(OpenSsl) +{ +} + +bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, + int keySize) +{ + m_type = type; + m_format = format; + + try { + AutoSeeded_RNG rng; + KeyPtr key; + if (m_type == Rsa) + key = KeyPtr(new RSA_PrivateKey(rng, keySize)); + else + key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, + keySize))); + return m_format == Pkcs8 + ? generatePkcs8Keys(key) : generateOpenSslKeys(key); + } catch (Botan::Exception &e) { + m_error = tr("Error generating key: %1").arg(e.what()); + return false; + } +} + +bool SshKeyGenerator::generatePkcs8Keys(const KeyPtr &key) +{ + generatePkcs8Key(key, false); + generatePkcs8Key(key, true); + return true; +} + +void SshKeyGenerator::generatePkcs8Key(const KeyPtr &key, bool privateKey) +{ + Pipe pipe; + pipe.start_msg(); + QByteArray *keyData; + if (privateKey) { + PKCS8::encode(*key, pipe); + keyData = &m_privateKey; + } else { + X509::encode(*key, pipe); + keyData = &m_publicKey; + } + pipe.end_msg(); + keyData->resize(pipe.remaining(pipe.message_count() - 1)); + pipe.read(convertByteArray(*keyData), keyData->size(), + pipe.message_count() - 1); +} + +bool SshKeyGenerator::generateOpenSslKeys(const KeyPtr &key) +{ + QList publicParams; + QList allParams; + QByteArray keyId; + if (m_type == Rsa) { + const QSharedPointer rsaKey + = key.dynamicCast(); + publicParams << rsaKey->get_e() << rsaKey->get_n(); + allParams << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() + << rsaKey->get_p() << rsaKey->get_q(); + keyId = SshCapabilities::PubKeyRsa; + } else { + const QSharedPointer dsaKey + = key.dynamicCast(); + publicParams << dsaKey->group_p() << dsaKey->group_q() + << dsaKey->group_g() << dsaKey->get_y(); + allParams << publicParams << dsaKey->get_x(); + keyId = SshCapabilities::PubKeyDss; + } + + QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId); + foreach (const BigInt &b, publicParams) + publicKeyBlob += AbstractSshPacket::encodeMpInt(b); + publicKeyBlob = publicKeyBlob.toBase64(); + const QByteArray id = "QtCreator/" + + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8(); + m_publicKey = keyId + ' ' + publicKeyBlob + ' ' + id; + + DER_Encoder encoder; + encoder.start_cons(SEQUENCE).encode (0U); + foreach (const BigInt &b, allParams) + encoder.encode(b); + encoder.end_cons(); + const char * const label + = m_type == Rsa ? "RSA PRIVATE KEY" : "DSA PRIVATE KEY"; + m_privateKey + = QByteArray(PEM_Code::encode (encoder.get_contents(), label).c_str()); + return true; +} + +} // namespace Utils diff --git a/src/libs/utils/ssh/sshkeygenerator.h b/src/libs/utils/ssh/sshkeygenerator.h new file mode 100644 index 0000000000..fa31f3e37d --- /dev/null +++ b/src/libs/utils/ssh/sshkeygenerator.h @@ -0,0 +1,79 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHKEYGENERATOR_H +#define SSHKEYGENERATOR_H + +#include + +#include +#include + +namespace Botan { + class Private_Key; +} + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT SshKeyGenerator +{ + Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator) +public: + enum KeyType { Rsa, Dsa }; + enum PrivateKeyFormat { Pkcs8, OpenSsl }; + + SshKeyGenerator(); + bool generateKeys(KeyType type, PrivateKeyFormat format, int keySize); + QString error() const { return m_error; } + QByteArray privateKey() const { return m_privateKey; } + QByteArray publicKey() const { return m_publicKey; } + KeyType type() const { return m_type; } + PrivateKeyFormat format() const { return m_format; } + +private: + typedef QSharedPointer KeyPtr; + + bool generatePkcs8Keys(const KeyPtr &key); + void generatePkcs8Key(const KeyPtr &key, bool privateKey); + bool generateOpenSslKeys(const KeyPtr &key); + + QString m_error; + QByteArray m_publicKey; + QByteArray m_privateKey; + KeyType m_type; + PrivateKeyFormat m_format; +}; + +} // namespace Utils + +#endif // SSHKEYGENERATOR_H diff --git a/src/libs/utils/ssh/sshoutgoingpacket.cpp b/src/libs/utils/ssh/sshoutgoingpacket.cpp new file mode 100644 index 0000000000..445aa75ae2 --- /dev/null +++ b/src/libs/utils/ssh/sshoutgoingpacket.cpp @@ -0,0 +1,298 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshoutgoingpacket_p.h" + +#include "sshcapabilities_p.h" +#include "sshcryptofacility_p.h" + +#include + +namespace Utils { +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(); +} + +void 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()); + + 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. + finalize(); +} + +void SshOutgoingPacket::generateKeyDhInitPacket(const Botan::BigInt &e) +{ + init(SSH_MSG_KEXDH_INIT).appendMpInt(e).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::generateUserAuthByPwdRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd) +{ + init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service) + .appendString("password").appendBool(false).appendString(pwd) + .finalize(); +} + +void SshOutgoingPacket::generateUserAuthByKeyRequestPacket(const QByteArray &user, + const QByteArray &service) +{ + init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service) + .appendString("publickey").appendBool(true) + .appendString(m_encrypter.authenticationAlgorithmName()) + .appendString(m_encrypter.authenticationPublicKey()); + const QByteArray &dataToSign = m_data.mid(PayloadOffset); + appendString(m_encrypter.authenticationKeySignature(dataToSign)); + 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::generateEnvPacket(quint32 remoteChannel, + const QByteArray &var, const QByteArray &value) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("env") + .appendBool(false).appendString(var).appendString(value); +} + +void SshOutgoingPacket::generateExecPacket(quint32 remoteChannel, + const QByteArray &command) +{ + init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("exec") + .appendBool(true).appendString(command).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::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(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; +#ifdef CREATOR_SSH_DEBUG + qDebug("Encrypting packet of type %u", m_data.at(TypeOffset)); +#endif + encrypt(); + Q_ASSERT(isComplete()); +} + +int SshOutgoingPacket::sizeDivisor() const +{ + return qMax(cipherBlockSize(), 8U); +} + +QByteArray SshOutgoingPacket::encodeNameList(const QList &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 Utils diff --git a/src/libs/utils/ssh/sshoutgoingpacket_p.h b/src/libs/utils/ssh/sshoutgoingpacket_p.h new file mode 100644 index 0000000000..22adf6d2e7 --- /dev/null +++ b/src/libs/utils/ssh/sshoutgoingpacket_p.h @@ -0,0 +1,104 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHOUTGOINGPACKET_P_H +#define SSHOUTGOINGPACKET_P_H + +#include "sshpacket_p.h" + +namespace Utils { +namespace Internal { + +class SshEncryptionFacility; + +class SshOutgoingPacket : public AbstractSshPacket +{ +public: + SshOutgoingPacket(const SshEncryptionFacility &encrypter, + const quint32 &seqNr); + + void generateKeyExchangeInitPacket(); + void generateKeyDhInitPacket(const Botan::BigInt &e); + void generateNewKeysPacket(); + void generateDisconnectPacket(SshErrorCode reason, + const QByteArray &reasonString); + void generateMsgUnimplementedPacket(quint32 serverSeqNr); + void generateUserAuthServiceRequestPacket(); + void generateUserAuthByPwdRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd); + void generateUserAuthByKeyRequestPacket(const QByteArray &user, + const QByteArray &service); + void generateRequestFailurePacket(); + void generateIgnorePacket(); + void generateInvalidMessagePacket(); + void generateSessionPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize); + void generateEnvPacket(quint32 remoteChannel, const QByteArray &var, + const QByteArray &value); + void generateExecPacket(quint32 remoteChannel, const QByteArray &command); + 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); + +private: + virtual quint32 cipherBlockSize() const; + virtual quint32 macLength() const; + + static QByteArray encodeNameList(const QList &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 Utils + +#endif // SSHOUTGOINGPACKET_P_H diff --git a/src/libs/utils/ssh/sshpacket.cpp b/src/libs/utils/ssh/sshpacket.cpp new file mode 100644 index 0000000000..0ec644786e --- /dev/null +++ b/src/libs/utils/ssh/sshpacket.cpp @@ -0,0 +1,171 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshpacket_p.h" + +#include "sshcapabilities_p.h" +#include "sshcryptofacility_p.h" +#include "sshexception_p.h" +#include "sshpacketparser_p.h" + +#include + +#include + +namespace Utils { +namespace Internal { + +const quint32 AbstractSshPacket::PaddingLengthOffset = 4; +const quint32 AbstractSshPacket::PayloadOffset = PaddingLengthOffset + 1; +const quint32 AbstractSshPacket::TypeOffset = PayloadOffset; +const quint32 AbstractSshPacket::MinPaddingLength = 4; + +namespace { + + void printByteArray(const QByteArray &data) + { +#ifdef CREATOR_SSH_DEBUG + for (int i = 0; i < data.count(); ++i) + qDebug() << std::hex << (static_cast(data[i]) & 0xff) << " "; +#else + Q_UNUSED(data); +#endif + } +} // anonymous namespace + + +AbstractSshPacket::AbstractSshPacket() : m_length(0) { } +AbstractSshPacket::~AbstractSshPacket() {} + +bool AbstractSshPacket::isComplete() const +{ + if (currentDataSize() < minPacketSize()) + return false; + Q_ASSERT(4 + length() + macLength() >= currentDataSize()); + return 4 + length() + macLength() == currentDataSize(); +} + +void AbstractSshPacket::clear() +{ + m_data.clear(); + m_length = 0; +} + +SshPacketType AbstractSshPacket::type() const +{ + Q_ASSERT(isComplete()); + return static_cast(m_data.at(TypeOffset)); +} + +AbstractSshPacket::Payload AbstractSshPacket::payLoad() const +{ + Payload p; + p.data = m_data.constData() + PayloadOffset; + p.size = length() - paddingLength() - 1; + return p; +} + +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 = 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(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(0)); +} + +QByteArray AbstractSshPacket::generateMac(const SshAbstractCryptoFacility &crypt, + quint32 seqNr) const +{ + const quint32 seqNrBe = qToBigEndian(seqNr); + QByteArray data(reinterpret_cast(&seqNrBe), sizeof seqNrBe); + data += QByteArray(m_data.constData(), length() + 4); + return crypt.generateMac(data, data.size()); +} + +quint32 AbstractSshPacket::minPacketSize() const +{ + return qMax(cipherBlockSize(), 16) + macLength(); +} + +void AbstractSshPacket::setLengthField(QByteArray &data) +{ + const quint32 length = qToBigEndian(data.size() - 4); + data.replace(0, 4, reinterpret_cast(&length), 4); +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshpacket_p.h b/src/libs/utils/ssh/sshpacket_p.h new file mode 100644 index 0000000000..e2641ea5e4 --- /dev/null +++ b/src/libs/utils/ssh/sshpacket_p.h @@ -0,0 +1,146 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHPACKET_P_H +#define SSHPACKET_P_H + +#include "sshexception_p.h" + +#include +#include +#include + +#include + +namespace Utils { +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_KEXDH_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_GLOBAL_REQUEST = 80, + SSH_MSG_REQUEST_SUCCESS = 81, + SSH_MSG_REQUEST_FAILURE = 82, + + 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 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 static QByteArray encodeInt(T value) + { + const T valMsb = qToBigEndian(value); + return QByteArray(reinterpret_cast(&valMsb), sizeof valMsb); + } + + static void setLengthField(QByteArray &data); + + void printRawBytes() const; // For Debugging. + + const QByteArray &rawData() const { return m_data; } + + struct Payload { const char *data; quint32 size; }; + Payload 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 Utils + +#endif // SSHPACKET_P_H diff --git a/src/libs/utils/ssh/sshpacketparser.cpp b/src/libs/utils/ssh/sshpacketparser.cpp new file mode 100644 index 0000000000..f83c395de3 --- /dev/null +++ b/src/libs/utils/ssh/sshpacketparser.cpp @@ -0,0 +1,157 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshpacketparser_p.h" + +#include + +namespace Utils { +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(data.at(offset) & 0xff) << 56) + + (static_cast(data.at(offset + 1) & 0xff) << 48) + + (static_cast(data.at(offset + 2) & 0xff) << 40) + + (static_cast(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) +{ + 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(data.constData() + *offset); + *offset += length; + return Botan::BigInt::decode(numberStart, length); +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshpacketparser_p.h b/src/libs/utils/ssh/sshpacketparser_p.h new file mode 100644 index 0000000000..0c87ac77c8 --- /dev/null +++ b/src/libs/utils/ssh/sshpacketparser_p.h @@ -0,0 +1,85 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHPACKETPARSER_P_H +#define SSHPACKETPARSER_P_H + +#include + +#include +#include +#include + +namespace Utils { +namespace Internal { + +struct SshNameList +{ + SshNameList() : originalLength(0) {} + SshNameList(quint32 originalLength) : originalLength(originalLength) {} + quint32 originalLength; + QList 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 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 Utils + +#endif // SSHPACKETPARSER_P_H diff --git a/src/libs/utils/ssh/sshremoteprocess.cpp b/src/libs/utils/ssh/sshremoteprocess.cpp new file mode 100644 index 0000000000..b6d71167a3 --- /dev/null +++ b/src/libs/utils/ssh/sshremoteprocess.cpp @@ -0,0 +1,237 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshremoteprocess.h" +#include "sshremoteprocess_p.h" + +#include "sshincomingpacket_p.h" +#include "sshsendfacility_p.h" + +#include + +#include + +namespace Utils { + +const QByteArray SshRemoteProcess::AbrtSignal("ABRT"); +const QByteArray SshRemoteProcess::AlrmSignal("ALRM"); +const QByteArray SshRemoteProcess::FpeSignal("FPE"); +const QByteArray SshRemoteProcess::HupSignal("HUP"); +const QByteArray SshRemoteProcess::IllSignal("ILL"); +const QByteArray SshRemoteProcess::IntSignal("INT"); +const QByteArray SshRemoteProcess::KillSignal("KILL"); +const QByteArray SshRemoteProcess::PipeSignal("PIPE"); +const QByteArray SshRemoteProcess::QuitSignal("QUIT"); +const QByteArray SshRemoteProcess::SegvSignal("SEGV"); +const QByteArray SshRemoteProcess::TermSignal("TERM"); +const QByteArray SshRemoteProcess::Usr1Signal("USR1"); +const QByteArray SshRemoteProcess::Usr2Signal("USR2"); + +SshRemoteProcess::SshRemoteProcess(const QByteArray &command, quint32 channelId, + Internal::SshSendFacility &sendFacility) + : d(new Internal::SshRemoteProcessPrivate(command, channelId, sendFacility, this)) +{ + connect(d, SIGNAL(started()), this, SIGNAL(started()), + Qt::QueuedConnection); + connect(d, SIGNAL(outputAvailable(QByteArray)), this, + SIGNAL(outputAvailable(QByteArray)), Qt::QueuedConnection); + connect(d, SIGNAL(errorOutputAvailable(QByteArray)), this, + SIGNAL(errorOutputAvailable(QByteArray)), Qt::QueuedConnection); + connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)), + Qt::QueuedConnection); +} + +SshRemoteProcess::~SshRemoteProcess() +{ + Q_ASSERT(d->channelState() == Internal::SshRemoteProcessPrivate::Inactive + || d->channelState() == Internal::SshRemoteProcessPrivate::CloseRequested + || d->channelState() == Internal::SshRemoteProcessPrivate::Closed); + delete d; +} + +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::start() +{ + if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive) { +#ifdef CREATOR_SSH_DEBUG + qDebug("process start requested, channel id = %u", d->localChannelId()); +#endif + d->requestSessionStart(); + } +} + +void SshRemoteProcess::sendSignal(const QByteArray &signal) +{ + try { + if (isRunning()) + d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(), + signal); + } catch (Botan::Exception &e) { + d->setError(QString::fromAscii(e.what())); + d->closeChannel(); + } +} + +void SshRemoteProcess::closeChannel() +{ + d->closeChannel(); +} + +void SshRemoteProcess::sendInput(const QByteArray &data) +{ + if (isRunning()) + d->sendData(data); +} + +bool SshRemoteProcess::isRunning() const +{ + return d->m_procState == Internal::SshRemoteProcessPrivate::Running; +} + +QString SshRemoteProcess::errorString() const { return d->errorString(); } + +int SshRemoteProcess::exitCode() const { return d->m_exitCode; } + +QByteArray SshRemoteProcess::exitSignal() const { return d->m_signal; } + +namespace Internal { + +SshRemoteProcessPrivate::SshRemoteProcessPrivate(const QByteArray &command, + quint32 channelId, SshSendFacility &sendFacility, SshRemoteProcess *proc) + : AbstractSshChannel(channelId, sendFacility), m_procState(NotYetStarted), + m_wasRunning(false), m_exitCode(0), m_command(command), m_proc(proc) +{ +} + +void SshRemoteProcessPrivate::setProcState(ProcessState newState) +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("channel: old state = %d,new state = %d", m_procState, newState); +#endif + m_procState = newState; + if (newState == StartFailed) { + emit closed(SshRemoteProcess::FailedToStart); + } else if (newState == Running) { + m_wasRunning = true; + emit started(); + } +} + +void SshRemoteProcessPrivate::closeHook() +{ + if (m_wasRunning) { + if (!m_signal.isEmpty()) + emit closed(SshRemoteProcess::KilledBySignal); + else + emit closed(SshRemoteProcess::ExitedNormally); + } +} + +void SshRemoteProcessPrivate::handleOpenSuccessInternal() +{ + foreach (const EnvVar &envVar, m_env) { + m_sendFacility.sendEnvPacket(remoteChannel(), envVar.first, + envVar.second); + } + + m_sendFacility.sendExecPacket(remoteChannel(), m_command); + setProcState(ExecRequested); + m_timeoutTimer->start(ReplyTimeout); +} + +void SshRemoteProcessPrivate::handleOpenFailureInternal() +{ + setProcState(StartFailed); +} + +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) +{ + emit outputAvailable(data); +} + +void SshRemoteProcessPrivate::handleChannelExtendedDataInternal(quint32 type, + const QByteArray &data) +{ + if (type != SSH_EXTENDED_DATA_STDERR) + qWarning("Unknown extended data type %u", type); + else + emit errorOutputAvailable(data); +} + +void SshRemoteProcessPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("Process exiting with exit code %d", exitStatus.exitStatus); +#endif + m_exitCode = exitStatus.exitStatus; + m_procState = Exited; +} + +void SshRemoteProcessPrivate::handleExitSignal(const SshChannelExitSignal &signal) +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("Exit due to signal %s", signal.signal.data()); +#endif + setError(signal.error); + m_signal = signal.signal; + m_procState = Exited; +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshremoteprocess.h b/src/libs/utils/ssh/sshremoteprocess.h new file mode 100644 index 0000000000..d0b996cc54 --- /dev/null +++ b/src/libs/utils/ssh/sshremoteprocess.h @@ -0,0 +1,134 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHREMOTECOMMAND_H +#define SSHREMOTECOMMAND_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +QT_END_NAMESPACE + +namespace Utils { +namespace Internal { +class SshChannelManager; +class SshRemoteProcessPrivate; +class SshSendFacility; +} // namespace Internal + + +/* + * This class implements an SSH channel for running a remote process. + * Objects are created via SshConnection::createRemoteProcess. + * The process is started via the start() member function. + * A closeChannel() function is provided, but rarely useful, because + * a) when the process ends, the channel is closed automatically, and + * b) closing a channel will not necessarily kill the remote process. + * Therefore, the only sensible use case for calling closeChannel() is to + * get rid of an SshRemoteProces object before the process is actually started. + * Note that the process does not have a terminal, so you can't use it + * for applications that require one. + */ +class QTCREATOR_UTILS_EXPORT SshRemoteProcess : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(SshRemoteProcess) + + friend class Internal::SshChannelManager; + friend class Internal::SshRemoteProcessPrivate; + +public: + typedef QSharedPointer Ptr; + enum ExitStatus { FailedToStart, KilledBySignal, ExitedNormally }; + + static const QByteArray AbrtSignal; + static const QByteArray AlrmSignal; + static const QByteArray FpeSignal; + static const QByteArray HupSignal; + static const QByteArray IllSignal; + static const QByteArray IntSignal; + static const QByteArray KillSignal; + static const QByteArray PipeSignal; + static const QByteArray QuitSignal; + static const QByteArray SegvSignal; + static const QByteArray TermSignal; + static const QByteArray Usr1Signal; + static const QByteArray Usr2Signal; + + ~SshRemoteProcess(); + + /* + * 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 start(); + void closeChannel(); + + bool isRunning() const; + QString errorString() const; + int exitCode() const; + QByteArray exitSignal() const; + + // Note: This is ignored by the OpenSSH server. + void sendSignal(const QByteArray &signal); + void kill() { sendSignal(KillSignal); } + + void sendInput(const QByteArray &data); // Should usually have a trailing newline. + +signals: + void started(); + void outputAvailable(const QByteArray &output); + void errorOutputAvailable(const QByteArray &output); + + /* + * Parameter is of type ExitStatus, but we use int because of + * signal/slot awkwardness (full namespace required). + */ + void closed(int exitStatus); + +private: + SshRemoteProcess(const QByteArray &command, quint32 channelId, + Internal::SshSendFacility &sendFacility); + + Internal::SshRemoteProcessPrivate *d; +}; + +} // namespace Utils + +#endif // SSHREMOTECOMMAND_H diff --git a/src/libs/utils/ssh/sshremoteprocess_p.h b/src/libs/utils/ssh/sshremoteprocess_p.h new file mode 100644 index 0000000000..d667bde2f0 --- /dev/null +++ b/src/libs/utils/ssh/sshremoteprocess_p.h @@ -0,0 +1,98 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHREMOTEPROCESS_P_H +#define SSHREMOTEPROCESS_P_H + +#include "sshchannel_p.h" + +#include +#include + +namespace Utils { +class SshRemoteProcess; + +namespace Internal { +class SshSendFacility; + +class SshRemoteProcessPrivate : public AbstractSshChannel +{ + Q_OBJECT + friend class Utils::SshRemoteProcess; +public: + enum ProcessState { + NotYetStarted, ExecRequested, StartFailed,Running, Exited + }; + + virtual void handleChannelSuccess(); + virtual void handleChannelFailure(); + + virtual void closeHook(); + +signals: + void started(); + void outputAvailable(const QByteArray &output); + void errorOutputAvailable(const QByteArray &output); + void closed(int exitStatus); + +private: + SshRemoteProcessPrivate(const QByteArray &command, quint32 channelId, + SshSendFacility &sendFacility, SshRemoteProcess *proc); + + virtual void handleOpenSuccessInternal(); + virtual void handleOpenFailureInternal(); + 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); + + void setProcState(ProcessState newState); + + ProcessState m_procState; + bool m_wasRunning; + QByteArray m_signal; + int m_exitCode; + + const QByteArray m_command; + + typedef QPair EnvVar; + QList m_env; + + SshRemoteProcess *m_proc; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHREMOTEPROCESS_P_H diff --git a/src/libs/utils/ssh/sshremoteprocessrunner.cpp b/src/libs/utils/ssh/sshremoteprocessrunner.cpp new file mode 100644 index 0000000000..fcff1692f0 --- /dev/null +++ b/src/libs/utils/ssh/sshremoteprocessrunner.cpp @@ -0,0 +1,210 @@ +#include "sshremoteprocessrunner.h" + +#define ASSERT_STATE(states) assertState(states, Q_FUNC_INFO) + +namespace Utils { + +class SshRemoteProcessRunnerPrivate : public QObject +{ + Q_OBJECT +public: + SshRemoteProcessRunnerPrivate(const SshConnectionParameters ¶ms, + QObject *parent); + SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection, + QObject *parent); + void run(const QByteArray &command); + QByteArray command() const { return m_command; } + + const SshConnection::Ptr m_connection; + SshRemoteProcess::Ptr m_process; + +signals: + void connectionError(Utils::SshError); + void processStarted(); + void processOutputAvailable(const QByteArray &output); + void processErrorOutputAvailable(const QByteArray &output); + void processClosed(int exitStatus); + +private slots: + void handleConnected(); + void handleConnectionError(Utils::SshError error); + void handleDisconnected(); + void handleProcessStarted(); + void handleProcessFinished(int exitStatus); + +private: + enum State { Inactive, Connecting, Connected, ProcessRunning }; + + void setState(State state); + void assertState(const QList &allowedStates, const char *func); + void assertState(State allowedState, const char *func); + + State m_state; + QByteArray m_command; + const SshConnectionParameters m_params; +}; + + +SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnectionParameters ¶ms, + QObject *parent) + : QObject(parent), + m_connection(SshConnection::create()), + m_state(Inactive), + m_params(params) +{ +} + +SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection, + QObject *parent) + : QObject(parent), + m_connection(connection), + m_state(Inactive), + m_params(connection->connectionParameters()) +{ +} + +void SshRemoteProcessRunnerPrivate::run(const QByteArray &command) +{ + ASSERT_STATE(Inactive); + setState(Connecting); + + m_command = command; + connect(m_connection.data(), SIGNAL(error(Utils::SshError)), + SLOT(handleConnectionError(Utils::SshError))); + connect(m_connection.data(), SIGNAL(disconnected()), + SLOT(handleDisconnected())); + if (m_connection->state() == SshConnection::Connected) { + handleConnected(); + } else { + connect(m_connection.data(), SIGNAL(connected()), + SLOT(handleConnected())); + m_connection->connectToHost(m_params); + } +} + +void SshRemoteProcessRunnerPrivate::handleConnected() +{ + ASSERT_STATE(Connecting); + setState(Connected); + + m_process = m_connection->createRemoteProcess(m_command); + connect(m_process.data(), SIGNAL(started()), SLOT(handleProcessStarted())); + connect(m_process.data(), SIGNAL(closed(int)), + SLOT(handleProcessFinished(int))); + connect(m_process.data(), SIGNAL(outputAvailable(QByteArray)), + SIGNAL(processOutputAvailable(QByteArray))); + connect(m_process.data(), SIGNAL(errorOutputAvailable(QByteArray)), + SIGNAL(processErrorOutputAvailable(QByteArray))); + m_process->start(); +} + +void SshRemoteProcessRunnerPrivate::handleConnectionError(Utils::SshError error) +{ + handleDisconnected(); + emit connectionError(error); +} + +void SshRemoteProcessRunnerPrivate::handleDisconnected() +{ + ASSERT_STATE(QList() << Connecting << Connected << ProcessRunning); + setState(Inactive); +} + +void SshRemoteProcessRunnerPrivate::handleProcessStarted() +{ + ASSERT_STATE(Connected); + setState(ProcessRunning); + + emit processStarted(); +} + +void SshRemoteProcessRunnerPrivate::handleProcessFinished(int exitStatus) +{ + switch (exitStatus) { + case SshRemoteProcess::FailedToStart: + ASSERT_STATE(Connected); + break; + case SshRemoteProcess::KilledBySignal: + case SshRemoteProcess::ExitedNormally: + ASSERT_STATE(ProcessRunning); + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible exit status."); + } + setState(Inactive); + emit processClosed(exitStatus); +} + +void SshRemoteProcessRunnerPrivate::setState(State state) +{ + if (m_state != state) { + m_state = state; + if (m_state == Inactive) { + if (m_process) + disconnect(m_process.data(), 0, this, 0); + disconnect(m_connection.data(), 0, this, 0); + } + } +} + +void SshRemoteProcessRunnerPrivate::assertState(const QList &allowedStates, + const char *func) +{ + if (!allowedStates.contains(m_state)) + qWarning("Unexpected state %d in function %s", m_state, func); +} + +void SshRemoteProcessRunnerPrivate::assertState(State allowedState, + const char *func) +{ + assertState(QList() << allowedState, func); +} + + +SshRemoteProcessRunner::Ptr SshRemoteProcessRunner::create(const SshConnectionParameters ¶ms) +{ + return SshRemoteProcessRunner::Ptr(new SshRemoteProcessRunner(params)); +} + +SshRemoteProcessRunner::Ptr SshRemoteProcessRunner::create(const SshConnection::Ptr &connection) +{ + return SshRemoteProcessRunner::Ptr(new SshRemoteProcessRunner(connection)); +} + +SshRemoteProcessRunner::SshRemoteProcessRunner(const SshConnectionParameters ¶ms) + : d(new SshRemoteProcessRunnerPrivate(params, this)) +{ + init(); +} + +SshRemoteProcessRunner::SshRemoteProcessRunner(const SshConnection::Ptr &connection) + : d(new SshRemoteProcessRunnerPrivate(connection, this)) +{ + init(); +} + +void SshRemoteProcessRunner::init() +{ + connect(d, SIGNAL(connectionError(Utils::SshError)), + SIGNAL(connectionError(Utils::SshError))); + connect(d, SIGNAL(processStarted()), SIGNAL(processStarted())); + connect(d, SIGNAL(processClosed(int)), SIGNAL(processClosed(int))); + connect(d, SIGNAL(processOutputAvailable(QByteArray)), + SIGNAL(processOutputAvailable(QByteArray))); + connect(d, SIGNAL(processErrorOutputAvailable(QByteArray)), + SIGNAL(processErrorOutputAvailable(QByteArray))); +} + +void SshRemoteProcessRunner::run(const QByteArray &command) +{ + d->run(command); +} + +QByteArray SshRemoteProcessRunner::command() const { return d->command(); } +SshConnection::Ptr SshRemoteProcessRunner::connection() const { return d->m_connection; } +SshRemoteProcess::Ptr SshRemoteProcessRunner::process() const { return d->m_process; } + +} // namespace Utils + + +#include "sshremoteprocessrunner.moc" diff --git a/src/libs/utils/ssh/sshremoteprocessrunner.h b/src/libs/utils/ssh/sshremoteprocessrunner.h new file mode 100644 index 0000000000..a8eff8b513 --- /dev/null +++ b/src/libs/utils/ssh/sshremoteprocessrunner.h @@ -0,0 +1,44 @@ +#ifndef SSHREMOTEPROCESSRUNNER_H +#define SSHREMOTEPROCESSRUNNER_H + +#include "sshconnection.h" +#include "sshremoteprocess.h" + +namespace Utils { +class SshRemoteProcessRunnerPrivate; + +// Convenience class for running a remote process over an SSH connection. +class QTCREATOR_UTILS_EXPORT SshRemoteProcessRunner : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(SshRemoteProcessRunner) +public: + typedef QSharedPointer Ptr; + + static Ptr create(const SshConnectionParameters ¶ms); + static Ptr create(const SshConnection::Ptr &connection); + + void run(const QByteArray &command); + QByteArray command() const; + + SshConnection::Ptr connection() const; + SshRemoteProcess::Ptr process() const; + +signals: + void connectionError(Utils::SshError); + void processStarted(); + void processOutputAvailable(const QByteArray &output); + void processErrorOutputAvailable(const QByteArray &output); + void processClosed(int exitStatus); // values are of type SshRemoteProcess::ExitStatus + +private: + SshRemoteProcessRunner(const SshConnectionParameters ¶ms); + SshRemoteProcessRunner(const SshConnection::Ptr &connection); + void init(); + + SshRemoteProcessRunnerPrivate *d; +}; + +} // namespace Utils + +#endif // SSHREMOTEPROCESSRUNNER_H diff --git a/src/libs/utils/ssh/sshsendfacility.cpp b/src/libs/utils/ssh/sshsendfacility.cpp new file mode 100644 index 0000000000..95116aaf6f --- /dev/null +++ b/src/libs/utils/ssh/sshsendfacility.cpp @@ -0,0 +1,210 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "sshsendfacility_p.h" + +#include "sshkeyexchange_p.h" +#include "sshoutgoingpacket_p.h" + +#include + +namespace Utils { +namespace Internal { + +SshSendFacility::SshSendFacility(QTcpSocket *socket) + : m_clientSeqNr(0), m_socket(socket), + m_outgoingPacket(m_encrypter, m_clientSeqNr) +{ +} + +void SshSendFacility::sendPacket() +{ +#ifdef CREATOR_SSH_DEBUG + qDebug("Sending packet, client seq nr is %u", m_clientSeqNr); +#endif + 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); +} + +SshOutgoingPacket::Payload SshSendFacility::sendKeyExchangeInitPacket() +{ + m_outgoingPacket.generateKeyExchangeInitPacket(); + sendPacket(); + return m_outgoingPacket.payLoad(); +} + +void SshSendFacility::sendKeyDhInitPacket(const Botan::BigInt &e) +{ + m_outgoingPacket.generateKeyDhInitPacket(e); + 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::sendUserAuthByPwdRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd) +{ + m_outgoingPacket.generateUserAuthByPwdRequestPacket(user, service, pwd); + sendPacket(); + } + +void SshSendFacility::sendUserAuthByKeyRequestPacket(const QByteArray &user, + const QByteArray &service) +{ + m_outgoingPacket.generateUserAuthByKeyRequestPacket(user, service); + 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::sendEnvPacket(quint32 remoteChannel, + const QByteArray &var, const QByteArray &value) +{ + m_outgoingPacket.generateEnvPacket(remoteChannel, var, value); + sendPacket(); +} + +void SshSendFacility::sendExecPacket(quint32 remoteChannel, + const QByteArray &command) +{ + m_outgoingPacket.generateExecPacket(remoteChannel, command); + 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(); +} + +} // namespace Internal +} // namespace Utils diff --git a/src/libs/utils/ssh/sshsendfacility_p.h b/src/libs/utils/ssh/sshsendfacility_p.h new file mode 100644 index 0000000000..9cd7cd6ad1 --- /dev/null +++ b/src/libs/utils/ssh/sshsendfacility_p.h @@ -0,0 +1,97 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SSHCONNECTIONOUTSTATE_P_H +#define SSHCONNECTIONOUTSTATE_P_H + +#include "sshcryptofacility_p.h" +#include "sshoutgoingpacket_p.h" + +QT_BEGIN_NAMESPACE +class QTcpSocket; +QT_END_NAMESPACE + + +namespace Utils { +namespace Internal { +class SshKeyExchange; + +class SshSendFacility +{ +public: + SshSendFacility(QTcpSocket *socket); + void reset(); + void recreateKeys(const SshKeyExchange &keyExchange); + void createAuthenticationKey(const QByteArray &privKeyFileContents); + + SshOutgoingPacket::Payload sendKeyExchangeInitPacket(); + void sendKeyDhInitPacket(const Botan::BigInt &e); + void sendNewKeysPacket(); + void sendDisconnectPacket(SshErrorCode reason, + const QByteArray &reasonString); + void sendMsgUnimplementedPacket(quint32 serverSeqNr); + void sendUserAuthServiceRequestPacket(); + void sendUserAuthByPwdRequestPacket(const QByteArray &user, + const QByteArray &service, const QByteArray &pwd); + void sendUserAuthByKeyRequestPacket(const QByteArray &user, + const QByteArray &service); + void sendRequestFailurePacket(); + void sendIgnorePacket(); + void sendInvalidPacket(); + void sendSessionPacket(quint32 channelId, quint32 windowSize, + quint32 maxPacketSize); + void sendEnvPacket(quint32 remoteChannel, const QByteArray &var, + const QByteArray &value); + void sendExecPacket(quint32 remoteChannel, const QByteArray &command); + 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); + quint32 nextClientSeqNr() const { return m_clientSeqNr; } + +private: + void sendPacket(); + + quint32 m_clientSeqNr; + SshEncryptionFacility m_encrypter; + QTcpSocket *m_socket; + SshOutgoingPacket m_outgoingPacket; +}; + +} // namespace Internal +} // namespace Utils + +#endif // SSHCONNECTIONOUTSTATE_P_H diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 7d83452b78..f6711bee36 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -55,7 +55,27 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/buildablehelperlibrary.cpp \ $$PWD/annotateditemdelegate.cpp \ $$PWD/fileinprojectfinder.cpp \ - $$PWD/ipaddresslineedit.cpp + $$PWD/ipaddresslineedit.cpp \ + $$PWD/ssh/sshsendfacility.cpp \ + $$PWD/ssh/sshremoteprocess.cpp \ + $$PWD/ssh/sshpacketparser.cpp \ + $$PWD/ssh/sshpacket.cpp \ + $$PWD/ssh/sshoutgoingpacket.cpp \ + $$PWD/ssh/sshkeygenerator.cpp \ + $$PWD/ssh/sshkeyexchange.cpp \ + $$PWD/ssh/sshincomingpacket.cpp \ + $$PWD/ssh/sshcryptofacility.cpp \ + $$PWD/ssh/sshconnection.cpp \ + $$PWD/ssh/sshchannelmanager.cpp \ + $$PWD/ssh/sshchannel.cpp \ + $$PWD/ssh/sshcapabilities.cpp \ + $$PWD/ssh/sftppacket.cpp \ + $$PWD/ssh/sftpoutgoingpacket.cpp \ + $$PWD/ssh/sftpoperation.cpp \ + $$PWD/ssh/sftpincomingpacket.cpp \ + $$PWD/ssh/sftpdefs.cpp \ + $$PWD/ssh/sftpchannel.cpp \ + $$PWD/ssh/sshremoteprocessrunner.cpp win32 { SOURCES += $$PWD/abstractprocess_win.cpp \ @@ -121,7 +141,33 @@ HEADERS += $$PWD/environment.h \ $$PWD/buildablehelperlibrary.h \ $$PWD/annotateditemdelegate.h \ $$PWD/fileinprojectfinder.h \ - $$PWD/ipaddresslineedit.h + $$PWD/ipaddresslineedit.h \ + $$PWD/ssh/sshsendfacility_p.h \ + $$PWD/ssh/sshremoteprocess.h \ + $$PWD/ssh/sshremoteprocess_p.h \ + $$PWD/ssh/sshpacketparser_p.h \ + $$PWD/ssh/sshpacket_p.h \ + $$PWD/ssh/sshoutgoingpacket_p.h \ + $$PWD/ssh/sshkeygenerator.h \ + $$PWD/ssh/sshkeyexchange_p.h \ + $$PWD/ssh/sshincomingpacket_p.h \ + $$PWD/ssh/sshexception_p.h \ + $$PWD/ssh/ssherrors.h \ + $$PWD/ssh/sshcryptofacility_p.h \ + $$PWD/ssh/sshconnection.h \ + $$PWD/ssh/sshconnection_p.h \ + $$PWD/ssh/sshchannelmanager_p.h \ + $$PWD/ssh/sshchannel_p.h \ + $$PWD/ssh/sshcapabilities_p.h \ + $$PWD/ssh/sshbotanconversions_p.h \ + $$PWD/ssh/sftppacket_p.h \ + $$PWD/ssh/sftpoutgoingpacket_p.h \ + $$PWD/ssh/sftpoperation_p.h \ + $$PWD/ssh/sftpincomingpacket_p.h \ + $$PWD/ssh/sftpdefs.h \ + $$PWD/ssh/sftpchannel.h \ + $$PWD/ssh/sftpchannel_p.h \ + $$PWD/ssh/sshremoteprocessrunner.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.pro b/src/libs/utils/utils.pro index 7a3d40146a..dbf97987c2 100644 --- a/src/libs/utils/utils.pro +++ b/src/libs/utils/utils.pro @@ -5,6 +5,7 @@ QT += gui \ CONFIG += dll include($$PWD/../../qtcreatorlibrary.pri) +include($$PWD/../3rdparty/botan/botan.pri) include(utils-lib.pri) diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index dd416a7cc0..b8db79dbf4 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -84,26 +84,6 @@ SOURCES += mainwindow.cpp \ designmode.cpp \ editortoolbar.cpp \ helpmanager.cpp \ - ssh/sshsendfacility.cpp \ - ssh/sshremoteprocess.cpp \ - ssh/sshpacketparser.cpp \ - ssh/sshpacket.cpp \ - ssh/sshoutgoingpacket.cpp \ - ssh/sshkeygenerator.cpp \ - ssh/sshkeyexchange.cpp \ - ssh/sshincomingpacket.cpp \ - ssh/sshcryptofacility.cpp \ - ssh/sshconnection.cpp \ - ssh/sshchannelmanager.cpp \ - ssh/sshchannel.cpp \ - ssh/sshcapabilities.cpp \ - ssh/sftppacket.cpp \ - ssh/sftpoutgoingpacket.cpp \ - ssh/sftpoperation.cpp \ - ssh/sftpincomingpacket.cpp \ - ssh/sftpdefs.cpp \ - ssh/sftpchannel.cpp \ - ssh/sshremoteprocessrunner.cpp \ outputpanemanager.cpp \ navigationsubwidget.cpp \ sidebarwidget.cpp \ @@ -189,32 +169,6 @@ HEADERS += mainwindow.h \ designmode.h \ editortoolbar.h \ helpmanager.h \ - ssh/sshsendfacility_p.h \ - ssh/sshremoteprocess.h \ - ssh/sshremoteprocess_p.h \ - ssh/sshpacketparser_p.h \ - ssh/sshpacket_p.h \ - ssh/sshoutgoingpacket_p.h \ - ssh/sshkeygenerator.h \ - ssh/sshkeyexchange_p.h \ - ssh/sshincomingpacket_p.h \ - ssh/sshexception_p.h \ - ssh/ssherrors.h \ - ssh/sshcryptofacility_p.h \ - ssh/sshconnection.h \ - ssh/sshconnection_p.h \ - ssh/sshchannelmanager_p.h \ - ssh/sshchannel_p.h \ - ssh/sshcapabilities_p.h \ - ssh/sshbotanconversions_p.h \ - ssh/sftppacket_p.h \ - ssh/sftpoutgoingpacket_p.h \ - ssh/sftpoperation_p.h \ - ssh/sftpincomingpacket_p.h \ - ssh/sftpdefs.h \ - ssh/sftpchannel.h \ - ssh/sftpchannel_p.h \ - ssh/sshremoteprocessrunner.h \ outputpanemanager.h \ navigationsubwidget.h \ sidebarwidget.h \ diff --git a/src/plugins/coreplugin/ssh/sftpchannel.cpp b/src/plugins/coreplugin/ssh/sftpchannel.cpp deleted file mode 100644 index e61d27a226..0000000000 --- a/src/plugins/coreplugin/ssh/sftpchannel.cpp +++ /dev/null @@ -1,885 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sftpchannel.h" -#include "sftpchannel_p.h" - -#include "sshexception_p.h" -#include "sshincomingpacket_p.h" -#include "sshsendfacility_p.h" - -#include -#include - -namespace Core { - -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, SIGNAL(initialized()), this, SIGNAL(initialized()), - Qt::QueuedConnection); - connect(d, SIGNAL(initializationFailed(QString)), this, - SIGNAL(initializationFailed(QString)), Qt::QueuedConnection); - connect(d, SIGNAL(dataAvailable(Core::SftpJobId, QString)), this, - SIGNAL(dataAvailable(Core::SftpJobId, QString)), Qt::QueuedConnection); - connect(d, SIGNAL(finished(Core::SftpJobId,QString)), this, - SIGNAL(finished(Core::SftpJobId,QString)), Qt::QueuedConnection); - connect(d, SIGNAL(closed()), this, SIGNAL(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::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::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 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 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; -#ifdef CREATOR_SSH_DEBUG - qDebug("sftp subsystem initialized"); -#endif - 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 initializationFailed(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) -{ - qWarning("Unexpected extended data '%s' of type %d on SFTP channel.", - data.data(), type); -} - -void SftpChannelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) -{ - const char * const message = "Remote SFTP service exited with exit code %d"; -#ifdef CREATOR_SSH_DEBUG - qDebug(message, exitStatus.exitStatus); -#else - if (exitStatus.exitStatus != 0) - qWarning(message, exitStatus.exitStatus); -#endif -} - -void SftpChannelPrivate::handleExitSignal(const SshChannelExitSignal &signal) -{ - qWarning("Remote SFTP service killed; signal was %s", signal.signal.data()); -} - -void SftpChannelPrivate::handleCurrentPacket() -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("Handling SFTP packet of type %d", m_incomingPacket.type()); -#endif - 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."); - } - -#ifdef CREATOR_SSH_DEBUG - qDebug("sftp init received"); -#endif - const quint32 serverVersion = m_incomingPacket.extractServerVersion(); - if (serverVersion != ProtocolVersion) { - emit initializationFailed(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 job - = it.value().dynamicCast(); - 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(); - sendData(m_outgoingPacket.generateReadDir(op->remoteHandle, - op->jobId).rawData()); -} - -void SftpChannelPrivate::handleCreateFileHandle(const JobMap::Iterator &it) -{ - SftpCreateFile::Ptr op = it.value().staticCast(); - sendData(m_outgoingPacket.generateCloseHandle(op->remoteHandle, - op->jobId).rawData()); -} - -void SftpChannelPrivate::handleGetHandle(const JobMap::Iterator &it) -{ - SftpDownload::Ptr op = it.value().staticCast(); - 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(); - 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(); -#ifdef CREATOR_SSH_DEBUG - qDebug("%s: status = %d", Q_FUNC_INFO, response.status); -#endif - 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::RmDir: - case AbstractSftpOperation::Rm: - case AbstractSftpOperation::Rename: - case AbstractSftpOperation::CreateFile: - 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(); - if (op->parentJob == SftpUploadDir::Ptr()) { - handleStatusGeneric(it, response); - return; - } - if (op->parentJob->hasError) { - m_jobs.erase(it); - return; - } - - typedef QMap::Iterator DirIt; - DirIt dirIt = op->parentJob->mkdirsInProgress.find(op); - Q_ASSERT(dirIt != op->parentJob->mkdirsInProgress.end()); - const QString &remoteDir = dirIt.value().remoteDir; - if (response.status == SSH_FX_OK) { - emit dataAvailable(op->parentJob->jobId, - tr("Created remote directory '%1'.").arg(remoteDir)); - } else if (response.status == SSH_FX_FAILURE) { - emit dataAvailable(op->parentJob->jobId, - tr("Remote directory '%1' already exists.").arg(remoteDir)); - } else { - op->parentJob->setError(); - emit finished(op->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 + '/' + dirInfo.fileName(); - const SftpMakeDir::Ptr mkdirOp( - new SftpMakeDir(++m_nextJobId, remoteSubDir, op->parentJob)); - op->parentJob->mkdirsInProgress.insert(mkdirOp, - SftpUploadDir::Dir(dirInfo.absoluteFilePath(), remoteSubDir)); - createJob(mkdirOp); - } - - const QFileInfoList &fileInfos = localDir.entryInfoList(QDir::Files); - foreach (const QFileInfo &fileInfo, fileInfos) { - QSharedPointer localFile(new QFile(fileInfo.absoluteFilePath())); - if (!localFile->open(QIODevice::ReadOnly)) { - op->parentJob->setError(); - emit finished(op->parentJob->jobId, - tr("Could not open local file '%1': %2") - .arg(fileInfo.absoluteFilePath(), localFile->error())); - m_jobs.erase(it); - return; - } - - const QString remoteFilePath = remoteDir + '/' + fileInfo.fileName(); - SftpUploadFile::Ptr uploadFileOp(new SftpUploadFile(++m_nextJobId, - remoteFilePath, localFile, SftpOverwriteExisting, op->parentJob)); - createJob(uploadFileOp); - op->parentJob->uploadsInProgress.append(uploadFileOp); - } - - op->parentJob->mkdirsInProgress.erase(dirIt); - if (op->parentJob->mkdirsInProgress.isEmpty() - && op->parentJob->uploadsInProgress.isEmpty()) - emit finished(op->parentJob->jobId); - m_jobs.erase(it); -} - -void SftpChannelPrivate::handleLsStatus(const JobMap::Iterator &it, - const SftpStatusResponse &response) -{ - SftpListDir::Ptr op = it.value().staticCast(); - 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(); - 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 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(); - 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(); - if (op->state != SftpListDir::Open) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Unexpected SSH_FXP_NAME packet."); - } - - for (int i = 0; i < response.files.count(); ++i) { - const SftpFile &file = response.files.at(i); - emit dataAvailable(op->jobId, file.fileName); - } - 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(); - 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); - AbstractSftpTransfer::Ptr transfer - = it.value().dynamicCast(); - 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(); - 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(); - 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() -{ - m_jobs.clear(); - m_incomingData.clear(); - m_incomingPacket.clear(); - emit closed(); -} - -void SftpChannelPrivate::handleOpenSuccessInternal() -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("SFTP session started"); -#endif - m_sendFacility.sendSftpPacket(remoteChannel()); - m_sftpState = SubsystemRequested; -} - -void SftpChannelPrivate::handleOpenFailureInternal() -{ - if (channelState() != SessionRequested) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet."); - } - emit initializationFailed(tr("Server could not start session.")); -} - -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(); - 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::removeTransferRequest(const JobMap::Iterator &it) -{ - --it.value().staticCast()->inFlightCount; - m_jobs.erase(it); -} - -void SftpChannelPrivate::sendWriteRequest(const JobMap::Iterator &it) -{ - SftpUploadFile::Ptr job = it.value().staticCast(); - 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(); - 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 Core diff --git a/src/plugins/coreplugin/ssh/sftpchannel.h b/src/plugins/coreplugin/ssh/sftpchannel.h deleted file mode 100644 index 0cbbf9c0cc..0000000000 --- a/src/plugins/coreplugin/ssh/sftpchannel.h +++ /dev/null @@ -1,128 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTCHANNEL_H -#define SFTCHANNEL_H - -#include "sftpdefs.h" -#include "sftpincomingpacket_p.h" - -#include - -#include -#include -#include -#include - -namespace Core { - -namespace Internal { -class SftpChannelPrivate; -class SshChannelManager; -class SshSendFacility; -} // namespace Internal - -/* - * This 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. - */ -class CORE_EXPORT SftpChannel : public QObject -{ - Q_OBJECT - - friend class Internal::SftpChannelPrivate; - friend class Internal::SshChannelManager; -public: - typedef QSharedPointer Ptr; - - enum State { Uninitialized, Initializing, Initialized, Closing, Closed }; - State state() const; - - void initialize(); - void closeChannel(); - - 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 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 initializationFailed(const QString &reason); - void closed(); - - // error.isEmpty <=> finished successfully - void finished(Core::SftpJobId job, const QString &error = QString()); - - /* - * This signal is only emitted by the "List Directory" operation, - * one file at a time. - // TODO: Also emit for each file copied by uploadDir(). - */ - void dataAvailable(Core::SftpJobId job, const QString &data); - -private: - SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility); - - Internal::SftpChannelPrivate *d; -}; - -} // namespace Core - -#endif // SFTPCHANNEL_H diff --git a/src/plugins/coreplugin/ssh/sftpchannel_p.h b/src/plugins/coreplugin/ssh/sftpchannel_p.h deleted file mode 100644 index 60cb5d24d2..0000000000 --- a/src/plugins/coreplugin/ssh/sftpchannel_p.h +++ /dev/null @@ -1,133 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTCHANNEL_P_H -#define SFTCHANNEL_P_H - -#include "sftpdefs.h" -#include "sftpincomingpacket_p.h" -#include "sftpoperation_p.h" -#include "sftpoutgoingpacket_p.h" -#include "sshchannel_p.h" - -#include -#include - -namespace Core { -class SftpChannel; -namespace Internal { - -class SftpChannelPrivate : public AbstractSshChannel -{ - Q_OBJECT - friend class Core::SftpChannel; -public: - - enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized }; - - virtual void handleChannelSuccess(); - virtual void handleChannelFailure(); - - virtual void closeHook(); - -signals: - void initialized(); - void initializationFailed(const QString &reason); - void closed(); - void finished(Core::SftpJobId job, const QString &error = QString()); - void dataAvailable(Core::SftpJobId job, const QString &data); - -private: - typedef QMap JobMap; - - SftpChannelPrivate(quint32 channelId, SshSendFacility &sendFacility, - SftpChannel *sftp); - SftpJobId createJob(const AbstractSftpOperation::Ptr &job); - - virtual void handleOpenSuccessInternal(); - virtual void handleOpenFailureInternal(); - 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); - - 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); - - 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 Core - -#endif // SFTPCHANNEL_P_H diff --git a/src/plugins/coreplugin/ssh/sftpdefs.cpp b/src/plugins/coreplugin/ssh/sftpdefs.cpp deleted file mode 100644 index dd50f2ac72..0000000000 --- a/src/plugins/coreplugin/ssh/sftpdefs.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sftpdefs.h" - -namespace Core { const SftpJobId SftpInvalidJob = 0; } diff --git a/src/plugins/coreplugin/ssh/sftpdefs.h b/src/plugins/coreplugin/ssh/sftpdefs.h deleted file mode 100644 index ccf3c1c4f0..0000000000 --- a/src/plugins/coreplugin/ssh/sftpdefs.h +++ /dev/null @@ -1,52 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTPDEFS_H -#define SFTPDEFS_H - -#include - -#include - -namespace Core { - -typedef quint32 SftpJobId; -CORE_EXPORT extern const SftpJobId SftpInvalidJob; - -enum SftpOverwriteMode { - SftpOverwriteExisting, SftpAppendToExisting, SftpSkipExisting -}; - -} // namespace Core - -#endif // SFTPDEFS_H diff --git a/src/plugins/coreplugin/ssh/sftpincomingpacket.cpp b/src/plugins/coreplugin/ssh/sftpincomingpacket.cpp deleted file mode 100644 index 1df7fbe69c..0000000000 --- a/src/plugins/coreplugin/ssh/sftpincomingpacket.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sftpincomingpacket_p.h" - -#include "sshexception_p.h" -#include "sshpacketparser_p.h" - -namespace Core { -namespace Internal { - -namespace { - const int SSH_FILEXFER_ATTR_SIZE = 0x00000001; - const int SSH_FILEXFER_ATTR_UIDGID = 0x00000002; - const int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004; - const int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; - const int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000; -} // anonymous namespace - -SftpIncomingPacket::SftpIncomingPacket() : m_length(0) -{ -} - -void SftpIncomingPacket::consumeData(QByteArray &newData) -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("%s: current data size = %d, new data size = %d", Q_FUNC_INFO, - m_data.size(), newData.size()); -#endif - - 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(0)); - if (m_length < static_cast(TypeOffset + 1) - || m_length > MaxPacketSize) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid length field in SFTP packet."); - } - } - - moveFirstBytes(m_data, newData, - qMin(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 (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 (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(SshPacketParser::asUint32(m_data, &offset)); - response.errorString = SshPacketParser::asUserString(m_data, &offset); - response.language = SshPacketParser::asString(m_data, &offset); - return response; - } catch (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 (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 (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 (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 Core diff --git a/src/plugins/coreplugin/ssh/sftpincomingpacket_p.h b/src/plugins/coreplugin/ssh/sftpincomingpacket_p.h deleted file mode 100644 index d1248c7e87..0000000000 --- a/src/plugins/coreplugin/ssh/sftpincomingpacket_p.h +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTPINCOMINGPACKET_P_H -#define SFTPINCOMINGPACKET_P_H - -#include "sftppacket_p.h" - -namespace Core { -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 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 Core - -#endif // SFTPINCOMINGPACKET_P_H diff --git a/src/plugins/coreplugin/ssh/sftpoperation.cpp b/src/plugins/coreplugin/ssh/sftpoperation.cpp deleted file mode 100644 index edecb5710b..0000000000 --- a/src/plugins/coreplugin/ssh/sftpoperation.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sftpoperation_p.h" - -#include "sftpoutgoingpacket_p.h" - -#include - -namespace Core { -namespace Internal { - -AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId) -{ -} - -AbstractSftpOperation::~AbstractSftpOperation() { } - - -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, const QString &path) - : AbstractSftpOperation(jobId), 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); -} - - -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, jobId); -} - - -const int AbstractSftpTransfer::MaxInFlightCount = 10; // Experimentally found to be enough. - -AbstractSftpTransfer::AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath, - const QSharedPointer &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 &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 &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; - return packet.generateOpenFileForWriting(remotePath, mode, jobId); -} - - -SftpUploadDir::~SftpUploadDir() {} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sftpoperation_p.h b/src/plugins/coreplugin/ssh/sftpoperation_p.h deleted file mode 100644 index c1934e81b0..0000000000 --- a/src/plugins/coreplugin/ssh/sftpoperation_p.h +++ /dev/null @@ -1,232 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTPOPERATION_P_H -#define SFTPOPERATION_P_H - -#include "sftpdefs.h" - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QFile; -QT_END_NAMESPACE - -namespace Core { -namespace Internal { - -class SftpOutgoingPacket; - -struct AbstractSftpOperation -{ - typedef QSharedPointer Ptr; - enum Type { - ListDir, MakeDir, RmDir, Rm, Rename, 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 SftpMakeDir : public AbstractSftpOperation -{ - typedef QSharedPointer Ptr; - - SftpMakeDir(SftpJobId jobId, const QString &path, - const QSharedPointer &parentJob = QSharedPointer()); - virtual Type type() const { return MakeDir; } - virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); - - const QSharedPointer parentJob; - const QString remoteDir; -}; - -struct SftpRmDir : public AbstractSftpOperation -{ - typedef QSharedPointer Ptr; - - SftpRmDir(SftpJobId jobId, const QString &path); - virtual Type type() const { return RmDir; } - virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); - - const QString remoteDir; -}; - -struct SftpRm : public AbstractSftpOperation -{ - typedef QSharedPointer 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 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 AbstractSftpOperationWithHandle : public AbstractSftpOperation -{ - typedef QSharedPointer 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 Ptr; - - SftpListDir(SftpJobId jobId, const QString &path); - virtual Type type() const { return ListDir; } - virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); -}; - - -struct SftpCreateFile : public AbstractSftpOperationWithHandle -{ - typedef QSharedPointer 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 Ptr; - - AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath, - const QSharedPointer &localFile); - ~AbstractSftpTransfer(); - void calculateInFlightCount(quint32 chunkSize); - - static const int MaxInFlightCount; - - const QSharedPointer localFile; - quint64 fileSize; - quint64 offset; - int inFlightCount; - bool statRequested; -}; - -struct SftpDownload : public AbstractSftpTransfer -{ - typedef QSharedPointer Ptr; - SftpDownload(SftpJobId jobId, const QString &remotePath, - const QSharedPointer &localFile); - virtual Type type() const { return Download; } - virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); - - QMap offsets; - SftpJobId eofId; -}; - -struct SftpUploadFile : public AbstractSftpTransfer -{ - typedef QSharedPointer Ptr; - - SftpUploadFile(SftpJobId jobId, const QString &remotePath, - const QSharedPointer &localFile, SftpOverwriteMode mode, - const QSharedPointer &parentJob = QSharedPointer()); - virtual Type type() const { return UploadFile; } - virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet); - - const QSharedPointer parentJob; - SftpOverwriteMode mode; -}; - -// Composite operation. -struct SftpUploadDir -{ - typedef QSharedPointer 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 uploadsInProgress; - QMap mkdirsInProgress; -}; - -} // namespace Internal -} // namespace Core - -#endif // SFTPOPERATION_P_H diff --git a/src/plugins/coreplugin/ssh/sftpoutgoingpacket.cpp b/src/plugins/coreplugin/ssh/sftpoutgoingpacket.cpp deleted file mode 100644 index 66a06d458a..0000000000 --- a/src/plugins/coreplugin/ssh/sftpoutgoingpacket.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sftpoutgoingpacket_p.h" - -#include "sshpacket_p.h" - -#include - -namespace Core { -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::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 requestId) -{ - return generateOpenFile(path, Write, mode, requestId); -} - -SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForReading(const QString &path, - quint32 requestId) -{ - // Note: Overwrite mode is irrelevant and will be ignored. - return generateOpenFile(path, Read, SftpSkipExisting, 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::generateOpenFile(const QString &path, - OpenType openType, SftpOverwriteMode mode, quint32 requestId) -{ - quint32 pFlags; - 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; - } - return init(SSH_FXP_OPEN, requestId).appendString(path).appendInt(pFlags) - .appendInt(DefaultAttributes).finalize(); -} - -SftpOutgoingPacket &SftpOutgoingPacket::init(SftpPacketType type, - quint32 requestId) -{ - m_data.resize(TypeOffset + 1); - m_data[TypeOffset] = type; - if (type != SSH_FXP_INIT) { - appendInt(requestId); -#ifdef CREATOR_SSH_DEBUG - qDebug("Generating SFTP packet of type %d with request id %u", type, - requestId); -#endif - } - 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; -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sftpoutgoingpacket_p.h b/src/plugins/coreplugin/ssh/sftpoutgoingpacket_p.h deleted file mode 100644 index c88a729802..0000000000 --- a/src/plugins/coreplugin/ssh/sftpoutgoingpacket_p.h +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTPOUTGOINGPACKET_P_H -#define SFTPOUTGOINGPACKET_P_H - -#include "sftppacket_p.h" -#include "sftpdefs.h" - -namespace Core { -namespace Internal { - -class SftpOutgoingPacket : public AbstractSftpPacket -{ -public: - SftpOutgoingPacket(); - SftpOutgoingPacket &generateInit(quint32 version); - 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 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); - -private: - static QByteArray encodeString(const QString &string); - - enum OpenType { Read, Write }; - SftpOutgoingPacket &generateOpenFile(const QString &path, OpenType openType, - SftpOverwriteMode mode, 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 Core - -#endif // SFTPOUTGOINGPACKET_P_H diff --git a/src/plugins/coreplugin/ssh/sftppacket.cpp b/src/plugins/coreplugin/ssh/sftppacket.cpp deleted file mode 100644 index c9fe5a5815..0000000000 --- a/src/plugins/coreplugin/ssh/sftppacket.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sftppacket_p.h" - -#include "sshpacketparser_p.h" - -namespace Core { -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 Core diff --git a/src/plugins/coreplugin/ssh/sftppacket_p.h b/src/plugins/coreplugin/ssh/sftppacket_p.h deleted file mode 100644 index c6a3af4964..0000000000 --- a/src/plugins/coreplugin/ssh/sftppacket_p.h +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SFTPPACKET_P_H -#define SFTPPACKET_P_H - -#include -#include -#include - -namespace Core { -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 -}; - -class AbstractSftpPacket -{ -public: - AbstractSftpPacket(); - quint32 requestId() const; - const QByteArray &rawData() const { return m_data; } - SftpPacketType type() const { return static_cast(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(m_data.size()); } - - static const int TypeOffset; - static const int RequestIdOffset; - static const int PayloadOffset; - - QByteArray m_data; -}; - -} // namespace Internal -} // namespace Core - -#endif // SFTPPACKET_P_H diff --git a/src/plugins/coreplugin/ssh/sshbotanconversions_p.h b/src/plugins/coreplugin/ssh/sshbotanconversions_p.h deleted file mode 100644 index fa7856f83d..0000000000 --- a/src/plugins/coreplugin/ssh/sshbotanconversions_p.h +++ /dev/null @@ -1,101 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef BYTEARRAYCONVERSIONS_P_H -#define BYTEARRAYCONVERSIONS_P_H - -#include "sshcapabilities_p.h" - -#include -#include - -namespace Core { -namespace Internal { - -inline const Botan::byte *convertByteArray(const QByteArray &a) -{ - return reinterpret_cast(a.constData()); -} - -inline Botan::byte *convertByteArray(QByteArray &a) -{ - return reinterpret_cast(a.data()); -} - -inline QByteArray convertByteArray(const Botan::SecureVector &v) -{ - return QByteArray(reinterpret_cast(v.begin()), v.size()); -} - -inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName) -{ - Q_ASSERT(rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1 - || rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1); - return rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1 - ? "modp/ietf/1024" : "modp/ietf/2048"; -} - -inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName) -{ - Q_ASSERT(rfcAlgoName == SshCapabilities::CryptAlgo3Des - || rfcAlgoName == SshCapabilities::CryptAlgoAes128); - return rfcAlgoName == SshCapabilities::CryptAlgo3Des - ? "TripleDES" : "AES-128"; -} - -inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName) -{ - Q_ASSERT(rfcAlgoName == SshCapabilities::PubKeyDss - || rfcAlgoName == SshCapabilities::PubKeyRsa); - return rfcAlgoName == SshCapabilities::PubKeyDss - ? "EMSA1(SHA-1)" : "EMSA3(SHA-1)"; -} - -inline const char *botanSha1Name() { return "SHA-1"; } - -inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName) -{ - Q_ASSERT(rfcAlgoName == SshCapabilities::HMacSha1); - return botanSha1Name(); -} - -inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName) -{ - Q_ASSERT(rfcAlgoName == SshCapabilities::HMacSha1); - return 20; -} - -} // namespace Internal -} // namespace Core - -#endif // BYTEARRAYCONVERSIONS_P_H diff --git a/src/plugins/coreplugin/ssh/sshcapabilities.cpp b/src/plugins/coreplugin/ssh/sshcapabilities.cpp deleted file mode 100644 index 589029e875..0000000000 --- a/src/plugins/coreplugin/ssh/sshcapabilities.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshcapabilities_p.h" - -#include "sshexception_p.h" - -#include -#include - -namespace Core { -namespace Internal { - -namespace { - QByteArray listAsByteArray(const QList &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 QList SshCapabilities::KeyExchangeMethods - = QList() << SshCapabilities::DiffieHellmanGroup1Sha1 - << SshCapabilities::DiffieHellmanGroup14Sha1; - -const QByteArray SshCapabilities::PubKeyDss("ssh-dss"); -const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa"); -const QList SshCapabilities::PublicKeyAlgorithms - = QList() << SshCapabilities::PubKeyRsa - << SshCapabilities::PubKeyDss; - -const QByteArray SshCapabilities::CryptAlgo3Des("3des-cbc"); -const QByteArray SshCapabilities::CryptAlgoAes128("aes128-cbc"); -const QList SshCapabilities::EncryptionAlgorithms - = QList() << SshCapabilities::CryptAlgoAes128 - << SshCapabilities::CryptAlgo3Des; - -const QByteArray SshCapabilities::HMacSha1("hmac-sha1"); -const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96"); -const QList SshCapabilities::MacAlgorithms - = QList() /* << SshCapabilities::HMacSha196 */ - << SshCapabilities::HMacSha1; - -const QList SshCapabilities::CompressionAlgorithms - = QList() << "none"; - -const QByteArray SshCapabilities::SshConnectionService("ssh-connection"); - -const QByteArray SshCapabilities::PublicKeyAuthMethod("publickey"); -const QByteArray SshCapabilities::PasswordAuthMethod("password"); - - -QByteArray SshCapabilities::findBestMatch(const QList &myCapabilities, - const QList &serverCapabilities) -{ - foreach (const QByteArray &myCapability, myCapabilities) { - if (serverCapabilities.contains(myCapability)) - return myCapability; - } - - 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(listAsByteArray(myCapabilities).data()) - .arg(listAsByteArray(serverCapabilities).data())); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshcapabilities_p.h b/src/plugins/coreplugin/ssh/sshcapabilities_p.h deleted file mode 100644 index 6a1e1a7b53..0000000000 --- a/src/plugins/coreplugin/ssh/sshcapabilities_p.h +++ /dev/null @@ -1,76 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CAPABILITIES_P_H -#define CAPABILITIES_P_H - -#include -#include - -namespace Core { -namespace Internal { - -class SshCapabilities -{ -public: - static const QByteArray DiffieHellmanGroup1Sha1; - static const QByteArray DiffieHellmanGroup14Sha1; - static const QList KeyExchangeMethods; - - static const QByteArray PubKeyDss; - static const QByteArray PubKeyRsa; - static const QList PublicKeyAlgorithms; - - static const QByteArray CryptAlgo3Des; - static const QByteArray CryptAlgoAes128; - static const QList EncryptionAlgorithms; - - static const QByteArray HMacSha1; - static const QByteArray HMacSha196; - static const QList MacAlgorithms; - - static const QList CompressionAlgorithms; - - static const QByteArray SshConnectionService; - - static const QByteArray PublicKeyAuthMethod; - static const QByteArray PasswordAuthMethod; - - static QByteArray findBestMatch(const QList &myCapabilities, - const QList &serverCapabilities); -}; - -} // namespace Internal -} // namespace Core - -#endif // CAPABILITIES_P_H diff --git a/src/plugins/coreplugin/ssh/sshchannel.cpp b/src/plugins/coreplugin/ssh/sshchannel.cpp deleted file mode 100644 index 3e8d5d50b3..0000000000 --- a/src/plugins/coreplugin/ssh/sshchannel.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshchannel_p.h" - -#include "sshincomingpacket_p.h" -#include "sshsendfacility_p.h" - -#include - -#include - -namespace Core { -namespace Internal { - -namespace { - const quint32 MinMaxPacketSize = 32768; - const quint32 MaxPacketSize = 16 * 1024 * 1024; - const quint32 InitialWindowSize = MaxPacketSize; - const quint32 NoChannel = 0xffffffffu; -} // anonymous namespace - -AbstractSshChannel::AbstractSshChannel(quint32 channelId, - SshSendFacility &sendFacility) - : m_sendFacility(sendFacility), m_timeoutTimer(new QTimer(this)), - m_localChannel(channelId), m_remoteChannel(NoChannel), - m_localWindowSize(InitialWindowSize), m_remoteWindowSize(0), - m_state(Inactive) -{ - m_timeoutTimer->setSingleShot(true); - connect(m_timeoutTimer, SIGNAL(timeout()), this, SIGNAL(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 (Botan::Exception &e) { - m_errorString = QString::fromAscii(e.what()); - closeChannel(); - } -} - -void AbstractSshChannel::sendData(const QByteArray &data) -{ - try { - m_sendBuffer += data; - flushSendBuffer(); - } catch (Botan::Exception &e) { - m_errorString = QString::fromAscii(e.what()); - closeChannel(); - } -} - -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() -{ - const quint32 bytesToSend - = qMin(m_remoteWindowSize, m_sendBuffer.size()); - if (bytesToSend > 0) { - 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) -{ - if (m_state != SessionRequested) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet."); - } - m_timeoutTimer->stop(); - - if (remoteMaxPacketSize < MinMaxPacketSize) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Maximum packet size too low."); - } - -#ifdef CREATOR_SSH_DEBUG - qDebug("Channel opened. remote channel id: %u, remote window size: %u, " - "remote max packet size: %u", - remoteChannelId, remoteWindowSize, remoteMaxPacketSize); -#endif - m_remoteChannel = remoteChannelId; - m_remoteWindowSize = remoteWindowSize; - m_remoteMaxPacketSize = remoteMaxPacketSize; - setChannelState(SessionEstablished); - handleOpenSuccessInternal(); -} - -void AbstractSshChannel::handleOpenFailure(const QString &reason) -{ - if (m_state != SessionRequested) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid SSH_MSG_CHANNEL_OPEN_FAILURE packet."); - } - m_timeoutTimer->stop(); - -#ifdef CREATOR_SSH_DEBUG - qDebug("Channel open request failed for channel %u", m_localChannel); -#endif - m_errorString = reason; - handleOpenFailureInternal(); -} - -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; -} - -void AbstractSshChannel::handleChannelClose() -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("Receiving CLOSE for channel %u", m_localChannel); -#endif - 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. - qWarning("Ignoring unknown request type '%s'", requestType.data()); -} - -int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &data) -{ - checkChannelActive(); - - const int bytesToDeliver = qMin(data.size(), maxDataSize()); - if (bytesToDeliver != data.size()) - qWarning("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 { - setChannelState(CloseRequested); - m_sendFacility.sendChannelEofPacket(m_remoteChannel); - m_sendFacility.sendChannelClosePacket(m_remoteChannel); - } - } -} - -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 Core diff --git a/src/plugins/coreplugin/ssh/sshchannel_p.h b/src/plugins/coreplugin/ssh/sshchannel_p.h deleted file mode 100644 index 43915046ff..0000000000 --- a/src/plugins/coreplugin/ssh/sshchannel_p.h +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHCHANNEL_P_H -#define SSHCHANNEL_P_H - -#include -#include -#include - -QT_FORWARD_DECLARE_CLASS(QTimer) - -namespace Core { -namespace Internal { - -struct SshChannelExitSignal; -struct SshChannelExitStatus; -class SshIncomingPacket; -class SshSendFacility; - -class AbstractSshChannel : public QObject -{ - Q_OBJECT -public: - enum ChannelState { - Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed - }; - - ChannelState channelState() const { return m_state; } - void setChannelState(ChannelState state); - - void setError(const QString &error) { m_errorString = error; } - QString errorString() const { return m_errorString; } - - quint32 localChannelId() const { return m_localChannel; } - quint32 remoteChannel() const { return m_remoteChannel; } - - virtual void handleChannelSuccess()=0; - virtual void handleChannelFailure()=0; - - virtual void closeHook()=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 requestSessionStart(); - void sendData(const QByteArray &data); - void closeChannel(); - - virtual ~AbstractSshChannel(); - - static const int ReplyTimeout = 10000; // milli seconds - -signals: - void timeout(); - -protected: - AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility); - - quint32 maxDataSize() const; - void checkChannelActive(); - - SshSendFacility &m_sendFacility; - QTimer * const m_timeoutTimer; - -private: - virtual void handleOpenSuccessInternal()=0; - virtual void handleOpenFailureInternal()=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; - - void setState(ChannelState newState); - 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; - QString m_errorString; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHCHANNEL_P_H diff --git a/src/plugins/coreplugin/ssh/sshchannelmanager.cpp b/src/plugins/coreplugin/ssh/sshchannelmanager.cpp deleted file mode 100644 index 4362d11542..0000000000 --- a/src/plugins/coreplugin/ssh/sshchannelmanager.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshchannelmanager_p.h" - -#include "sftpchannel.h" -#include "sftpchannel_p.h" -#include "sshincomingpacket_p.h" -#include "sshremoteprocess.h" -#include "sshremoteprocess_p.h" -#include "sshsendfacility_p.h" - -#include - -namespace Core { -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 &) -{ - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Server tried to open channel on client."); -} - -void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet) -{ - const SshChannelOpenFailure &failure = packet.extractChannelOpenFailure(); - ChannelIterator it = lookupChannelAsIterator(failure.localChannel); - try { - it.value()->handleOpenFailure(failure.reasonString); - } catch (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); - } -} - -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(); -} - -Core::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteArray &command) -{ - SshRemoteProcess::Ptr proc(new SshRemoteProcess(command, m_nextLocalChannelId++, m_sendFacility)); - insertChannel(proc->d, proc); - return proc; -} - -Core::SftpChannel::Ptr SshChannelManager::createSftpChannel() -{ - SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility)); - insertChannel(sftp->d, sftp); - return sftp; -} - -void SshChannelManager::insertChannel(AbstractSshChannel *priv, - const QSharedPointer &pub) -{ - connect(priv, SIGNAL(timeout()), this, SIGNAL(timeout())); - m_channels.insert(priv->localChannelId(), priv); - m_sessions.insert(priv, pub); -} - -void SshChannelManager::closeAllChannels() -{ - for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) - it.value()->closeChannel(); - m_channels.clear(); - m_sessions.clear(); -} - -void SshChannelManager::removeChannel(ChannelIterator it) -{ - Q_ASSERT(it != m_channels.end() && "Unexpected channel lookup failure."); - const int removeCount = m_sessions.remove(it.value()); - Q_ASSERT(removeCount == 1 && "Session for channel not found."); - m_channels.erase(it); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshchannelmanager_p.h b/src/plugins/coreplugin/ssh/sshchannelmanager_p.h deleted file mode 100644 index 94b44088c2..0000000000 --- a/src/plugins/coreplugin/ssh/sshchannelmanager_p.h +++ /dev/null @@ -1,97 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHCHANNELLAYER_P_H -#define SSHCHANNELLAYER_P_H - -#include -#include -#include - -namespace Core { - -class SftpChannel; -class SshRemoteProcess; - -namespace Internal { - -class AbstractSshChannel; -class SshIncomingPacket; -class SshSendFacility; - -class SshChannelManager : public QObject -{ - Q_OBJECT -public: - SshChannelManager(SshSendFacility &sendFacility, QObject *parent); - - QSharedPointer createRemoteProcess(const QByteArray &command); - QSharedPointer createSftpChannel(); - void closeAllChannels(); - - 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); - -signals: - void timeout(); - -private: - typedef QHash::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 &pub); - - SshSendFacility &m_sendFacility; - QHash m_channels; - QHash > m_sessions; - quint32 m_nextLocalChannelId; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHCHANNELLAYER_P_H diff --git a/src/plugins/coreplugin/ssh/sshconnection.cpp b/src/plugins/coreplugin/ssh/sshconnection.cpp deleted file mode 100644 index 802c2ae003..0000000000 --- a/src/plugins/coreplugin/ssh/sshconnection.cpp +++ /dev/null @@ -1,645 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshconnection.h" -#include "sshconnection_p.h" - -#include "sftpchannel.h" -#include "sshcapabilities_p.h" -#include "sshchannelmanager_p.h" -#include "sshcryptofacility_p.h" -#include "sshexception_p.h" -#include "sshkeyexchange_p.h" - -#include - -#include -#include - -#include -#include -#include -#include - -namespace Core { - -namespace { - const QByteArray ClientId("SSH-2.0-QtCreator\r\n"); - - bool staticInitializationsDone = false; - QMutex staticInitMutex; - - void doStaticInitializationsIfNecessary() - { - if (!staticInitializationsDone) { - staticInitMutex.lock(); - if (!staticInitializationsDone) { - Botan::LibraryInitializer::initialize("thread_safe=true"); - qRegisterMetaType("Core::SshError"); - qRegisterMetaType("Core::SftpJobId"); - staticInitializationsDone = true; - } - staticInitMutex.unlock(); - } - } -} // anonymous namespace - - -SshConnectionParameters::SshConnectionParameters(ProxyType proxyType) : - timeout(0), authType(AuthByKey), port(0), proxyType(proxyType) -{ -} - -static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2) -{ - return p1.host == p2.host && p1.uname == p2.uname - && p1.authType == p2.authType - && (p1.authType == SshConnectionParameters::AuthByPwd ? - p1.pwd == p2.pwd : p1.privateKeyFile == p2.privateKeyFile) - && p1.timeout == p2.timeout && p1.port == p2.port; -} - -CORE_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2) -{ - return equals(p1, p2); -} - -CORE_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2) -{ - return !equals(p1, p2); -} - -// TODO: Mechanism for checking the host key. First connection to host: save, later: compare - -SshConnection::Ptr SshConnection::create() -{ - doStaticInitializationsIfNecessary(); - return Ptr(new SshConnection); -} - -SshConnection::SshConnection() : d(new Internal::SshConnectionPrivate(this)) -{ - connect(d, SIGNAL(connected()), this, SIGNAL(connected()), - Qt::QueuedConnection); - connect(d, SIGNAL(dataAvailable(QString)), this, - SIGNAL(dataAvailable(QString)), Qt::QueuedConnection); - connect(d, SIGNAL(disconnected()), this, SIGNAL(disconnected()), - Qt::QueuedConnection); - connect(d, SIGNAL(error(Core::SshError)), this, - SIGNAL(error(Core::SshError)), Qt::QueuedConnection); -} - -void SshConnection::connectToHost(const SshConnectionParameters &serverInfo) -{ - d->connectToHost(serverInfo); -} - -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->error(); -} - -QString SshConnection::errorString() const -{ - return d->errorString(); -} - -SshConnectionParameters SshConnection::connectionParameters() const -{ - return d->m_connParams; -} - -SshConnection::~SshConnection() -{ - disconnect(); - disconnectFromHost(); - delete d; -} - -QSharedPointer SshConnection::createRemoteProcess(const QByteArray &command) -{ - QTC_ASSERT(state() == Connected, return QSharedPointer()); - return d->createRemoteProcess(command); -} - -QSharedPointer SshConnection::createSftpChannel() -{ - QTC_ASSERT(state() == Connected, return QSharedPointer()); - return d->createSftpChannel(); -} - - -namespace Internal { - -SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn) - : m_socket(new QTcpSocket(this)), m_state(SocketUnconnected), - m_sendFacility(m_socket), - m_channelManager(new SshChannelManager(m_sendFacility, this)), - m_connParams(SshConnectionParameters::DefaultProxy), - m_error(SshNoError), m_ignoreNextPacket(false), m_conn(conn) -{ - setupPacketHandlers(); - m_timeoutTimer.setSingleShot(true); - m_keepAliveTimer.setSingleShot(true); - m_keepAliveTimer.setInterval(10000); - connect(m_channelManager, SIGNAL(timeout()), this, SLOT(handleTimeout())); -} - -SshConnectionPrivate::~SshConnectionPrivate() -{ - disconnect(); -} - -void SshConnectionPrivate::setupPacketHandlers() -{ - typedef SshConnectionPrivate This; - - setupPacketHandler(SSH_MSG_KEXINIT, StateList() << SocketConnected, - &This::handleKeyExchangeInitPacket); - setupPacketHandler(SSH_MSG_KEXDH_REPLY, StateList() << KeyExchangeStarted, - &This::handleKeyExchangeReplyPacket); - - setupPacketHandler(SSH_MSG_NEWKEYS, StateList() << KeyExchangeSuccess, - &This::handleNewKeysPacket); - setupPacketHandler(SSH_MSG_SERVICE_ACCEPT, - StateList() << UserAuthServiceRequested, - &This::handleServiceAcceptPacket); - 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); - - 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 - << KeyExchangeStarted << KeyExchangeSuccess - << UserAuthServiceRequested << UserAuthRequested - << ConnectionEstablished, &This::handleDisconnect); - - setupPacketHandler(SSH_MSG_UNIMPLEMENTED, - StateList() << ConnectionEstablished, &This::handleUnimplementedPacket); -} - -void SshConnectionPrivate::setupPacketHandler(SshPacketType type, - const SshConnectionPrivate::StateList &states, - SshConnectionPrivate::PacketHandler handler) -{ - m_packetHandlers.insert(type, HandlerInStates(states, handler)); -} - -void SshConnectionPrivate::handleSocketConnected() -{ - m_state = SocketConnected; - sendData(ClientId); -} - -void SshConnectionPrivate::handleIncomingData() -{ - if (m_state == SocketUnconnected) - return; // For stuff queued in the event loop after we've called closeConnection(); - - try { - if (!canUseSocket()) - return; - m_incomingData += m_socket->readAll(); -#ifdef CREATOR_SSH_DEBUG - qDebug("state = %d, remote data size = %d", m_state, - m_incomingData.count()); -#endif - if (m_state == SocketConnected) - handleServerId(); - handlePackets(); - } catch (SshServerException &e) { - closeConnection(e.error, SshProtocolError, e.errorStringServer, - tr("SSH Protocol error: %1").arg(e.errorStringUser)); - } catch (SshClientException &e) { - closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "", - e.errorString); - } catch (Botan::Exception &e) { - closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "", - tr("Botan library exception: %1").arg(e.what())); - } -} - -void SshConnectionPrivate::handleServerId() -{ - const int idOffset = m_incomingData.indexOf("SSH-"); - if (idOffset == -1) - return; - m_incomingData.remove(0, idOffset); - if (m_incomingData.size() < 7) - return; - const QByteArray &version = m_incomingData.mid(4, 3); - if (version != "2.0") { - throw SshServerException(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, - "Invalid protocol version.", - tr("Invalid protocol version: Expected '2.0', got '%1'.") - .arg(SshPacketParser::asUserString(version))); - } - const int endOffset = m_incomingData.indexOf("\r\n"); - if (endOffset == -1) - return; - if (m_incomingData.at(7) != '-') { - throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid server id.", tr("Invalid server id '%1'.") - .arg(SshPacketParser::asUserString(m_incomingData))); - } - - m_keyExchange.reset(new SshKeyExchange(m_sendFacility)); - m_keyExchange->sendKexInitPacket(m_incomingData.left(endOffset)); - m_incomingData.remove(0, endOffset + 2); -} - -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_state == KeyExchangeStarted || !m_ignoreNextPacket); - - if (m_ignoreNextPacket) { - m_ignoreNextPacket = false; - return; - } - - QHash::ConstIterator it - = m_packetHandlers.find(m_incomingPacket.type()); - if (it == m_packetHandlers.end()) { - m_sendFacility.sendMsgUnimplementedPacket(m_incomingPacket.serverSeqNr()); - return; - } - if (!it.value().first.contains(m_state)) { - throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, - "Unexpected packet.", tr("Unexpected packet of type %1.") - .arg(m_incomingPacket.type())); - } - (this->*it.value().second)(); -} - -void SshConnectionPrivate::handleKeyExchangeInitPacket() -{ - // If the server sends a guessed packet, the guess must be wrong, - // because the algorithms we support requires us to initiate the - // key exchange. - if (m_keyExchange->sendDhInitPacket(m_incomingPacket)) - m_ignoreNextPacket = true; - m_state = KeyExchangeStarted; -} - -void SshConnectionPrivate::handleKeyExchangeReplyPacket() -{ - m_keyExchange->sendNewKeysPacket(m_incomingPacket, - ClientId.left(ClientId.size() - 2)); - m_sendFacility.recreateKeys(*m_keyExchange); - m_state = KeyExchangeSuccess; -} - -void SshConnectionPrivate::handleNewKeysPacket() -{ - m_incomingPacket.recreateKeys(*m_keyExchange); - m_keyExchange.reset(); - m_sendFacility.sendUserAuthServiceRequestPacket(); - m_state = UserAuthServiceRequested; -} - -void SshConnectionPrivate::handleServiceAcceptPacket() -{ - if (m_connParams.authType == SshConnectionParameters::AuthByPwd) { - m_sendFacility.sendUserAuthByPwdRequestPacket(m_connParams.uname.toUtf8(), - SshCapabilities::SshConnectionService, m_connParams.pwd.toUtf8()); - } else { - QFile privKeyFile(m_connParams.privateKeyFile); - bool couldOpen = privKeyFile.open(QIODevice::ReadOnly); - QByteArray contents; - if (couldOpen) - contents = privKeyFile.readAll(); - if (!couldOpen || privKeyFile.error() != QFile::NoError) { - throw SshClientException(SshKeyFileError, - tr("Could not read private key file: %1") - .arg(privKeyFile.errorString())); - } - - m_sendFacility.createAuthenticationKey(contents); - m_sendFacility.sendUserAuthByKeyRequestPacket(m_connParams.uname.toUtf8(), - SshCapabilities::SshConnectionService); - } - m_state = UserAuthRequested; -} - -void SshConnectionPrivate::handlePasswordExpiredPacket() -{ - if (m_connParams.authType == SshConnectionParameters::AuthByKey) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Got SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, but did not use password."); - } - - throw SshClientException(SshAuthenticationError, tr("Password expired.")); -} - -void SshConnectionPrivate::handleUserAuthBannerPacket() -{ - emit dataAvailable(m_incomingPacket.extractUserAuthBanner().message); -} - -void SshConnectionPrivate::handleGlobalRequest() -{ - m_sendFacility.sendRequestFailurePacket(); -} - -void SshConnectionPrivate::handleUserAuthSuccessPacket() -{ - m_state = ConnectionEstablished; - m_timeoutTimer.stop(); - emit connected(); - m_lastInvalidMsgSeqNr = InvalidSeqNr; - connect(&m_keepAliveTimer, SIGNAL(timeout()), SLOT(sendKeepAlivePacket())); - m_keepAliveTimer.start(); -} - -void SshConnectionPrivate::handleUserAuthFailurePacket() -{ - m_timeoutTimer.stop(); - const QString errorMsg = m_connParams.authType == SshConnectionParameters::AuthByPwd - ? tr("Server rejected password.") : tr("Server rejected key."); - throw SshClientException(SshAuthenticationError, errorMsg); -} -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.")); - } - 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); -} - -void SshConnectionPrivate::handleChannelData() -{ - m_channelManager->handleChannelData(m_incomingPacket); -} - -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::sendData(const QByteArray &data) -{ - if (canUseSocket()) - m_socket->write(data); -} - -void SshConnectionPrivate::handleSocketDisconnected() -{ - closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshClosedByServerError, - "Connection closed unexpectedly.", - tr("Connection closed unexpectedly.")); -} - -void SshConnectionPrivate::handleSocketError() -{ - if (m_error == SshNoError) { - closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshSocketError, - "Network error", m_socket->errorString()); - } -} - -void SshConnectionPrivate::handleTimeout() -{ - closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshTimeoutError, "", - tr("Timeout waiting for reply from server.")); -} - -void SshConnectionPrivate::sendKeepAlivePacket() -{ - Q_ASSERT(m_lastInvalidMsgSeqNr == InvalidSeqNr); - m_lastInvalidMsgSeqNr = m_sendFacility.nextClientSeqNr(); - m_sendFacility.sendInvalidPacket(); - m_timeoutTimer.start(5000); -} - -void SshConnectionPrivate::connectToHost(const SshConnectionParameters &serverInfo) -{ - m_incomingData.clear(); - m_incomingPacket.reset(); - m_sendFacility.reset(); - m_error = SshNoError; - m_ignoreNextPacket = false; - m_errorString.clear(); - connect(m_socket, SIGNAL(connected()), this, SLOT(handleSocketConnected())); - connect(m_socket, SIGNAL(readyRead()), this, SLOT(handleIncomingData())); - connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, - SLOT(handleSocketError())); - connect(m_socket, SIGNAL(disconnected()), this, - SLOT(handleSocketDisconnected())); - connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(handleTimeout())); - this->m_connParams = serverInfo; - m_state = SocketConnecting; - m_timeoutTimer.start(m_connParams.timeout * 1000); - m_socket->setProxy(m_connParams.proxyType == SshConnectionParameters::DefaultProxy - ? QNetworkProxy::DefaultProxy : QNetworkProxy::NoProxy); - m_socket->connectToHost(serverInfo.host, serverInfo.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) - 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); - try { - m_channelManager->closeAllChannels(); - m_sendFacility.sendDisconnectPacket(sshError, serverErrorString); - } catch (Botan::Exception &) {} // 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; -} - -bool SshConnectionPrivate::canUseSocket() const -{ - return m_socket->isValid() - && m_socket->state() == QAbstractSocket::ConnectedState; -} - -QSharedPointer SshConnectionPrivate::createRemoteProcess(const QByteArray &command) -{ - return m_channelManager->createRemoteProcess(command); -} - -QSharedPointer SshConnectionPrivate::createSftpChannel() -{ - return m_channelManager->createSftpChannel(); -} - -const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast(-1); - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshconnection.h b/src/plugins/coreplugin/ssh/sshconnection.h deleted file mode 100644 index d61517b41b..0000000000 --- a/src/plugins/coreplugin/ssh/sshconnection.h +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHCONNECTION_H -#define SSHCONNECTION_H - -#include "ssherrors.h" - -#include - -#include -#include -#include -#include - -namespace Core { -class SftpChannel; -class SshRemoteProcess; - -namespace Internal { -class SshConnectionPrivate; -} // namespace Internal - -struct CORE_EXPORT SshConnectionParameters -{ - enum ProxyType { DefaultProxy, NoProxy }; - SshConnectionParameters(ProxyType proxyType); - - QString host; - QString uname; - QString pwd; - QString privateKeyFile; - int timeout; - enum AuthType { AuthByPwd, AuthByKey } authType; - quint16 port; - ProxyType proxyType; -}; - -CORE_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2); -CORE_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2); - -/* - * This class provides an SSH connection, implementing protocol version 2.0 - * It can spawn channels for remote execution and SFTP operations (version 3). - * It operates asynchronously (non-blocking) and is not thread-safe. - */ -class CORE_EXPORT SshConnection : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(SshConnection) -public: - enum State { Unconnected, Connecting, Connected }; - typedef QSharedPointer Ptr; - - static Ptr create(); - - void connectToHost(const SshConnectionParameters &serverInfo); - void disconnectFromHost(); - State state() const; - SshError errorState() const; - QString errorString() const; - SshConnectionParameters connectionParameters() const; - ~SshConnection(); - - QSharedPointer createRemoteProcess(const QByteArray &command); - QSharedPointer createSftpChannel(); - -signals: - void connected(); - void disconnected(); - void dataAvailable(const QString &message); - void error(Core::SshError); - -private: - SshConnection(); - - Internal::SshConnectionPrivate *d; -}; - -} // namespace Internal - -#endif // SSHCONNECTION_H diff --git a/src/plugins/coreplugin/ssh/sshconnection_p.h b/src/plugins/coreplugin/ssh/sshconnection_p.h deleted file mode 100644 index 9a89d99a78..0000000000 --- a/src/plugins/coreplugin/ssh/sshconnection_p.h +++ /dev/null @@ -1,168 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHCONNECTION_P_H -#define SSHCONNECTION_P_H - -#include "sshconnection.h" -#include "sshexception_p.h" -#include "sshincomingpacket_p.h" -#include "sshremoteprocess.h" -#include "sshsendfacility_p.h" - -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QTcpSocket; -QT_END_NAMESPACE - -namespace Botan { class Exception; } - -namespace Core { -class SftpChannel; - -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 - KeyExchangeStarted, // After server's KEXINIT message - KeyExchangeSuccess, // After server's DH_REPLY message - UserAuthServiceRequested, - UserAuthRequested, - - ConnectionEstablished // After service has been started - // ... -}; - -class SshConnectionPrivate : public QObject -{ - Q_OBJECT - friend class Core::SshConnection; -public: - SshConnectionPrivate(SshConnection *conn); - ~SshConnectionPrivate(); - - void connectToHost(const SshConnectionParameters &serverInfo); - void closeConnection(SshErrorCode sshError, SshError userError, - const QByteArray &serverErrorString, const QString &userErrorString); - QSharedPointer createRemoteProcess(const QByteArray &command); - QSharedPointer createSftpChannel(); - SshStateInternal state() const { return m_state; } - SshError error() const { return m_error; } - QString errorString() const { return m_errorString; } - -signals: - void connected(); - void disconnected(); - void dataAvailable(const QString &message); - void error(Core::SshError); - -private: - Q_SLOT void handleSocketConnected(); - Q_SLOT void handleIncomingData(); - Q_SLOT void handleSocketError(); - Q_SLOT void handleSocketDisconnected(); - Q_SLOT void handleTimeout(); - Q_SLOT void sendKeepAlivePacket(); - - void handleServerId(); - void handlePackets(); - void handleCurrentPacket(); - void handleKeyExchangeInitPacket(); - void handleKeyExchangeReplyPacket(); - void handleNewKeysPacket(); - void handleServiceAcceptPacket(); - void handlePasswordExpiredPacket(); - void handleUserAuthSuccessPacket(); - void handleUserAuthFailurePacket(); - void handleUserAuthBannerPacket(); - 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(); - bool canUseSocket() const; - - void sendData(const QByteArray &data); - - typedef void (SshConnectionPrivate::*PacketHandler)(); - typedef QList StateList; - void setupPacketHandlers(); - void setupPacketHandler(SshPacketType type, const StateList &states, - PacketHandler handler); - - typedef QPair HandlerInStates; - QHash m_packetHandlers; - - static const quint64 InvalidSeqNr; - - QTcpSocket *m_socket; - SshStateInternal m_state; - SshIncomingPacket m_incomingPacket; - SshSendFacility m_sendFacility; - SshChannelManager * const m_channelManager; - SshConnectionParameters m_connParams; - QByteArray m_incomingData; - SshError m_error; - QString m_errorString; - QScopedPointer m_keyExchange; - QTimer m_timeoutTimer; - QTimer m_keepAliveTimer; - bool m_ignoreNextPacket; - SshConnection *m_conn; - quint64 m_lastInvalidMsgSeqNr; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHCONNECTION_P_H diff --git a/src/plugins/coreplugin/ssh/sshcryptofacility.cpp b/src/plugins/coreplugin/ssh/sshcryptofacility.cpp deleted file mode 100644 index 5f6bb69ed3..0000000000 --- a/src/plugins/coreplugin/ssh/sshcryptofacility.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshcryptofacility_p.h" - -#include "sshbotanconversions_p.h" -#include "sshcapabilities_p.h" -#include "sshexception_p.h" -#include "sshkeyexchange_p.h" -#include "sshpacket_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -using namespace Botan; - -namespace Core { -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); -} - -void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex) -{ - checkInvariant(); - - if (m_sessionId.isEmpty()) - m_sessionId = kex.h(); - Algorithm_Factory &af = global_state().algorithm_factory(); - const std::string &cryptAlgo = botanCryptAlgoName(cryptAlgoName(kex)); - BlockCipher * const cipher = af.prototype_block_cipher(cryptAlgo)->clone(); - - m_cipherBlockSize = cipher->BLOCK_SIZE; - const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize); - const InitializationVector iv(convertByteArray(ivData), m_cipherBlockSize); - - const quint32 keySize = max_keylength_of(cryptAlgo); - const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize); - SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize); - - BlockCipherMode * const cipherMode - = makeCipherMode(cipher, new Null_Padding, 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()); - const HashFunction * const hMacProto - = af.prototype_hash_function(botanHMacAlgoName(hMacAlgoName(kex))); - m_hMac.reset(new HMAC(hMacProto->clone())); - m_hMac->set_key(hMacKey); -} - -void SshAbstractCryptoFacility::convert(QByteArray &data, quint32 offset, - quint32 dataSize) const -{ - Q_ASSERT(offset + dataSize <= static_cast(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(data.constData()) + offset, - dataSize); - quint32 bytesRead = m_pipe->read(reinterpret_cast(data.data()) + offset, - dataSize, m_pipe->message_count() - 1); // Can't use Pipe::LAST_MESSAGE because of a VC bug. - Q_ASSERT(bytesRead == dataSize); -} - -QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data, - quint32 dataSize) const -{ - return m_sessionId.isEmpty() - ? QByteArray() - : convertByteArray(m_hMac->process(reinterpret_cast(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 key - = kex.hash()->process(convertByteArray(data), data.size()); - while (key.size() < length) { - SecureVector tmpKey; - tmpKey.append(convertByteArray(k), k.size()); - tmpKey.append(convertByteArray(h), h.size()); - tmpKey.append(key); - key.append(kex.hash()->process(tmpKey)); - } - return QByteArray(reinterpret_cast(key.begin()), 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-----"); - -QByteArray SshEncryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const -{ - return kex.encryptionAlgo(); -} - -QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const -{ - return kex.hMacAlgoClientToServer(); -} - -BlockCipherMode *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, - BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv, - const SymmetricKey &key) -{ - return new CBC_Encryption(cipher, paddingMethod, key, iv); -} - -void SshEncryptionFacility::encrypt(QByteArray &data) const -{ - convert(data, 0, data.size()); -} - -void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFileContents) -{ - if (privKeyFileContents == m_cachedPrivKeyContents) - return; - -#ifdef CREATOR_SSH_DEBUG - qDebug("%s: Key not cached, reading", Q_FUNC_INFO); -#endif - QList pubKeyParams; - QList allKeyParams; - try { - createAuthenticationKeyFromPKCS8(privKeyFileContents, pubKeyParams, - allKeyParams); - } catch (Botan::Exception &) { - createAuthenticationKeyFromOpenSSL(privKeyFileContents, pubKeyParams, - allKeyParams); - } - - foreach (const BigInt &b, allKeyParams) { - if (b.is_zero()) { - throw SshClientException(SshKeyFileError, - SSH_TR("Decoding of private key file failed.")); - } - } - - m_authPubKeyBlob = AbstractSshPacket::encodeString(m_authKeyAlgoName); - foreach (const BigInt &b, pubKeyParams) - m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b); - m_cachedPrivKeyContents = privKeyFileContents; -} - -void SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, - QList &pubKeyParams, QList &allKeyParams) -{ - Pipe pipe; - pipe.process_msg(convertByteArray(privKeyFileContents), - privKeyFileContents.size()); - Private_Key * const key = PKCS8::load_key(pipe, m_rng); - if (DSA_PrivateKey * const dsaKey = dynamic_cast(key)) { - m_authKey.reset(dsaKey); - pubKeyParams << dsaKey->group_p() << dsaKey->group_q() - << dsaKey->group_g() << dsaKey->get_y(); - allKeyParams << pubKeyParams << dsaKey->get_x(); - } else if (RSA_PrivateKey * const rsaKey = dynamic_cast(key)) { - m_authKey.reset(rsaKey); - pubKeyParams << rsaKey->get_e() << rsaKey->get_n(); - allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q() - << rsaKey->get_d(); - } else { - throw Botan::Exception(); - } -} - -void SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, - QList &pubKeyParams, QList &allKeyParams) -{ - bool syntaxOk = true; - QList 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 { - syntaxOk = false; - } - if (!syntaxOk) { - throw SshClientException(SshKeyFileError, - SSH_TR("Private key file has unexpected format.")); - } - - 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); - quint32 version; - sequence.decode (version); - if (version != 0) { - throw SshClientException(SshKeyFileError, - SSH_TR("Private key encoding has version %1, expected 0.") - .arg(version)); - } - - 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 { - BigInt p, q, e, d, n; - sequence.decode (n).decode (e).decode (d).decode (p).decode (q); - RSA_PrivateKey * const rsaKey - = new RSA_PrivateKey (m_rng, p, q, e, d, n); - m_authKey.reset(rsaKey); - pubKeyParams << e << n; - allKeyParams << pubKeyParams << p << q << d; - } - - sequence.discard_remaining(); - sequence.verify_end(); -} - -QByteArray SshEncryptionFacility::authenticationAlgorithmName() const -{ - Q_ASSERT(m_authKey); - return m_authKeyAlgoName; -} - -QByteArray SshEncryptionFacility::authenticationKeySignature(const QByteArray &data) const -{ - Q_ASSERT(m_authKey); - - QScopedPointer signer(get_pk_signer (*m_authKey, - botanEmsaAlgoName(m_authKeyAlgoName))); - QByteArray dataToSign = AbstractSshPacket::encodeString(sessionId()) + data; - QByteArray signature - = convertByteArray(signer->sign_message(convertByteArray(dataToSign), - dataToSign.size(), m_rng)); - 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(); -} - -BlockCipherMode *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, - BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv, - const SymmetricKey &key) -{ - return new CBC_Decryption(cipher, paddingMethod, key, iv); -} - -void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset, - quint32 dataSize) const -{ - convert(data, offset, dataSize); -#ifdef CREATOR_SSH_DEBUG - qDebug("Decrypted data:"); - const char * const start = data.constData() + offset; - const char * const end = start + dataSize; - for (const char *c = start; c < end; ++c) - qDebug() << "'" << *c << "' (0x" << (static_cast(*c) & 0xff) << ")"; -#endif -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshcryptofacility_p.h b/src/plugins/coreplugin/ssh/sshcryptofacility_p.h deleted file mode 100644 index 92bca5d992..0000000000 --- a/src/plugins/coreplugin/ssh/sshcryptofacility_p.h +++ /dev/null @@ -1,158 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHABSTRACTCRYPTOFACILITY_P_H -#define SSHABSTRACTCRYPTOFACILITY_P_H - -#include -#include - -#include -#include - -namespace Botan { - class BigInt; - class BlockCipher; - class BlockCipherMode; - class BlockCipherModePaddingMethod; - class HashFunction; - class HMAC; - class Pipe; - class PK_Signing_Key; -} - -namespace Core { -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; } - -protected: - SshAbstractCryptoFacility(); - void convert(QByteArray &data, quint32 offset, quint32 dataSize) const; - QByteArray sessionId() const { return m_sessionId; } - -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::BlockCipherMode *makeCipherMode(Botan::BlockCipher *cipher, - Botan::BlockCipherModePaddingMethod *paddingMethod, - 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; - - QByteArray m_sessionId; - QScopedPointer m_pipe; - QScopedPointer 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::BlockCipherMode *makeCipherMode(Botan::BlockCipher *cipher, - Botan::BlockCipherModePaddingMethod *paddingMethod, - 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'; } - - void createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, - QList &pubKeyParams, QList &allKeyParams); - void createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, - QList &pubKeyParams, QList &allKeyParams); - - static const QByteArray PrivKeyFileStartLineRsa; - static const QByteArray PrivKeyFileStartLineDsa; - static const QByteArray PrivKeyFileEndLineRsa; - static const QByteArray PrivKeyFileEndLineDsa; - - QByteArray m_authKeyAlgoName; - QByteArray m_authPubKeyBlob; - QByteArray m_cachedPrivKeyContents; - QScopedPointer 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::BlockCipherMode *makeCipherMode(Botan::BlockCipher *cipher, - Botan::BlockCipherModePaddingMethod *paddingMethod, - 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 Core - -#endif // SSHABSTRACTCRYPTOFACILITY_P_H diff --git a/src/plugins/coreplugin/ssh/ssherrors.h b/src/plugins/coreplugin/ssh/ssherrors.h deleted file mode 100644 index 21d4a42bfb..0000000000 --- a/src/plugins/coreplugin/ssh/ssherrors.h +++ /dev/null @@ -1,47 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHERRORS_P_H -#define SSHERRORS_P_H - -namespace Core { - -enum SshError { - SshNoError, SshSocketError, SshTimeoutError, SshProtocolError, - SshHostKeyError, SshKeyFileError, SshAuthenticationError, - SshClosedByServerError, SshInternalError -}; - -} // namespace Core - -#endif // SSHERRORS_P_H diff --git a/src/plugins/coreplugin/ssh/sshexception_p.h b/src/plugins/coreplugin/ssh/sshexception_p.h deleted file mode 100644 index c634c2f223..0000000000 --- a/src/plugins/coreplugin/ssh/sshexception_p.h +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHEXCEPTION_P_H -#define SSHEXCEPTION_P_H - -#include "ssherrors.h" - -#include -#include -#include - -namespace Core { -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 -{ - SshServerException(SshErrorCode error, const QByteArray &errorStringServer, - const QString &errorStringUser) - : error(error), errorStringServer(errorStringServer), - errorStringUser(errorStringUser) {} - - const SshErrorCode error; - const QByteArray errorStringServer; - const QString errorStringUser; -}; - -struct SshClientException -{ - SshClientException(SshError error, const QString &errorString) - : error(error), errorString(errorString) {} - - const SshError error; - const QString errorString; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHEXCEPTION_P_H diff --git a/src/plugins/coreplugin/ssh/sshincomingpacket.cpp b/src/plugins/coreplugin/ssh/sshincomingpacket.cpp deleted file mode 100644 index 2e8bec0d4c..0000000000 --- a/src/plugins/coreplugin/ssh/sshincomingpacket.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshincomingpacket_p.h" - -#include "sshcapabilities_p.h" - -namespace Core { -namespace Internal { - -const QByteArray SshIncomingPacket::ExitStatusType("exit-status"); -const QByteArray SshIncomingPacket::ExitSignalType("exit-signal"); - -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) -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("%s: current data size = %d, new data size = %d", - Q_FUNC_INFO, m_data.size(), newData.size()); -#endif - - 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(minSize - currentDataSize(), newData.size()); - moveFirstBytes(m_data, newData, bytesToTake); -#ifdef CREATOR_SSH_DEBUG - qDebug("Took %d bytes from new data", bytesToTake); -#endif - if (currentDataSize() < minSize) - return; - } - - const int bytesToTake - = qMin(length() + 4 + macLength() - currentDataSize(), - newData.size()); - moveFirstBytes(m_data, newData, bytesToTake); -#ifdef CREATOR_SSH_DEBUG - qDebug("Took %d bytes from new data", bytesToTake); -#endif - if (isComplete()) { -#ifdef CREATOR_SSH_DEBUG - qDebug("Message complete. Overall size: %u, payload size: %u", - m_data.size(), m_length - paddingLength() - 1); -#endif - 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 (SshPacketParseException &) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - "Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet."); - } - return exchangeData; -} - -SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &pubKeyAlgo) const -{ - Q_ASSERT(isComplete()); - Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY); - - try { - SshKeyExchangeReply replyData; - quint32 offset = TypeOffset + 1; - const quint32 k_sLength - = SshPacketParser::asUint32(m_data, &offset); - if (offset + k_sLength > currentDataSize()) - throw SshPacketParseException(); - replyData.k_s = m_data.mid(offset - 4, k_sLength + 4); - if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) - throw SshPacketParseException(); - - // DSS: p and q, RSA: e and n - replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); - replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); - - // g and y - if (pubKeyAlgo == SshCapabilities::PubKeyDss) { - replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); - replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); - } - - replyData.f = SshPacketParser::asBigInt(m_data, &offset); - offset += 4; - if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) - throw SshPacketParseException(); - replyData.signatureBlob = SshPacketParser::asString(m_data, &offset); - return replyData; - } catch (SshPacketParseException &) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - "Key exchange failed: " - "Server sent invalid SSH_MSG_KEXDH_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 (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 (SshPacketParseException &) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid SSH_MSG_USERAUTH_BANNER."); - } -} - -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 (SshPacketParseException &) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid SSH_MSG_DEBUG."); - } -} - -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 (SshPacketParseException &) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid SSH_MSG_UNIMPLEMENTED."); - } -} - -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 = SshPacketParser::asString(m_data, &offset); - openFailure.language = SshPacketParser::asString(m_data, &offset); - } catch (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 (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 (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 (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 (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); - if (SshPacketParser::asBool(m_data, &offset)) - throw SshPacketParseException(); - exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset); - } catch (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); - 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 (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 (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 (SshPacketParseException &) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, - "Invalid SSH_MSG_CHANNEL_REQUEST packet."); - } -} - -void SshIncomingPacket::calculateLength() const -{ - Q_ASSERT(currentDataSize() >= minPacketSize()); -#ifdef CREATOR_SSH_DEBUG - qDebug("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); -#endif - m_decrypter.decrypt(m_data, 0, cipherBlockSize()); -#ifdef CREATOR_SSH_DEBUG - qDebug("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); - qDebug("message type = %d", m_data.at(TypeOffset)); -#endif - m_length = SshPacketParser::asUint32(m_data, static_cast(0)); -#ifdef CREATOR_SSH_DEBUG - qDebug("decrypted length is %u", m_length); -#endif -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshincomingpacket_p.h b/src/plugins/coreplugin/ssh/sshincomingpacket_p.h deleted file mode 100644 index 6c8ce46d84..0000000000 --- a/src/plugins/coreplugin/ssh/sshincomingpacket_p.h +++ /dev/null @@ -1,196 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHINCOMINGPACKET_P_H -#define SSHINCOMINGPACKET_P_H - -#include "sshpacket_p.h" - -#include "sshcryptofacility_p.h" -#include "sshpacketparser_p.h" - -#include -#include - -namespace Core { -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 parameters; // DSS: p, q, g, y. RSA: e, n. - Botan::BigInt f; - QByteArray signatureBlob; -}; - -struct SshDisconnect -{ - quint32 reasonCode; - QString description; - QByteArray language; -}; - -struct SshUserAuthBanner -{ - QString message; - QByteArray language; -}; - -struct SshDebug -{ - bool display; - QString message; - QByteArray language; -}; - -struct SshUnimplemented -{ - quint32 invalidMsgSeqNr; -}; - -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 &pubKeyAlgo) const; - SshDisconnect extractDisconnect() const; - SshUserAuthBanner extractUserAuthBanner() const; - SshDebug extractDebug() const; - SshUnimplemented extractUnimplemented() const; - - 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; - -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 Core - -#endif // SSHINCOMINGPACKET_P_H diff --git a/src/plugins/coreplugin/ssh/sshkeyexchange.cpp b/src/plugins/coreplugin/ssh/sshkeyexchange.cpp deleted file mode 100644 index bb3e2a2896..0000000000 --- a/src/plugins/coreplugin/ssh/sshkeyexchange.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshkeyexchange_p.h" - -#include "sshbotanconversions_p.h" -#include "sshcapabilities_p.h" -#include "sshsendfacility_p.h" -#include "sshexception_p.h" -#include "sshincomingpacket_p.h" - -#include -#include -#include -#include -#include - -#include - -using namespace Botan; - -namespace Core { -namespace Internal { - -namespace { - - // For debugging - void printNameList(const char *listName, const SshNameList &list) - { -#ifdef CREATOR_SSH_DEBUG - qDebug("%s:", listName); - foreach (const QByteArray &name, list.names) - qDebug("%s", name.constData()); -#else - Q_UNUSED(listName); - Q_UNUSED(list); -#endif - } -} // anonymous namespace - -SshKeyExchange::SshKeyExchange(SshSendFacility &sendFacility) - : m_sendFacility(sendFacility) -{ -} - -SshKeyExchange::~SshKeyExchange() {} - -void SshKeyExchange::sendKexInitPacket(const QByteArray &serverId) -{ - m_serverId = serverId; - const AbstractSshPacket::Payload &payload - = m_sendFacility.sendKeyExchangeInitPacket(); - m_clientKexInitPayload = QByteArray(payload.data, payload.size); -} - -bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit) -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("server requests key exchange"); -#endif - 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); -#ifdef CREATOR_SSH_DEBUG - qDebug("First packet follows: %d", kexInitParams.firstKexPacketFollows); -#endif - - const QByteArray &keyAlgo - = SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods, - kexInitParams.keyAlgorithms.names); - m_serverHostKeyAlgo - = SshCapabilities::findBestMatch(SshCapabilities::PublicKeyAlgorithms, - kexInitParams.serverHostKeyAlgorithms.names); - m_encryptionAlgo - = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms, - kexInitParams.encryptionAlgorithmsClientToServer.names); - m_decryptionAlgo - = SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms, - kexInitParams.encryptionAlgorithmsServerToClient.names); - m_c2sHMacAlgo - = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms, - kexInitParams.macAlgorithmsClientToServer.names); - m_s2cHMacAlgo - = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms, - kexInitParams.macAlgorithmsServerToClient.names); - SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms, - kexInitParams.compressionAlgorithmsClientToServer.names); - SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms, - kexInitParams.compressionAlgorithmsServerToClient.names); - - AutoSeeded_RNG rng; - m_dhKey.reset(new DH_PrivateKey(rng, - DL_Group(botanKeyExchangeAlgoName(keyAlgo)))); - - const AbstractSshPacket::Payload &payload = serverKexInit.payLoad(); - m_serverKexInitPayload = QByteArray(payload.data, payload.size); - m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y()); - return kexInitParams.firstKexPacketFollows; -} - -void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply, - const QByteArray &clientId) -{ - const SshKeyExchangeReply &reply - = dhReply.extractKeyExchangeReply(m_serverHostKeyAlgo); - if (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; - concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y()); - concatenatedData += AbstractSshPacket::encodeMpInt(reply.f); - SymmetricKey k = m_dhKey->derive_key(reply.f); - m_k = AbstractSshPacket::encodeMpInt(BigInt(k.begin(), k.length())); - concatenatedData += m_k; - - m_hash.reset(get_hash(botanSha1Name())); - const SecureVector &hashResult - = m_hash->process(convertByteArray(concatenatedData), - concatenatedData.size()); - m_h = convertByteArray(hashResult); - - QScopedPointer sigKey; - QScopedPointer verifier; - if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) { - const DL_Group group(reply.parameters.at(0), reply.parameters.at(1), - reply.parameters.at(2)); - DSA_PublicKey * const dsaKey - = new DSA_PublicKey(group, reply.parameters.at(3)); - sigKey.reset(dsaKey); - verifier.reset(get_pk_verifier(*dsaKey, - botanEmsaAlgoName(SshCapabilities::PubKeyDss))); - } else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) { - RSA_PublicKey * const rsaKey - = new RSA_PublicKey(reply.parameters.at(1), reply.parameters.at(0)); - sigKey.reset(rsaKey); - verifier.reset(get_pk_verifier(*rsaKey, - botanEmsaAlgoName(SshCapabilities::PubKeyRsa))); - } else { - Q_ASSERT(!"Impossible: Neither DSS nor RSA!"); - } - const byte * const botanH = convertByteArray(m_h); - const Botan::byte * const botanSig - = convertByteArray(reply.signatureBlob); - if (!verifier->verify_message(botanH, m_h.size(), botanSig, - reply.signatureBlob.size())) { - throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, - "Invalid signature in SSH_MSG_KEXDH_REPLY packet."); - } - - m_sendFacility.sendNewKeysPacket(); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshkeyexchange_p.h b/src/plugins/coreplugin/ssh/sshkeyexchange_p.h deleted file mode 100644 index cdaea098d3..0000000000 --- a/src/plugins/coreplugin/ssh/sshkeyexchange_p.h +++ /dev/null @@ -1,91 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHKEYEXCHANGE_P_H -#define SSHKEYEXCHANGE_P_H - -#include - -#include -#include - -namespace Botan { class HashFunction; } - -namespace Core { -namespace Internal { - -class SshSendFacility; -class SshIncomingPacket; - -class SshKeyExchange -{ -public: - SshKeyExchange(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.data(); } - 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 m_serverId; - QByteArray m_clientKexInitPayload; - QByteArray m_serverKexInitPayload; - QScopedPointer m_dhKey; - QByteArray m_k; - QByteArray m_h; - QByteArray m_serverHostKeyAlgo; - QByteArray m_encryptionAlgo; - QByteArray m_decryptionAlgo; - QByteArray m_c2sHMacAlgo; - QByteArray m_s2cHMacAlgo; - QScopedPointer m_hash; - SshSendFacility &m_sendFacility; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHKEYEXCHANGE_P_H diff --git a/src/plugins/coreplugin/ssh/sshkeygenerator.cpp b/src/plugins/coreplugin/ssh/sshkeygenerator.cpp deleted file mode 100644 index db2bd60228..0000000000 --- a/src/plugins/coreplugin/ssh/sshkeygenerator.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshkeygenerator.h" - -#include "sshbotanconversions_p.h" -#include "sshcapabilities_p.h" -#include "sshpacket_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace Core { - -using namespace Botan; -using namespace Internal; - -SshKeyGenerator::SshKeyGenerator() - : m_type(Rsa) - , m_format(OpenSsl) -{ -} - -bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, - int keySize) -{ - m_type = type; - m_format = format; - - try { - AutoSeeded_RNG rng; - KeyPtr key; - if (m_type == Rsa) - key = KeyPtr(new RSA_PrivateKey(rng, keySize)); - else - key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, - keySize))); - return m_format == Pkcs8 - ? generatePkcs8Keys(key) : generateOpenSslKeys(key); - } catch (Botan::Exception &e) { - m_error = tr("Error generating key: %1").arg(e.what()); - return false; - } -} - -bool SshKeyGenerator::generatePkcs8Keys(const KeyPtr &key) -{ - generatePkcs8Key(key, false); - generatePkcs8Key(key, true); - return true; -} - -void SshKeyGenerator::generatePkcs8Key(const KeyPtr &key, bool privateKey) -{ - Pipe pipe; - pipe.start_msg(); - QByteArray *keyData; - if (privateKey) { - PKCS8::encode(*key, pipe); - keyData = &m_privateKey; - } else { - X509::encode(*key, pipe); - keyData = &m_publicKey; - } - pipe.end_msg(); - keyData->resize(pipe.remaining(pipe.message_count() - 1)); - pipe.read(convertByteArray(*keyData), keyData->size(), - pipe.message_count() - 1); -} - -bool SshKeyGenerator::generateOpenSslKeys(const KeyPtr &key) -{ - QList publicParams; - QList allParams; - QByteArray keyId; - if (m_type == Rsa) { - const QSharedPointer rsaKey - = key.dynamicCast(); - publicParams << rsaKey->get_e() << rsaKey->get_n(); - allParams << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() - << rsaKey->get_p() << rsaKey->get_q(); - keyId = SshCapabilities::PubKeyRsa; - } else { - const QSharedPointer dsaKey - = key.dynamicCast(); - publicParams << dsaKey->group_p() << dsaKey->group_q() - << dsaKey->group_g() << dsaKey->get_y(); - allParams << publicParams << dsaKey->get_x(); - keyId = SshCapabilities::PubKeyDss; - } - - QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId); - foreach (const BigInt &b, publicParams) - publicKeyBlob += AbstractSshPacket::encodeMpInt(b); - publicKeyBlob = publicKeyBlob.toBase64(); - const QByteArray id = "QtCreator/" - + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8(); - m_publicKey = keyId + ' ' + publicKeyBlob + ' ' + id; - - DER_Encoder encoder; - encoder.start_cons(SEQUENCE).encode (0U); - foreach (const BigInt &b, allParams) - encoder.encode(b); - encoder.end_cons(); - const char * const label - = m_type == Rsa ? "RSA PRIVATE KEY" : "DSA PRIVATE KEY"; - m_privateKey - = QByteArray(PEM_Code::encode (encoder.get_contents(), label).c_str()); - return true; -} - -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshkeygenerator.h b/src/plugins/coreplugin/ssh/sshkeygenerator.h deleted file mode 100644 index 6416ac74fc..0000000000 --- a/src/plugins/coreplugin/ssh/sshkeygenerator.h +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHKEYGENERATOR_H -#define SSHKEYGENERATOR_H - -#include - -#include -#include - -namespace Botan { - class Private_Key; -} - -namespace Core { - -class CORE_EXPORT SshKeyGenerator -{ - Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator) -public: - enum KeyType { Rsa, Dsa }; - enum PrivateKeyFormat { Pkcs8, OpenSsl }; - - SshKeyGenerator(); - bool generateKeys(KeyType type, PrivateKeyFormat format, int keySize); - QString error() const { return m_error; } - QByteArray privateKey() const { return m_privateKey; } - QByteArray publicKey() const { return m_publicKey; } - KeyType type() const { return m_type; } - PrivateKeyFormat format() const { return m_format; } - -private: - typedef QSharedPointer KeyPtr; - - bool generatePkcs8Keys(const KeyPtr &key); - void generatePkcs8Key(const KeyPtr &key, bool privateKey); - bool generateOpenSslKeys(const KeyPtr &key); - - QString m_error; - QByteArray m_publicKey; - QByteArray m_privateKey; - KeyType m_type; - PrivateKeyFormat m_format; -}; - -} // namespace Core - -#endif // SSHKEYGENERATOR_H diff --git a/src/plugins/coreplugin/ssh/sshoutgoingpacket.cpp b/src/plugins/coreplugin/ssh/sshoutgoingpacket.cpp deleted file mode 100644 index c99db71aca..0000000000 --- a/src/plugins/coreplugin/ssh/sshoutgoingpacket.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshoutgoingpacket_p.h" - -#include "sshcapabilities_p.h" -#include "sshcryptofacility_p.h" - -#include - -namespace Core { -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(); -} - -void 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()); - - 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. - finalize(); -} - -void SshOutgoingPacket::generateKeyDhInitPacket(const Botan::BigInt &e) -{ - init(SSH_MSG_KEXDH_INIT).appendMpInt(e).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::generateUserAuthByPwdRequestPacket(const QByteArray &user, - const QByteArray &service, const QByteArray &pwd) -{ - init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service) - .appendString("password").appendBool(false).appendString(pwd) - .finalize(); -} - -void SshOutgoingPacket::generateUserAuthByKeyRequestPacket(const QByteArray &user, - const QByteArray &service) -{ - init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service) - .appendString("publickey").appendBool(true) - .appendString(m_encrypter.authenticationAlgorithmName()) - .appendString(m_encrypter.authenticationPublicKey()); - const QByteArray &dataToSign = m_data.mid(PayloadOffset); - appendString(m_encrypter.authenticationKeySignature(dataToSign)); - 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::generateEnvPacket(quint32 remoteChannel, - const QByteArray &var, const QByteArray &value) -{ - init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("env") - .appendBool(false).appendString(var).appendString(value); -} - -void SshOutgoingPacket::generateExecPacket(quint32 remoteChannel, - const QByteArray &command) -{ - init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("exec") - .appendBool(true).appendString(command).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::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(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; -#ifdef CREATOR_SSH_DEBUG - qDebug("Encrypting packet of type %u", m_data.at(TypeOffset)); -#endif - encrypt(); - Q_ASSERT(isComplete()); -} - -int SshOutgoingPacket::sizeDivisor() const -{ - return qMax(cipherBlockSize(), 8U); -} - -QByteArray SshOutgoingPacket::encodeNameList(const QList &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 Core diff --git a/src/plugins/coreplugin/ssh/sshoutgoingpacket_p.h b/src/plugins/coreplugin/ssh/sshoutgoingpacket_p.h deleted file mode 100644 index da7f6fcc03..0000000000 --- a/src/plugins/coreplugin/ssh/sshoutgoingpacket_p.h +++ /dev/null @@ -1,104 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHOUTGOINGPACKET_P_H -#define SSHOUTGOINGPACKET_P_H - -#include "sshpacket_p.h" - -namespace Core { -namespace Internal { - -class SshEncryptionFacility; - -class SshOutgoingPacket : public AbstractSshPacket -{ -public: - SshOutgoingPacket(const SshEncryptionFacility &encrypter, - const quint32 &seqNr); - - void generateKeyExchangeInitPacket(); - void generateKeyDhInitPacket(const Botan::BigInt &e); - void generateNewKeysPacket(); - void generateDisconnectPacket(SshErrorCode reason, - const QByteArray &reasonString); - void generateMsgUnimplementedPacket(quint32 serverSeqNr); - void generateUserAuthServiceRequestPacket(); - void generateUserAuthByPwdRequestPacket(const QByteArray &user, - const QByteArray &service, const QByteArray &pwd); - void generateUserAuthByKeyRequestPacket(const QByteArray &user, - const QByteArray &service); - void generateRequestFailurePacket(); - void generateIgnorePacket(); - void generateInvalidMessagePacket(); - void generateSessionPacket(quint32 channelId, quint32 windowSize, - quint32 maxPacketSize); - void generateEnvPacket(quint32 remoteChannel, const QByteArray &var, - const QByteArray &value); - void generateExecPacket(quint32 remoteChannel, const QByteArray &command); - 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); - -private: - virtual quint32 cipherBlockSize() const; - virtual quint32 macLength() const; - - static QByteArray encodeNameList(const QList &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 Core - -#endif // SSHOUTGOINGPACKET_P_H diff --git a/src/plugins/coreplugin/ssh/sshpacket.cpp b/src/plugins/coreplugin/ssh/sshpacket.cpp deleted file mode 100644 index 4ddba455b4..0000000000 --- a/src/plugins/coreplugin/ssh/sshpacket.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshpacket_p.h" - -#include "sshcapabilities_p.h" -#include "sshcryptofacility_p.h" -#include "sshexception_p.h" -#include "sshpacketparser_p.h" - -#include - -#include - -namespace Core { -namespace Internal { - -const quint32 AbstractSshPacket::PaddingLengthOffset = 4; -const quint32 AbstractSshPacket::PayloadOffset = PaddingLengthOffset + 1; -const quint32 AbstractSshPacket::TypeOffset = PayloadOffset; -const quint32 AbstractSshPacket::MinPaddingLength = 4; - -namespace { - - void printByteArray(const QByteArray &data) - { -#ifdef CREATOR_SSH_DEBUG - for (int i = 0; i < data.count(); ++i) - qDebug() << std::hex << (static_cast(data[i]) & 0xff) << " "; -#else - Q_UNUSED(data); -#endif - } -} // anonymous namespace - - -AbstractSshPacket::AbstractSshPacket() : m_length(0) { } -AbstractSshPacket::~AbstractSshPacket() {} - -bool AbstractSshPacket::isComplete() const -{ - if (currentDataSize() < minPacketSize()) - return false; - Q_ASSERT(4 + length() + macLength() >= currentDataSize()); - return 4 + length() + macLength() == currentDataSize(); -} - -void AbstractSshPacket::clear() -{ - m_data.clear(); - m_length = 0; -} - -SshPacketType AbstractSshPacket::type() const -{ - Q_ASSERT(isComplete()); - return static_cast(m_data.at(TypeOffset)); -} - -AbstractSshPacket::Payload AbstractSshPacket::payLoad() const -{ - Payload p; - p.data = m_data.constData() + PayloadOffset; - p.size = length() - paddingLength() - 1; - return p; -} - -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 = 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(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(0)); -} - -QByteArray AbstractSshPacket::generateMac(const SshAbstractCryptoFacility &crypt, - quint32 seqNr) const -{ - const quint32 seqNrBe = qToBigEndian(seqNr); - QByteArray data(reinterpret_cast(&seqNrBe), sizeof seqNrBe); - data += QByteArray(m_data.constData(), length() + 4); - return crypt.generateMac(data, data.size()); -} - -quint32 AbstractSshPacket::minPacketSize() const -{ - return qMax(cipherBlockSize(), 16) + macLength(); -} - -void AbstractSshPacket::setLengthField(QByteArray &data) -{ - const quint32 length = qToBigEndian(data.size() - 4); - data.replace(0, 4, reinterpret_cast(&length), 4); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshpacket_p.h b/src/plugins/coreplugin/ssh/sshpacket_p.h deleted file mode 100644 index 1f66797a9a..0000000000 --- a/src/plugins/coreplugin/ssh/sshpacket_p.h +++ /dev/null @@ -1,146 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHPACKET_P_H -#define SSHPACKET_P_H - -#include "sshexception_p.h" - -#include -#include -#include - -#include - -namespace Core { -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_KEXDH_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_GLOBAL_REQUEST = 80, - SSH_MSG_REQUEST_SUCCESS = 81, - SSH_MSG_REQUEST_FAILURE = 82, - - 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 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 static QByteArray encodeInt(T value) - { - const T valMsb = qToBigEndian(value); - return QByteArray(reinterpret_cast(&valMsb), sizeof valMsb); - } - - static void setLengthField(QByteArray &data); - - void printRawBytes() const; // For Debugging. - - const QByteArray &rawData() const { return m_data; } - - struct Payload { const char *data; quint32 size; }; - Payload 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 Core - -#endif // SSHPACKET_P_H diff --git a/src/plugins/coreplugin/ssh/sshpacketparser.cpp b/src/plugins/coreplugin/ssh/sshpacketparser.cpp deleted file mode 100644 index 26f8ed4d59..0000000000 --- a/src/plugins/coreplugin/ssh/sshpacketparser.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshpacketparser_p.h" - -#include - -namespace Core { -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(data.at(offset) & 0xff) << 56) - + (static_cast(data.at(offset + 1) & 0xff) << 48) - + (static_cast(data.at(offset + 2) & 0xff) << 40) - + (static_cast(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) -{ - 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(data.constData() + *offset); - *offset += length; - return Botan::BigInt::decode(numberStart, length); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshpacketparser_p.h b/src/plugins/coreplugin/ssh/sshpacketparser_p.h deleted file mode 100644 index 061fd0389f..0000000000 --- a/src/plugins/coreplugin/ssh/sshpacketparser_p.h +++ /dev/null @@ -1,85 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHPACKETPARSER_P_H -#define SSHPACKETPARSER_P_H - -#include - -#include -#include -#include - -namespace Core { -namespace Internal { - -struct SshNameList -{ - SshNameList() : originalLength(0) {} - SshNameList(quint32 originalLength) : originalLength(originalLength) {} - quint32 originalLength; - QList 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 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 Core - -#endif // SSHPACKETPARSER_P_H diff --git a/src/plugins/coreplugin/ssh/sshremoteprocess.cpp b/src/plugins/coreplugin/ssh/sshremoteprocess.cpp deleted file mode 100644 index 97a4c9ebe9..0000000000 --- a/src/plugins/coreplugin/ssh/sshremoteprocess.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshremoteprocess.h" -#include "sshremoteprocess_p.h" - -#include "sshincomingpacket_p.h" -#include "sshsendfacility_p.h" - -#include - -#include - -namespace Core { - -const QByteArray SshRemoteProcess::AbrtSignal("ABRT"); -const QByteArray SshRemoteProcess::AlrmSignal("ALRM"); -const QByteArray SshRemoteProcess::FpeSignal("FPE"); -const QByteArray SshRemoteProcess::HupSignal("HUP"); -const QByteArray SshRemoteProcess::IllSignal("ILL"); -const QByteArray SshRemoteProcess::IntSignal("INT"); -const QByteArray SshRemoteProcess::KillSignal("KILL"); -const QByteArray SshRemoteProcess::PipeSignal("PIPE"); -const QByteArray SshRemoteProcess::QuitSignal("QUIT"); -const QByteArray SshRemoteProcess::SegvSignal("SEGV"); -const QByteArray SshRemoteProcess::TermSignal("TERM"); -const QByteArray SshRemoteProcess::Usr1Signal("USR1"); -const QByteArray SshRemoteProcess::Usr2Signal("USR2"); - -SshRemoteProcess::SshRemoteProcess(const QByteArray &command, quint32 channelId, - Internal::SshSendFacility &sendFacility) - : d(new Internal::SshRemoteProcessPrivate(command, channelId, sendFacility, this)) -{ - connect(d, SIGNAL(started()), this, SIGNAL(started()), - Qt::QueuedConnection); - connect(d, SIGNAL(outputAvailable(QByteArray)), this, - SIGNAL(outputAvailable(QByteArray)), Qt::QueuedConnection); - connect(d, SIGNAL(errorOutputAvailable(QByteArray)), this, - SIGNAL(errorOutputAvailable(QByteArray)), Qt::QueuedConnection); - connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)), - Qt::QueuedConnection); -} - -SshRemoteProcess::~SshRemoteProcess() -{ - Q_ASSERT(d->channelState() == Internal::SshRemoteProcessPrivate::Inactive - || d->channelState() == Internal::SshRemoteProcessPrivate::CloseRequested - || d->channelState() == Internal::SshRemoteProcessPrivate::Closed); - delete d; -} - -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::start() -{ - if (d->channelState() == Internal::SshRemoteProcessPrivate::Inactive) { -#ifdef CREATOR_SSH_DEBUG - qDebug("process start requested, channel id = %u", d->localChannelId()); -#endif - d->requestSessionStart(); - } -} - -void SshRemoteProcess::sendSignal(const QByteArray &signal) -{ - try { - if (isRunning()) - d->m_sendFacility.sendChannelSignalPacket(d->remoteChannel(), - signal); - } catch (Botan::Exception &e) { - d->setError(QString::fromAscii(e.what())); - d->closeChannel(); - } -} - -void SshRemoteProcess::closeChannel() -{ - d->closeChannel(); -} - -void SshRemoteProcess::sendInput(const QByteArray &data) -{ - if (isRunning()) - d->sendData(data); -} - -bool SshRemoteProcess::isRunning() const -{ - return d->m_procState == Internal::SshRemoteProcessPrivate::Running; -} - -QString SshRemoteProcess::errorString() const { return d->errorString(); } - -int SshRemoteProcess::exitCode() const { return d->m_exitCode; } - -QByteArray SshRemoteProcess::exitSignal() const { return d->m_signal; } - -namespace Internal { - -SshRemoteProcessPrivate::SshRemoteProcessPrivate(const QByteArray &command, - quint32 channelId, SshSendFacility &sendFacility, SshRemoteProcess *proc) - : AbstractSshChannel(channelId, sendFacility), m_procState(NotYetStarted), - m_wasRunning(false), m_exitCode(0), m_command(command), m_proc(proc) -{ -} - -void SshRemoteProcessPrivate::setProcState(ProcessState newState) -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("channel: old state = %d,new state = %d", m_procState, newState); -#endif - m_procState = newState; - if (newState == StartFailed) { - emit closed(SshRemoteProcess::FailedToStart); - } else if (newState == Running) { - m_wasRunning = true; - emit started(); - } -} - -void SshRemoteProcessPrivate::closeHook() -{ - if (m_wasRunning) { - if (!m_signal.isEmpty()) - emit closed(SshRemoteProcess::KilledBySignal); - else - emit closed(SshRemoteProcess::ExitedNormally); - } -} - -void SshRemoteProcessPrivate::handleOpenSuccessInternal() -{ - foreach (const EnvVar &envVar, m_env) { - m_sendFacility.sendEnvPacket(remoteChannel(), envVar.first, - envVar.second); - } - - m_sendFacility.sendExecPacket(remoteChannel(), m_command); - setProcState(ExecRequested); - m_timeoutTimer->start(ReplyTimeout); -} - -void SshRemoteProcessPrivate::handleOpenFailureInternal() -{ - setProcState(StartFailed); -} - -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) -{ - emit outputAvailable(data); -} - -void SshRemoteProcessPrivate::handleChannelExtendedDataInternal(quint32 type, - const QByteArray &data) -{ - if (type != SSH_EXTENDED_DATA_STDERR) - qWarning("Unknown extended data type %u", type); - else - emit errorOutputAvailable(data); -} - -void SshRemoteProcessPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus) -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("Process exiting with exit code %d", exitStatus.exitStatus); -#endif - m_exitCode = exitStatus.exitStatus; - m_procState = Exited; -} - -void SshRemoteProcessPrivate::handleExitSignal(const SshChannelExitSignal &signal) -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("Exit due to signal %s", signal.signal.data()); -#endif - setError(signal.error); - m_signal = signal.signal; - m_procState = Exited; -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshremoteprocess.h b/src/plugins/coreplugin/ssh/sshremoteprocess.h deleted file mode 100644 index 3250da56ae..0000000000 --- a/src/plugins/coreplugin/ssh/sshremoteprocess.h +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHREMOTECOMMAND_H -#define SSHREMOTECOMMAND_H - -#include - -#include -#include - -QT_BEGIN_NAMESPACE -class QByteArray; -QT_END_NAMESPACE - -namespace Core { -namespace Internal { -class SshChannelManager; -class SshRemoteProcessPrivate; -class SshSendFacility; -} // namespace Internal - - -/* - * This class implements an SSH channel for running a remote process. - * Objects are created via SshConnection::createRemoteProcess. - * The process is started via the start() member function. - * A closeChannel() function is provided, but rarely useful, because - * a) when the process ends, the channel is closed automatically, and - * b) closing a channel will not necessarily kill the remote process. - * Therefore, the only sensible use case for calling closeChannel() is to - * get rid of an SshRemoteProces object before the process is actually started. - * Note that the process does not have a terminal, so you can't use it - * for applications that require one. - */ -class CORE_EXPORT SshRemoteProcess : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(SshRemoteProcess) - - friend class Internal::SshChannelManager; - friend class Internal::SshRemoteProcessPrivate; - -public: - typedef QSharedPointer Ptr; - enum ExitStatus { FailedToStart, KilledBySignal, ExitedNormally }; - - static const QByteArray AbrtSignal; - static const QByteArray AlrmSignal; - static const QByteArray FpeSignal; - static const QByteArray HupSignal; - static const QByteArray IllSignal; - static const QByteArray IntSignal; - static const QByteArray KillSignal; - static const QByteArray PipeSignal; - static const QByteArray QuitSignal; - static const QByteArray SegvSignal; - static const QByteArray TermSignal; - static const QByteArray Usr1Signal; - static const QByteArray Usr2Signal; - - ~SshRemoteProcess(); - - /* - * 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 start(); - void closeChannel(); - - bool isRunning() const; - QString errorString() const; - int exitCode() const; - QByteArray exitSignal() const; - - // Note: This is ignored by the OpenSSH server. - void sendSignal(const QByteArray &signal); - void kill() { sendSignal(KillSignal); } - - void sendInput(const QByteArray &data); // Should usually have a trailing newline. - -signals: - void started(); - void outputAvailable(const QByteArray &output); - void errorOutputAvailable(const QByteArray &output); - - /* - * Parameter is of type ExitStatus, but we use int because of - * signal/slot awkwardness (full namespace required). - */ - void closed(int exitStatus); - -private: - SshRemoteProcess(const QByteArray &command, quint32 channelId, - Internal::SshSendFacility &sendFacility); - - Internal::SshRemoteProcessPrivate *d; -}; - -} // namespace Core - -#endif // SSHREMOTECOMMAND_H diff --git a/src/plugins/coreplugin/ssh/sshremoteprocess_p.h b/src/plugins/coreplugin/ssh/sshremoteprocess_p.h deleted file mode 100644 index 6d0af6e6a9..0000000000 --- a/src/plugins/coreplugin/ssh/sshremoteprocess_p.h +++ /dev/null @@ -1,98 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHREMOTEPROCESS_P_H -#define SSHREMOTEPROCESS_P_H - -#include "sshchannel_p.h" - -#include -#include - -namespace Core { -class SshRemoteProcess; - -namespace Internal { -class SshSendFacility; - -class SshRemoteProcessPrivate : public AbstractSshChannel -{ - Q_OBJECT - friend class Core::SshRemoteProcess; -public: - enum ProcessState { - NotYetStarted, ExecRequested, StartFailed,Running, Exited - }; - - virtual void handleChannelSuccess(); - virtual void handleChannelFailure(); - - virtual void closeHook(); - -signals: - void started(); - void outputAvailable(const QByteArray &output); - void errorOutputAvailable(const QByteArray &output); - void closed(int exitStatus); - -private: - SshRemoteProcessPrivate(const QByteArray &command, quint32 channelId, - SshSendFacility &sendFacility, SshRemoteProcess *proc); - - virtual void handleOpenSuccessInternal(); - virtual void handleOpenFailureInternal(); - 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); - - void setProcState(ProcessState newState); - - ProcessState m_procState; - bool m_wasRunning; - QByteArray m_signal; - int m_exitCode; - - const QByteArray m_command; - - typedef QPair EnvVar; - QList m_env; - - SshRemoteProcess *m_proc; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHREMOTEPROCESS_P_H diff --git a/src/plugins/coreplugin/ssh/sshremoteprocessrunner.cpp b/src/plugins/coreplugin/ssh/sshremoteprocessrunner.cpp deleted file mode 100644 index f8ded6a2c1..0000000000 --- a/src/plugins/coreplugin/ssh/sshremoteprocessrunner.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "sshremoteprocessrunner.h" - -#define ASSERT_STATE(states) assertState(states, Q_FUNC_INFO) - -namespace Core { - -class SshRemoteProcessRunnerPrivate : public QObject -{ - Q_OBJECT -public: - SshRemoteProcessRunnerPrivate(const SshConnectionParameters ¶ms, - QObject *parent); - SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection, - QObject *parent); - void run(const QByteArray &command); - QByteArray command() const { return m_command; } - - const SshConnection::Ptr m_connection; - SshRemoteProcess::Ptr m_process; - -signals: - void connectionError(Core::SshError); - void processStarted(); - void processOutputAvailable(const QByteArray &output); - void processErrorOutputAvailable(const QByteArray &output); - void processClosed(int exitStatus); - -private slots: - void handleConnected(); - void handleConnectionError(Core::SshError error); - void handleDisconnected(); - void handleProcessStarted(); - void handleProcessFinished(int exitStatus); - -private: - enum State { Inactive, Connecting, Connected, ProcessRunning }; - - void setState(State state); - void assertState(const QList &allowedStates, const char *func); - void assertState(State allowedState, const char *func); - - State m_state; - QByteArray m_command; - const SshConnectionParameters m_params; -}; - - -SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnectionParameters ¶ms, - QObject *parent) - : QObject(parent), - m_connection(SshConnection::create()), - m_state(Inactive), - m_params(params) -{ -} - -SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection, - QObject *parent) - : QObject(parent), - m_connection(connection), - m_state(Inactive), - m_params(connection->connectionParameters()) -{ -} - -void SshRemoteProcessRunnerPrivate::run(const QByteArray &command) -{ - ASSERT_STATE(Inactive); - setState(Connecting); - - m_command = command; - connect(m_connection.data(), SIGNAL(error(Core::SshError)), - SLOT(handleConnectionError(Core::SshError))); - connect(m_connection.data(), SIGNAL(disconnected()), - SLOT(handleDisconnected())); - if (m_connection->state() == SshConnection::Connected) { - handleConnected(); - } else { - connect(m_connection.data(), SIGNAL(connected()), - SLOT(handleConnected())); - m_connection->connectToHost(m_params); - } -} - -void SshRemoteProcessRunnerPrivate::handleConnected() -{ - ASSERT_STATE(Connecting); - setState(Connected); - - m_process = m_connection->createRemoteProcess(m_command); - connect(m_process.data(), SIGNAL(started()), SLOT(handleProcessStarted())); - connect(m_process.data(), SIGNAL(closed(int)), - SLOT(handleProcessFinished(int))); - connect(m_process.data(), SIGNAL(outputAvailable(QByteArray)), - SIGNAL(processOutputAvailable(QByteArray))); - connect(m_process.data(), SIGNAL(errorOutputAvailable(QByteArray)), - SIGNAL(processErrorOutputAvailable(QByteArray))); - m_process->start(); -} - -void SshRemoteProcessRunnerPrivate::handleConnectionError(Core::SshError error) -{ - handleDisconnected(); - emit connectionError(error); -} - -void SshRemoteProcessRunnerPrivate::handleDisconnected() -{ - ASSERT_STATE(QList() << Connecting << Connected << ProcessRunning); - setState(Inactive); -} - -void SshRemoteProcessRunnerPrivate::handleProcessStarted() -{ - ASSERT_STATE(Connected); - setState(ProcessRunning); - - emit processStarted(); -} - -void SshRemoteProcessRunnerPrivate::handleProcessFinished(int exitStatus) -{ - switch (exitStatus) { - case SshRemoteProcess::FailedToStart: - ASSERT_STATE(Connected); - break; - case SshRemoteProcess::KilledBySignal: - case SshRemoteProcess::ExitedNormally: - ASSERT_STATE(ProcessRunning); - break; - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible exit status."); - } - setState(Inactive); - emit processClosed(exitStatus); -} - -void SshRemoteProcessRunnerPrivate::setState(State state) -{ - if (m_state != state) { - m_state = state; - if (m_state == Inactive) { - if (m_process) - disconnect(m_process.data(), 0, this, 0); - disconnect(m_connection.data(), 0, this, 0); - } - } -} - -void SshRemoteProcessRunnerPrivate::assertState(const QList &allowedStates, - const char *func) -{ - if (!allowedStates.contains(m_state)) - qWarning("Unexpected state %d in function %s", m_state, func); -} - -void SshRemoteProcessRunnerPrivate::assertState(State allowedState, - const char *func) -{ - assertState(QList() << allowedState, func); -} - - -SshRemoteProcessRunner::Ptr SshRemoteProcessRunner::create(const SshConnectionParameters ¶ms) -{ - return SshRemoteProcessRunner::Ptr(new SshRemoteProcessRunner(params)); -} - -SshRemoteProcessRunner::Ptr SshRemoteProcessRunner::create(const SshConnection::Ptr &connection) -{ - return SshRemoteProcessRunner::Ptr(new SshRemoteProcessRunner(connection)); -} - -SshRemoteProcessRunner::SshRemoteProcessRunner(const SshConnectionParameters ¶ms) - : d(new SshRemoteProcessRunnerPrivate(params, this)) -{ - init(); -} - -SshRemoteProcessRunner::SshRemoteProcessRunner(const SshConnection::Ptr &connection) - : d(new SshRemoteProcessRunnerPrivate(connection, this)) -{ - init(); -} - -void SshRemoteProcessRunner::init() -{ - connect(d, SIGNAL(connectionError(Core::SshError)), - SIGNAL(connectionError(Core::SshError))); - connect(d, SIGNAL(processStarted()), SIGNAL(processStarted())); - connect(d, SIGNAL(processClosed(int)), SIGNAL(processClosed(int))); - connect(d, SIGNAL(processOutputAvailable(QByteArray)), - SIGNAL(processOutputAvailable(QByteArray))); - connect(d, SIGNAL(processErrorOutputAvailable(QByteArray)), - SIGNAL(processErrorOutputAvailable(QByteArray))); -} - -void SshRemoteProcessRunner::run(const QByteArray &command) -{ - d->run(command); -} - -QByteArray SshRemoteProcessRunner::command() const { return d->command(); } -SshConnection::Ptr SshRemoteProcessRunner::connection() const { return d->m_connection; } -SshRemoteProcess::Ptr SshRemoteProcessRunner::process() const { return d->m_process; } - -} // namespace Core - - -#include "sshremoteprocessrunner.moc" diff --git a/src/plugins/coreplugin/ssh/sshremoteprocessrunner.h b/src/plugins/coreplugin/ssh/sshremoteprocessrunner.h deleted file mode 100644 index c55b08aa1c..0000000000 --- a/src/plugins/coreplugin/ssh/sshremoteprocessrunner.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef SSHREMOTEPROCESSRUNNER_H -#define SSHREMOTEPROCESSRUNNER_H - -#include "sshconnection.h" -#include "sshremoteprocess.h" - -namespace Core { -class SshRemoteProcessRunnerPrivate; - -// Convenience class for running a remote process over an SSH connection. -class CORE_EXPORT SshRemoteProcessRunner : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(SshRemoteProcessRunner) -public: - typedef QSharedPointer Ptr; - - static Ptr create(const SshConnectionParameters ¶ms); - static Ptr create(const SshConnection::Ptr &connection); - - void run(const QByteArray &command); - QByteArray command() const; - - SshConnection::Ptr connection() const; - SshRemoteProcess::Ptr process() const; - -signals: - void connectionError(Core::SshError); - void processStarted(); - void processOutputAvailable(const QByteArray &output); - void processErrorOutputAvailable(const QByteArray &output); - void processClosed(int exitStatus); // values are of type SshRemoteProcess::ExitStatus - -private: - SshRemoteProcessRunner(const SshConnectionParameters ¶ms); - SshRemoteProcessRunner(const SshConnection::Ptr &connection); - void init(); - - SshRemoteProcessRunnerPrivate *d; -}; - -} // namespace Core - -#endif // SSHREMOTEPROCESSRUNNER_H diff --git a/src/plugins/coreplugin/ssh/sshsendfacility.cpp b/src/plugins/coreplugin/ssh/sshsendfacility.cpp deleted file mode 100644 index 150118fd8c..0000000000 --- a/src/plugins/coreplugin/ssh/sshsendfacility.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "sshsendfacility_p.h" - -#include "sshkeyexchange_p.h" -#include "sshoutgoingpacket_p.h" - -#include - -namespace Core { -namespace Internal { - -SshSendFacility::SshSendFacility(QTcpSocket *socket) - : m_clientSeqNr(0), m_socket(socket), - m_outgoingPacket(m_encrypter, m_clientSeqNr) -{ -} - -void SshSendFacility::sendPacket() -{ -#ifdef CREATOR_SSH_DEBUG - qDebug("Sending packet, client seq nr is %u", m_clientSeqNr); -#endif - 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); -} - -SshOutgoingPacket::Payload SshSendFacility::sendKeyExchangeInitPacket() -{ - m_outgoingPacket.generateKeyExchangeInitPacket(); - sendPacket(); - return m_outgoingPacket.payLoad(); -} - -void SshSendFacility::sendKeyDhInitPacket(const Botan::BigInt &e) -{ - m_outgoingPacket.generateKeyDhInitPacket(e); - 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::sendUserAuthByPwdRequestPacket(const QByteArray &user, - const QByteArray &service, const QByteArray &pwd) -{ - m_outgoingPacket.generateUserAuthByPwdRequestPacket(user, service, pwd); - sendPacket(); - } - -void SshSendFacility::sendUserAuthByKeyRequestPacket(const QByteArray &user, - const QByteArray &service) -{ - m_outgoingPacket.generateUserAuthByKeyRequestPacket(user, service); - 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::sendEnvPacket(quint32 remoteChannel, - const QByteArray &var, const QByteArray &value) -{ - m_outgoingPacket.generateEnvPacket(remoteChannel, var, value); - sendPacket(); -} - -void SshSendFacility::sendExecPacket(quint32 remoteChannel, - const QByteArray &command) -{ - m_outgoingPacket.generateExecPacket(remoteChannel, command); - 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(); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/ssh/sshsendfacility_p.h b/src/plugins/coreplugin/ssh/sshsendfacility_p.h deleted file mode 100644 index 366413917b..0000000000 --- a/src/plugins/coreplugin/ssh/sshsendfacility_p.h +++ /dev/null @@ -1,97 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** No Commercial Usage -** -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef SSHCONNECTIONOUTSTATE_P_H -#define SSHCONNECTIONOUTSTATE_P_H - -#include "sshcryptofacility_p.h" -#include "sshoutgoingpacket_p.h" - -QT_BEGIN_NAMESPACE -class QTcpSocket; -QT_END_NAMESPACE - - -namespace Core { -namespace Internal { -class SshKeyExchange; - -class SshSendFacility -{ -public: - SshSendFacility(QTcpSocket *socket); - void reset(); - void recreateKeys(const SshKeyExchange &keyExchange); - void createAuthenticationKey(const QByteArray &privKeyFileContents); - - SshOutgoingPacket::Payload sendKeyExchangeInitPacket(); - void sendKeyDhInitPacket(const Botan::BigInt &e); - void sendNewKeysPacket(); - void sendDisconnectPacket(SshErrorCode reason, - const QByteArray &reasonString); - void sendMsgUnimplementedPacket(quint32 serverSeqNr); - void sendUserAuthServiceRequestPacket(); - void sendUserAuthByPwdRequestPacket(const QByteArray &user, - const QByteArray &service, const QByteArray &pwd); - void sendUserAuthByKeyRequestPacket(const QByteArray &user, - const QByteArray &service); - void sendRequestFailurePacket(); - void sendIgnorePacket(); - void sendInvalidPacket(); - void sendSessionPacket(quint32 channelId, quint32 windowSize, - quint32 maxPacketSize); - void sendEnvPacket(quint32 remoteChannel, const QByteArray &var, - const QByteArray &value); - void sendExecPacket(quint32 remoteChannel, const QByteArray &command); - 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); - quint32 nextClientSeqNr() const { return m_clientSeqNr; } - -private: - void sendPacket(); - - quint32 m_clientSeqNr; - SshEncryptionFacility m_encrypter; - QTcpSocket *m_socket; - SshOutgoingPacket m_outgoingPacket; -}; - -} // namespace Internal -} // namespace Core - -#endif // SSHCONNECTIONOUTSTATE_P_H diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 263fcd3f98..3d627ad608 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1715,9 +1715,9 @@ void DebuggerPluginPrivate::startRemoteEngine() sp.connParams.pwd = dlg.password(); sp.connParams.timeout = 5; - sp.connParams.authType = SshConnectionParameters::AuthByPwd; + sp.connParams.authType = Utils::SshConnectionParameters::AuthByPwd; sp.connParams.port = 22; - sp.connParams.proxyType = SshConnectionParameters::NoProxy; + sp.connParams.proxyType = Utils::SshConnectionParameters::NoProxy; sp.executable = dlg.inferiorPath(); sp.serverStartScript = dlg.enginePath(); diff --git a/src/plugins/debugger/debuggerstartparameters.h b/src/plugins/debugger/debuggerstartparameters.h index 02fd27d8e3..2fe82d4bc0 100644 --- a/src/plugins/debugger/debuggerstartparameters.h +++ b/src/plugins/debugger/debuggerstartparameters.h @@ -37,7 +37,7 @@ #include "debugger_global.h" #include "debuggerconstants.h" -#include +#include #include #include @@ -69,7 +69,7 @@ public: qmlServerAddress(QLatin1String("127.0.0.1")), qmlServerPort(0), useServerStartScript(false), - connParams(Core::SshConnectionParameters::NoProxy), + connParams(Utils::SshConnectionParameters::NoProxy), toolChainType(ProjectExplorer::ToolChain_UNKNOWN), startMode(NoStartMode), executableUid(0), @@ -114,7 +114,7 @@ public: QByteArray remoteSourcesDir; QString remoteMountPoint; QString localMountDir; - Core::SshConnectionParameters connParams; + Utils::SshConnectionParameters connParams; QString debuggerCommand; ProjectExplorer::ToolChainType toolChainType; diff --git a/src/plugins/debugger/gdb/remotegdbprocess.cpp b/src/plugins/debugger/gdb/remotegdbprocess.cpp index 60b5ec6bd5..fe034052ff 100644 --- a/src/plugins/debugger/gdb/remotegdbprocess.cpp +++ b/src/plugins/debugger/gdb/remotegdbprocess.cpp @@ -47,7 +47,7 @@ using namespace Core; namespace Debugger { namespace Internal { -RemoteGdbProcess::RemoteGdbProcess(const Core::SshConnectionParameters &connParams, +RemoteGdbProcess::RemoteGdbProcess(const Utils::SshConnectionParameters &connParams, RemotePlainGdbAdapter *adapter, QObject *parent) : AbstractGdbProcess(parent), m_connParams(connParams), m_state(Inactive), m_adapter(adapter) @@ -91,9 +91,9 @@ void RemoteGdbProcess::realStart(const QString &cmd, const QStringList &args, m_gdbOutput.clear(); m_errorOutput.clear(); m_inputToSend.clear(); - m_conn = SshConnection::create(); + m_conn = Utils::SshConnection::create(); connect(m_conn.data(), SIGNAL(connected()), this, SLOT(handleConnected())); - connect(m_conn.data(), SIGNAL(error(Core::SshError)), this, + connect(m_conn.data(), SIGNAL(error(Utils::SshError)), this, SLOT(handleConnectionError())); m_conn->connectToHost(m_connParams); } @@ -125,7 +125,7 @@ void RemoteGdbProcess::handleFifoCreationFinished(int exitStatus) return; QTC_ASSERT(m_state == CreatingFifo, return); - if (exitStatus != SshRemoteProcess::ExitedNormally) { + if (exitStatus != Utils::SshRemoteProcess::ExitedNormally) { emitErrorExit(tr("Could not create FIFO.")); } else { setState(StartingFifoReader); @@ -167,7 +167,7 @@ void RemoteGdbProcess::handleAppOutputReaderStarted() void RemoteGdbProcess::handleAppOutputReaderFinished(int exitStatus) { - if (exitStatus != SshRemoteProcess::ExitedNormally) + if (exitStatus != Utils::SshRemoteProcess::ExitedNormally) emitErrorExit(tr("Application output reader unexpectedly finished.")); } @@ -187,15 +187,15 @@ void RemoteGdbProcess::handleGdbFinished(int exitStatus) QTC_ASSERT(m_state == RunningGdb, return); switch (exitStatus) { - case SshRemoteProcess::FailedToStart: + case Utils::SshRemoteProcess::FailedToStart: m_error = tr("Remote gdb failed to start."); setState(Inactive); emit startFailed(); break; - case SshRemoteProcess::KilledBySignal: + case Utils::SshRemoteProcess::KilledBySignal: emitErrorExit(tr("Remote gdb crashed.")); break; - case SshRemoteProcess::ExitedNormally: + case Utils::SshRemoteProcess::ExitedNormally: const int exitCode = m_gdbProc->exitCode(); setState(Inactive); emit finished(exitCode, QProcess::NormalExit); @@ -224,7 +224,7 @@ qint64 RemoteGdbProcess::write(const QByteArray &data) void RemoteGdbProcess::kill() { if (m_state == RunningGdb) { - SshRemoteProcess::Ptr killProc + Utils::SshRemoteProcess::Ptr killProc = m_conn->createRemoteProcess("pkill -SIGKILL -x gdb"); killProc->start(); } else { @@ -236,7 +236,7 @@ void RemoteGdbProcess::interruptInferior() { QTC_ASSERT(m_state == RunningGdb, return); - SshRemoteProcess::Ptr intProc + Utils::SshRemoteProcess::Ptr intProc = m_conn->createRemoteProcess("pkill -x -SIGINT gdb"); intProc->start(); } @@ -375,15 +375,15 @@ void RemoteGdbProcess::setState(State newState) if (m_state == Inactive) { if (m_gdbProc) { disconnect(m_gdbProc.data(), 0, this, 0); - m_gdbProc = SshRemoteProcess::Ptr(); + m_gdbProc = Utils::SshRemoteProcess::Ptr(); } if (m_appOutputReader) { disconnect(m_appOutputReader.data(), 0, this, 0); - m_appOutputReader = SshRemoteProcess::Ptr(); + m_appOutputReader = Utils::SshRemoteProcess::Ptr(); } if (m_fifoCreator) { disconnect(m_fifoCreator.data(), 0, this, 0); - m_fifoCreator = SshRemoteProcess::Ptr(); + m_fifoCreator = Utils::SshRemoteProcess::Ptr(); } disconnect(m_conn.data(), 0, this, 0); m_conn->disconnectFromHost(); diff --git a/src/plugins/debugger/gdb/remotegdbprocess.h b/src/plugins/debugger/gdb/remotegdbprocess.h index c1152a1e8d..adb1aef412 100644 --- a/src/plugins/debugger/gdb/remotegdbprocess.h +++ b/src/plugins/debugger/gdb/remotegdbprocess.h @@ -36,8 +36,8 @@ #include "abstractgdbprocess.h" -#include -#include +#include +#include #include #include @@ -51,7 +51,7 @@ class RemoteGdbProcess : public AbstractGdbProcess { Q_OBJECT public: - RemoteGdbProcess(const Core::SshConnectionParameters &server, + RemoteGdbProcess(const Utils::SshConnectionParameters &server, RemotePlainGdbAdapter *adapter, QObject *parent = 0); virtual QByteArray readAllStandardOutput(); @@ -106,11 +106,11 @@ private: void emitErrorExit(const QString &error); void setState(State newState); - Core::SshConnectionParameters m_connParams; - Core::SshConnection::Ptr m_conn; - Core::SshRemoteProcess::Ptr m_gdbProc; - Core::SshRemoteProcess::Ptr m_appOutputReader; - Core::SshRemoteProcess::Ptr m_fifoCreator; + Utils::SshConnectionParameters m_connParams; + Utils::SshConnection::Ptr m_conn; + Utils::SshRemoteProcess::Ptr m_gdbProc; + Utils::SshRemoteProcess::Ptr m_appOutputReader; + Utils::SshRemoteProcess::Ptr m_fifoCreator; QByteArray m_gdbOutput; QByteArray m_errorOutput; QString m_command; diff --git a/src/plugins/debugger/lldb/lldbenginehost.cpp b/src/plugins/debugger/lldb/lldbenginehost.cpp index fa4f3fb064..03af9d30a5 100644 --- a/src/plugins/debugger/lldb/lldbenginehost.cpp +++ b/src/plugins/debugger/lldb/lldbenginehost.cpp @@ -65,7 +65,7 @@ namespace Debugger { namespace Internal { -SshIODevice::SshIODevice(Core::SshRemoteProcessRunner::Ptr r) +SshIODevice::SshIODevice(Utils::SshRemoteProcessRunner::Ptr r) : runner(r) , buckethead(0) { @@ -147,10 +147,10 @@ LldbEngineHost::LldbEngineHost(const DebuggerStartParameters &startParameters) if (startParameters.startMode == StartRemoteEngine) { m_guestProcess = 0; - Core::SshRemoteProcessRunner::Ptr runner = - Core::SshRemoteProcessRunner::create(startParameters.connParams); - connect (runner.data(), SIGNAL(connectionError(Core::SshError)), - this, SLOT(sshConnectionError(Core::SshError))); + Utils::SshRemoteProcessRunner::Ptr runner = + Utils::SshRemoteProcessRunner::create(startParameters.connParams); + connect (runner.data(), SIGNAL(connectionError(Utils::SshError)), + this, SLOT(sshConnectionError(Utils::SshError))); runner->run(startParameters.serverStartScript.toUtf8()); setGuestDevice(new SshIODevice(runner)); } else { @@ -210,7 +210,7 @@ void LldbEngineHost::nuke() m_guestProcess->kill(); notifyEngineSpontaneousShutdown(); } -void LldbEngineHost::sshConnectionError(Core::SshError e) +void LldbEngineHost::sshConnectionError(Utils::SshError e) { showStatusMessage(tr("ssh connection error: %1").arg(e)); } diff --git a/src/plugins/debugger/lldb/lldbenginehost.h b/src/plugins/debugger/lldb/lldbenginehost.h index 3b81b2dd60..5adced6d93 100644 --- a/src/plugins/debugger/lldb/lldbenginehost.h +++ b/src/plugins/debugger/lldb/lldbenginehost.h @@ -35,10 +35,10 @@ #define DEBUGGER_LLDBENGINE_HOST_H #include "ipcenginehost.h" -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -50,7 +50,7 @@ class SshIODevice : public QIODevice { Q_OBJECT public: - SshIODevice(Core::SshRemoteProcessRunner::Ptr r); + SshIODevice(Utils::SshRemoteProcessRunner::Ptr r); virtual qint64 bytesAvailable () const; virtual qint64 writeData (const char * data, qint64 maxSize); virtual qint64 readData (char * data, qint64 maxSize); @@ -59,8 +59,8 @@ private slots: void outputAvailable(const QByteArray &output); void errorOutputAvailable(const QByteArray &output); private: - Core::SshRemoteProcessRunner::Ptr runner; - Core::SshRemoteProcess::Ptr proc; + Utils::SshRemoteProcessRunner::Ptr runner; + Utils::SshRemoteProcess::Ptr proc; int buckethead; QQueue buckets; QByteArray startupbuffer; @@ -76,11 +76,11 @@ public: private: QProcess *m_guestProcess; - Core::SshRemoteProcessRunner::Ptr m_ssh; + Utils::SshRemoteProcessRunner::Ptr m_ssh; protected: void nuke(); private slots: - void sshConnectionError(Core::SshError); + void sshConnectionError(Utils::SshError); void finished(int, QProcess::ExitStatus); void stderrReady(); }; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp index 01dd025f71..a072e536a9 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.cpp @@ -39,12 +39,12 @@ #include "maemoglobal.h" #include "maemousedportsgatherer.h" -#include +#include #include #include -using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -87,7 +87,7 @@ void MaemoConfigTestDialog::startConfigTest() m_ui->testResultEdit->setPlainText(testingText); m_closeButton->setText(tr("Stop Test")); m_testProcessRunner = SshRemoteProcessRunner::create(m_config->sshParameters()); - connect(m_testProcessRunner.data(), SIGNAL(connectionError(Core::SshError)), + connect(m_testProcessRunner.data(), SIGNAL(connectionError(Utils::SshError)), this, SLOT(handleConnectionError())); connect(m_testProcessRunner.data(), SIGNAL(processClosed(int)), this, SLOT(handleTestProcessFinished(int))); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.h b/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.h index 668ff492bd..a9c56d8004 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoconfigtestdialog.h @@ -43,9 +43,9 @@ class QPushButton; class Ui_MaemoConfigTestDialog; QT_END_NAMESPACE -namespace Core { +namespace Utils { class SshRemoteProcessRunner; -} // namespace Core +} // namespace Utils namespace Qt4ProjectManager { namespace Internal { @@ -83,7 +83,7 @@ private: QPushButton *m_closeButton; const QSharedPointer m_config; - QSharedPointer m_testProcessRunner; + QSharedPointer m_testProcessRunner; QString m_deviceTestOutput; bool m_qtVersionOk; MaemoUsedPortsGatherer *const m_portsGatherer; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp index 9ac94b2bdd..16586e5fdd 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.cpp @@ -41,7 +41,7 @@ #include "maemousedportsgatherer.h" #include "qt4maemotarget.h" -#include +#include #include #include #include @@ -54,7 +54,7 @@ #define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state) -using namespace Core; +using namespace Utils; using namespace Debugger; using namespace ProjectExplorer; @@ -205,8 +205,8 @@ void MaemoDebugSupport::startExecution() SLOT(handleSftpChannelInitialized())); connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), this, SLOT(handleSftpChannelInitializationFailed(QString))); - connect(m_uploader.data(), SIGNAL(finished(Core::SftpJobId, QString)), - this, SLOT(handleSftpJobFinished(Core::SftpJobId, QString))); + connect(m_uploader.data(), SIGNAL(finished(Utils::SftpJobId, QString)), + this, SLOT(handleSftpJobFinished(Utils::SftpJobId, QString))); m_uploader->initialize(); } else { setState(DumpersUploaded); @@ -244,7 +244,7 @@ void MaemoDebugSupport::handleSftpChannelInitializationFailed(const QString &err handleAdapterSetupFailed(error); } -void MaemoDebugSupport::handleSftpJobFinished(Core::SftpJobId job, +void MaemoDebugSupport::handleSftpJobFinished(Utils::SftpJobId job, const QString &error) { if (m_state == Inactive) diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h index 775f9b9400..a7051989d0 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodebugsupport.h @@ -37,7 +37,7 @@ #include "maemorunconfiguration.h" -#include +#include #include #include @@ -77,7 +77,7 @@ private slots: void startExecution(); void handleSftpChannelInitialized(); void handleSftpChannelInitializationFailed(const QString &error); - void handleSftpJobFinished(Core::SftpJobId job, const QString &error); + void handleSftpJobFinished(Utils::SftpJobId job, const QString &error); void handleDebuggingFinished(); void handleRemoteOutput(const QByteArray &output); void handleRemoteErrorOutput(const QByteArray &output); @@ -106,8 +106,8 @@ private: const QString m_dumperLib; const QList m_userEnvChanges; - QSharedPointer m_uploader; - Core::SftpJobId m_uploadJob; + QSharedPointer m_uploader; + Utils::SftpJobId m_uploadJob; QByteArray m_gdbserverOutput; State m_state; int m_gdbServerPort; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.cpp index af4a34ac68..725f2d38bd 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.cpp @@ -45,9 +45,9 @@ #include "maemousedportsgatherer.h" #include "qt4maemotarget.h" -#include -#include -#include +#include +#include +#include #include #include @@ -66,6 +66,7 @@ #define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state) using namespace Core; +using namespace Utils; using namespace ProjectExplorer; namespace Qt4ProjectManager { @@ -436,7 +437,7 @@ void MaemoDeployStep::handleSftpChannelInitializationFailed(const QString &error } } -void MaemoDeployStep::handleSftpJobFinished(Core::SftpJobId, +void MaemoDeployStep::handleSftpJobFinished(Utils::SftpJobId, const QString &error) { ASSERT_STATE(QList() << Uploading << StopRequested); @@ -612,8 +613,8 @@ void MaemoDeployStep::prepareSftpConnection() SLOT(handleSftpChannelInitialized())); connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), this, SLOT(handleSftpChannelInitializationFailed(QString))); - connect(m_uploader.data(), SIGNAL(finished(Core::SftpJobId, QString)), - this, SLOT(handleSftpJobFinished(Core::SftpJobId, QString))); + connect(m_uploader.data(), SIGNAL(finished(Utils::SftpJobId, QString)), + this, SLOT(handleSftpJobFinished(Utils::SftpJobId, QString))); connect(m_uploader.data(), SIGNAL(closed()), this, SLOT(handleSftpChannelClosed())); m_uploader->initialize(); @@ -695,7 +696,7 @@ void MaemoDeployStep::connectToDevice() m_connection = SshConnection::create(); connect(m_connection.data(), SIGNAL(connected()), this, SLOT(handleConnected())); - connect(m_connection.data(), SIGNAL(error(Core::SshError)), this, + connect(m_connection.data(), SIGNAL(error(Utils::SshError)), this, SLOT(handleConnectionFailure())); if (canReUse) { handleConnected(); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.h b/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.h index 1c8438283b..c0a1112634 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeploystep.h @@ -39,7 +39,7 @@ #include "maemodeviceconfigurations.h" #include "maemomountspecification.h" -#include +#include #include #include @@ -54,7 +54,7 @@ class QProcess; class QTimer; QT_END_NAMESPACE -namespace Core { +namespace Utils { class SftpChannel; class SshConnection; class SshRemoteProcess; @@ -84,7 +84,7 @@ public: const MaemoDeployable &deployable) const; void setDeployed(const QString &host, const MaemoDeployable &deployable); QSharedPointer deployables() const { return m_deployables; } - QSharedPointer sshConnection() const { return m_connection; } + QSharedPointer sshConnection() const { return m_connection; } MaemoPortList freePorts() const; bool isDeployToSysrootEnabled() const { return m_deployToSysroot; } @@ -112,7 +112,7 @@ private slots: void handleSysrootInstallerErrorOutput(); void handleSftpChannelInitialized(); void handleSftpChannelInitializationFailed(const QString &error); - void handleSftpJobFinished(Core::SftpJobId job, const QString &error); + void handleSftpJobFinished(Utils::SftpJobId job, const QString &error); void handleSftpChannelClosed(); void handleInstallationFinished(int exitStatus); void handleDeviceInstallerOutput(const QByteArray &output); @@ -162,15 +162,15 @@ private: static const QLatin1String Id; QSharedPointer m_deployables; - QSharedPointer m_connection; + QSharedPointer m_connection; QProcess *m_sysrootInstaller; - typedef QPair > DeviceDeployAction; + typedef QPair > DeviceDeployAction; QScopedPointer m_currentDeviceDeployAction; QList m_filesToCopy; MaemoRemoteMounter *m_mounter; bool m_deployToSysroot; - QSharedPointer m_uploader; - QSharedPointer m_deviceInstaller; + QSharedPointer m_uploader; + QSharedPointer m_deviceInstaller; bool m_needsInstall; typedef QPair DeployablePerHost; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp index ecff8f4797..b576080f45 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.cpp @@ -44,7 +44,7 @@ #include #include -typedef Core::SshConnectionParameters::AuthType AuthType; +typedef Utils::SshConnectionParameters::AuthType AuthType; namespace Qt4ProjectManager { namespace Internal { @@ -74,7 +74,7 @@ namespace { const int DefaultGdbServerPortSim(13219); const QString DefaultHostNameHW(QLatin1String("192.168.2.15")); const QString DefaultHostNameSim(QLatin1String("localhost")); - const AuthType DefaultAuthType(Core::SshConnectionParameters::AuthByKey); + const AuthType DefaultAuthType(Utils::SshConnectionParameters::AuthByKey); const int DefaultTimeout(30); const MaemoDeviceConfig::DeviceType DefaultDeviceType(MaemoDeviceConfig::Physical); } @@ -231,8 +231,8 @@ MaemoDeviceConfig::Ptr MaemoDeviceConfig::createHardwareConfig(const QString &na MaemoGlobal::MaemoVersion osVersion, const QString &hostName, const QString privateKeyFilePath, Id &nextId) { - Core::SshConnectionParameters sshParams(Core::SshConnectionParameters::NoProxy); - sshParams.authType = Core::SshConnectionParameters::AuthByKey; + Utils::SshConnectionParameters sshParams(Utils::SshConnectionParameters::NoProxy); + sshParams.authType = Utils::SshConnectionParameters::AuthByKey; sshParams.host = hostName; sshParams.privateKeyFile = privateKeyFilePath; return Ptr(new MaemoDeviceConfig(name, osVersion, Physical, sshParams, nextId)); @@ -241,8 +241,8 @@ MaemoDeviceConfig::Ptr MaemoDeviceConfig::createHardwareConfig(const QString &na MaemoDeviceConfig::Ptr MaemoDeviceConfig::createEmulatorConfig(const QString &name, MaemoGlobal::MaemoVersion osVersion, Id &nextId) { - Core::SshConnectionParameters sshParams(Core::SshConnectionParameters::NoProxy); - sshParams.authType = Core::SshConnectionParameters::AuthByPwd; + Utils::SshConnectionParameters sshParams(Utils::SshConnectionParameters::NoProxy); + sshParams.authType = Utils::SshConnectionParameters::AuthByPwd; sshParams.host = defaultHost(Simulator); sshParams.pwd = defaultQemuPassword(osVersion); return Ptr(new MaemoDeviceConfig(name, osVersion, Simulator, sshParams, nextId)); @@ -250,7 +250,7 @@ MaemoDeviceConfig::Ptr MaemoDeviceConfig::createEmulatorConfig(const QString &na MaemoDeviceConfig::MaemoDeviceConfig(const QString &name, MaemoGlobal::MaemoVersion osVersion, DeviceType devType, - const Core::SshConnectionParameters &sshParams, Id &nextId) + const Utils::SshConnectionParameters &sshParams, Id &nextId) : m_sshParameters(sshParams), m_name(name), m_osVersion(osVersion), @@ -266,7 +266,7 @@ MaemoDeviceConfig::MaemoDeviceConfig(const QString &name, MaemoDeviceConfig::MaemoDeviceConfig(const QSettings &settings, Id &nextId) - : m_sshParameters(Core::SshConnectionParameters::NoProxy), + : m_sshParameters(Utils::SshConnectionParameters::NoProxy), m_name(settings.value(NameKey).toString()), m_osVersion(static_cast(settings.value(OsVersionKey, MaemoGlobal::Maemo5).toInt())), m_type(static_cast(settings.value(TypeKey, DefaultDeviceType).toInt())), @@ -493,7 +493,7 @@ void MaemoDeviceConfigurations::setConfigurationName(int i, const QString &name) } void MaemoDeviceConfigurations::setSshParameters(int i, - const Core::SshConnectionParameters ¶ms) + const Utils::SshConnectionParameters ¶ms) { Q_ASSERT(i >= 0 && i < rowCount()); m_devConfigs.at(i)->m_sshParameters = params; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h index a738e7f7fb..a84cf79ff2 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurations.h @@ -37,7 +37,7 @@ #include "maemoglobal.h" -#include +#include #include #include @@ -77,7 +77,7 @@ public: enum DeviceType { Physical, Simulator }; MaemoPortList freePorts() const; - Core::SshConnectionParameters sshParameters() const { return m_sshParameters; } + Utils::SshConnectionParameters sshParameters() const { return m_sshParameters; } QString name() const { return m_name; } MaemoGlobal::MaemoVersion osVersion() const { return m_osVersion; } DeviceType type() const { return m_type; } @@ -98,7 +98,7 @@ private: typedef QSharedPointer Ptr; MaemoDeviceConfig(const QString &name, MaemoGlobal::MaemoVersion osVersion, - DeviceType type, const Core::SshConnectionParameters &sshParams, + DeviceType type, const Utils::SshConnectionParameters &sshParams, Id &nextId); MaemoDeviceConfig(const QSettings &settings, Id &nextId); MaemoDeviceConfig(const ConstPtr &other); @@ -117,7 +117,7 @@ private: void save(QSettings &settings) const; QString defaultPortsSpec(DeviceType type) const; - Core::SshConnectionParameters m_sshParameters; + Utils::SshConnectionParameters m_sshParameters; QString m_name; MaemoGlobal::MaemoVersion m_osVersion; DeviceType m_type; @@ -154,7 +154,7 @@ public: MaemoGlobal::MaemoVersion osVersion); void removeConfiguration(int index); void setConfigurationName(int i, const QString &name); - void setSshParameters(int i, const Core::SshConnectionParameters ¶ms); + void setSshParameters(int i, const Utils::SshConnectionParameters ¶ms); void setPortsSpec(int i, const QString &portsSpec); void setDefaultDevice(int index); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.cpp index f6b5dfff44..f42353f004 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.cpp @@ -44,7 +44,7 @@ #include "maemosshconfigdialog.h" #include -#include +#include #include #include @@ -58,6 +58,7 @@ #include using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -204,7 +205,7 @@ void MaemoDeviceConfigurationsSettingsWidget::displayCurrent() m_ui->deviceTypeValueLabel->setText(tr("Emulator (Qemu)")); m_ui->portsLineEdit->setReadOnly(true); } - if (sshParams.authType == Core::SshConnectionParameters::AuthByPwd) + if (sshParams.authType == Utils::SshConnectionParameters::AuthByPwd) m_ui->passwordButton->setChecked(true); else m_ui->keyButton->setChecked(true); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.h b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.h index ff0be87432..5715e1c885 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigurationssettingswidget.h @@ -46,7 +46,7 @@ class QLineEdit; class Ui_MaemoDeviceConfigurationsSettingsWidget; QT_END_NAMESPACE -namespace Core { +namespace Utils { class SshRemoteProcessRunner; } diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigwizard.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigwizard.cpp index c117007a92..f56920d3f0 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigwizard.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceconfigwizard.cpp @@ -41,7 +41,7 @@ #include "maemodeviceconfigurations.h" #include "maemokeydeployer.h" -#include +#include #include #include @@ -309,9 +309,9 @@ private: m_ui->keyDirPathChooser->setEnabled(false); m_ui->createKeysButton->setEnabled(false); m_ui->statusLabel->setText(tr("Creating keys ... ")); - Core::SshKeyGenerator keyGenerator; - if (!keyGenerator.generateKeys(Core::SshKeyGenerator::Rsa, - Core::SshKeyGenerator::OpenSsl, 1024)) { + Utils::SshKeyGenerator keyGenerator; + if (!keyGenerator.generateKeys(Utils::SshKeyGenerator::Rsa, + Utils::SshKeyGenerator::OpenSsl, 1024)) { QMessageBox::critical(this, tr("Can't Create Keys"), tr("Key creation failed: %1").arg(keyGenerator.error())); enableInput(); @@ -402,11 +402,11 @@ private: Q_SLOT void deployKey() { - using namespace Core; + using namespace Utils; m_ui->deviceAddressLineEdit->setEnabled(false); m_ui->passwordLineEdit->setEnabled(false); m_ui->deployButton->setEnabled(false); - Core::SshConnectionParameters sshParams(SshConnectionParameters::NoProxy); + Utils::SshConnectionParameters sshParams(SshConnectionParameters::NoProxy); sshParams.authType = SshConnectionParameters::AuthByPwd; sshParams.host = hostAddress(); sshParams.port = MaemoDeviceConfig::defaultSshPort(MaemoDeviceConfig::Physical); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.cpp index 8a8581c7d4..f683b28a3a 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.cpp @@ -38,7 +38,7 @@ #include "maemoglobal.h" #include "maemorunconfiguration.h" -#include +#include namespace Qt4ProjectManager { namespace Internal { @@ -63,13 +63,13 @@ void MaemoDeviceEnvReader::start() return; m_stop = false; if (!m_remoteProcessRunner - || m_remoteProcessRunner->connection()->state() != Core::SshConnection::Connected + || m_remoteProcessRunner->connection()->state() != Utils::SshConnection::Connected || m_remoteProcessRunner->connection()->connectionParameters() != m_devConfig->sshParameters()) { m_remoteProcessRunner - = Core::SshRemoteProcessRunner::create(m_devConfig->sshParameters()); + = Utils::SshRemoteProcessRunner::create(m_devConfig->sshParameters()); } connect(m_remoteProcessRunner.data(), - SIGNAL(connectionError(Core::SshError)), this, + SIGNAL(connectionError(Utils::SshError)), this, SLOT(handleConnectionFailure())); connect(m_remoteProcessRunner.data(), SIGNAL(processClosed(int)), this, SLOT(remoteProcessFinished(int))); @@ -115,16 +115,16 @@ void MaemoDeviceEnvReader::handleCurrentDeviceConfigChanged() void MaemoDeviceEnvReader::remoteProcessFinished(int exitCode) { - Q_ASSERT(exitCode == Core::SshRemoteProcess::FailedToStart - || exitCode == Core::SshRemoteProcess::KilledBySignal - || exitCode == Core::SshRemoteProcess::ExitedNormally); + Q_ASSERT(exitCode == Utils::SshRemoteProcess::FailedToStart + || exitCode == Utils::SshRemoteProcess::KilledBySignal + || exitCode == Utils::SshRemoteProcess::ExitedNormally); if (m_stop) return; disconnect(m_remoteProcessRunner.data(), 0, this, 0); m_env.clear(); - if (exitCode == Core::SshRemoteProcess::ExitedNormally) { + if (exitCode == Utils::SshRemoteProcess::ExitedNormally) { if (!m_remoteOutput.isEmpty()) { m_env = Utils::Environment(m_remoteOutput.split(QLatin1Char('\n'), QString::SkipEmptyParts)); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.h b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.h index 3933aff459..a36c1eec81 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemodeviceenvreader.h @@ -40,7 +40,7 @@ #include #include -namespace Core { +namespace Utils { class SshRemoteProcessRunner; } @@ -83,7 +83,7 @@ private: Utils::Environment m_env; QSharedPointer m_devConfig; MaemoRunConfiguration *m_runConfig; - QSharedPointer m_remoteProcessRunner; + QSharedPointer m_remoteProcessRunner; }; } // Internal diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp index 343c5676a9..178bbc4896 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.cpp @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include #include @@ -138,18 +138,18 @@ QString MaemoGlobal::remoteEnvironment(const QList &list return env.mid(0, env.size() - 1); } -QString MaemoGlobal::failedToConnectToServerMessage(const Core::SshConnection::Ptr &connection, +QString MaemoGlobal::failedToConnectToServerMessage(const Utils::SshConnection::Ptr &connection, const MaemoDeviceConfig::ConstPtr &deviceConfig) { QString errorMsg = tr("Could not connect to host: %1") .arg(connection->errorString()); if (deviceConfig->type() == MaemoDeviceConfig::Simulator) { - if (connection->errorState() == Core::SshTimeoutError - || connection->errorState() == Core::SshSocketError) { + if (connection->errorState() == Utils::SshTimeoutError + || connection->errorState() == Utils::SshSocketError) { errorMsg += tr("\nDid you start Qemu?"); } - } else if (connection->errorState() == Core::SshTimeoutError) { + } else if (connection->errorState() == Utils::SshTimeoutError) { errorMsg += tr("\nIs the device connected and set up for network access?"); } return errorMsg; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h index 682862ae5e..72afdc52d1 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoglobal.h @@ -51,7 +51,7 @@ class QProcess; class QString; QT_END_NAMESPACE -namespace Core { class SshConnection; } +namespace Utils { class SshConnection; } namespace Qt4ProjectManager { class QtVersion; namespace Internal { @@ -82,7 +82,7 @@ public: static QString remoteCommandPrefix(const QString &commandFilePath); static QString remoteEnvironment(const QList &list); static QString remoteSourceProfilesCommand(); - static QString failedToConnectToServerMessage(const QSharedPointer &connection, + static QString failedToConnectToServerMessage(const QSharedPointer &connection, const QSharedPointer &deviceConfig); static QString deviceConfigurationName(const QSharedPointer &devConf); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.cpp index ddc6061222..679feffce5 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.cpp @@ -33,11 +33,11 @@ ****************************************************************************/ #include "maemokeydeployer.h" -#include +#include #include -using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -68,7 +68,7 @@ void MaemoKeyDeployer::deployPublicKey(const SshConnectionParameters &sshParams, return; } - connect(m_deployProcess.data(), SIGNAL(connectionError(Core::SshError)), this, + connect(m_deployProcess.data(), SIGNAL(connectionError(Utils::SshError)), this, SLOT(handleConnectionFailure())); connect(m_deployProcess.data(), SIGNAL(processClosed(int)), this, SLOT(handleKeyUploadFinished(int))); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.h b/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.h index c0d4b15a92..30bc07d79e 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemokeydeployer.h @@ -37,7 +37,7 @@ #include #include -namespace Core { +namespace Utils { struct SshConnectionParameters; class SshRemoteProcessRunner; } @@ -52,7 +52,7 @@ public: explicit MaemoKeyDeployer(QObject *parent = 0); ~MaemoKeyDeployer(); - void deployPublicKey(const Core::SshConnectionParameters &sshParams, + void deployPublicKey(const Utils::SshConnectionParameters &sshParams, const QString &keyFilePath); void stopDeployment(); @@ -67,7 +67,7 @@ private slots: private: void cleanup(); - QSharedPointer m_deployProcess; + QSharedPointer m_deployProcess; }; } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.cpp index 000128b940..5fce2a4cbb 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.cpp @@ -54,6 +54,7 @@ #define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state) using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -371,7 +372,7 @@ void MaemoPublisherFremantleFree::uploadPackage() m_uploader = SshRemoteProcessRunner::create(m_sshParams); connect(m_uploader.data(), SIGNAL(processStarted()), SLOT(handleScpStarted())); - connect(m_uploader.data(), SIGNAL(connectionError(Core::SshError)), + connect(m_uploader.data(), SIGNAL(connectionError(Utils::SshError)), SLOT(handleConnectionError())); connect(m_uploader.data(), SIGNAL(processClosed(int)), SLOT(handleUploadJobFinished(int))); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.h b/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.h index b05d79d1e3..c74e969c2f 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemopublisherfremantlefree.h @@ -33,7 +33,7 @@ #ifndef MAEMOPUBLISHERFREMANTLEFREE_H #define MAEMOPUBLISHERFREMANTLEFREE_H -#include +#include #include #include @@ -112,9 +112,9 @@ private: State m_state; QString m_tmpProjectDir; QProcess *m_process; - Core::SshConnectionParameters m_sshParams; + Utils::SshConnectionParameters m_sshParams; QString m_remoteDir; - QSharedPointer m_uploader; + QSharedPointer m_uploader; QByteArray m_scpOutput; QList m_filesToUpload; QString m_resultString; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.cpp index a60f3d49c4..e18cc00c82 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.cpp @@ -37,8 +37,8 @@ #include "maemousedportsgatherer.h" #include "qt4maemotarget.h" -#include -#include +#include +#include #include #include @@ -46,7 +46,7 @@ #define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state) -using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.h b/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.h index 7aa2226b47..a73d4ddb10 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoremotemounter.h @@ -45,7 +45,7 @@ QT_FORWARD_DECLARE_CLASS(QTimer) -namespace Core { +namespace Utils { class SftpChannel; class SshConnection; class SshRemoteProcess; @@ -64,7 +64,7 @@ public: ~MaemoRemoteMounter(); // Must already be connected. - void setConnection(const QSharedPointer &connection); + void setConnection(const QSharedPointer &connection); void setBuildConfiguration(const Qt4BuildConfiguration *bc); void addMountSpecification(const MaemoMountSpecification &mountSpec, @@ -120,10 +120,10 @@ private: int remotePort; }; - QSharedPointer m_connection; + QSharedPointer m_connection; QList m_mountSpecs; - QSharedPointer m_mountProcess; - QSharedPointer m_unmountProcess; + QSharedPointer m_mountProcess; + QSharedPointer m_unmountProcess; typedef QSharedPointer ProcPtr; QList m_utfsServers; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.cpp index 1d27d0852f..611001e0dd 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.cpp @@ -43,11 +43,11 @@ #include "maemodeviceconfigurations.h" -#include +#include #include -using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -114,7 +114,7 @@ void MaemoRemoteProcessList::startProcess(const QByteArray &cmdLine, stop(); } m_state = newState; - connect(m_process.data(), SIGNAL(connectionError(Core::SshError)), + connect(m_process.data(), SIGNAL(connectionError(Utils::SshError)), SLOT(handleConnectionError())); connect(m_process.data(), SIGNAL(processOutputAvailable(QByteArray)), SLOT(handleRemoteStdOut(QByteArray))); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.h b/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.h index 81fddb25d9..edc22df5e9 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoremoteprocesslist.h @@ -47,7 +47,7 @@ #include #include #include -#include +#include namespace Qt4ProjectManager { namespace Internal { @@ -87,7 +87,7 @@ private: void stop(); void startProcess(const QByteArray &cmdLine, State newState); - const QSharedPointer m_process; + const QSharedPointer m_process; QByteArray m_remoteStdout; QByteArray m_remoteStderr; QString m_errorMsg; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp index a339c160dc..6775e2fb6a 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.cpp @@ -36,7 +36,7 @@ #include "maemodeviceconfigurations.h" -#include +#include #include #include @@ -45,7 +45,7 @@ #include #include -using namespace Core; +using namespace Utils; using namespace Qt4ProjectManager::Internal; MaemoSshConfigDialog::MaemoSshConfigDialog(QWidget *parent) diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h index 4073ff9e40..a0f7469785 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshconfigdialog.h @@ -40,7 +40,7 @@ #include #include -namespace Core { +namespace Utils { class SshKeyGenerator; } @@ -69,7 +69,7 @@ private: private: QString home; - QScopedPointer m_keyGenerator; + QScopedPointer m_keyGenerator; Ui::MaemoSshConfigDialog m_ui; }; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp index 556b5fb541..fd9a03a937 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp @@ -42,8 +42,8 @@ #include "maemorunconfiguration.h" #include "maemousedportsgatherer.h" -#include -#include +#include +#include #include @@ -51,7 +51,7 @@ #define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state) -using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -125,7 +125,7 @@ void MaemoSshRunner::start() m_connection = SshConnection::create(); connect(m_connection.data(), SIGNAL(connected()), this, SLOT(handleConnected())); - connect(m_connection.data(), SIGNAL(error(Core::SshError)), this, + connect(m_connection.data(), SIGNAL(error(Utils::SshError)), this, SLOT(handleConnectionFailure())); if (reUse) { handleConnected(); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h index f7b64a29f6..edf436be95 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h @@ -44,7 +44,7 @@ #include #include -namespace Core { +namespace Utils { class SshConnection; class SshRemoteProcess; } @@ -68,7 +68,7 @@ public: void startExecution(const QByteArray &remoteCall); - QSharedPointer connection() const { return m_connection; } + QSharedPointer connection() const { return m_connection; } const MaemoUsedPortsGatherer *usedPortsGatherer() const { return m_portsGatherer; } MaemoPortList *freePorts() { return &m_freePorts; } QString remoteExecutable() const { return m_remoteExecutable; } @@ -121,9 +121,9 @@ private: const MaemoPortList m_initialFreePorts; QList m_mountSpecs; - QSharedPointer m_connection; - QSharedPointer m_runner; - QSharedPointer m_cleaner; + QSharedPointer m_connection; + QSharedPointer m_runner; + QSharedPointer m_cleaner; QStringList m_procsToKill; MaemoPortList m_freePorts; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.cpp index 1ebd7baed8..3cb2eaee17 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.cpp @@ -35,9 +35,9 @@ #include "maemoglobal.h" -#include +#include -using namespace Core; +using namespace Utils; namespace Qt4ProjectManager { namespace Internal { @@ -49,7 +49,7 @@ MaemoUsedPortsGatherer::MaemoUsedPortsGatherer(QObject *parent) : MaemoUsedPortsGatherer::~MaemoUsedPortsGatherer() {} -void MaemoUsedPortsGatherer::start(const Core::SshConnection::Ptr &connection, +void MaemoUsedPortsGatherer::start(const Utils::SshConnection::Ptr &connection, const MaemoPortList &portList) { if (m_running) @@ -58,7 +58,7 @@ void MaemoUsedPortsGatherer::start(const Core::SshConnection::Ptr &connection, m_remoteStdout.clear(); m_remoteStderr.clear(); m_procRunner = SshRemoteProcessRunner::create(connection); - connect(m_procRunner.data(), SIGNAL(connectionError(Core::SshError)), + connect(m_procRunner.data(), SIGNAL(connectionError(Utils::SshError)), SLOT(handleConnectionError())); connect(m_procRunner.data(), SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int))); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.h b/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.h index b0137d9fe5..73ae9ac4ea 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemousedportsgatherer.h @@ -41,7 +41,7 @@ #include #include -namespace Core { +namespace Utils { class SshConnection; class SshRemoteProcessRunner; } @@ -55,7 +55,7 @@ class MaemoUsedPortsGatherer : public QObject public: explicit MaemoUsedPortsGatherer(QObject *parent = 0); ~MaemoUsedPortsGatherer(); - void start(const QSharedPointer &connection, + void start(const QSharedPointer &connection, const MaemoPortList &portList); void stop(); int getNextFreePort(MaemoPortList *freePorts) const; // returns -1 if no more are left @@ -74,7 +74,7 @@ private slots: private: void setupUsedPorts(); - QSharedPointer m_procRunner; + QSharedPointer m_procRunner; QList m_usedPorts; QByteArray m_remoteStdout; QByteArray m_remoteStderr; -- cgit v1.2.1