2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2010-07-12 09:33:22 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2010-07-12 09:33:22 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2010-04-26 11:43:25 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:58:39 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2010-04-26 11:43:25 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2010-04-26 11:43:25 +02:00
|
|
|
|
|
|
|
|
#include "sshconnection.h"
|
2010-07-12 09:33:22 +02:00
|
|
|
#include "sshconnection_p.h"
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
#include "sftpchannel.h"
|
2016-07-20 18:04:56 +02:00
|
|
|
#include "sshagent_p.h"
|
2010-07-12 09:33:22 +02:00
|
|
|
#include "sshcapabilities_p.h"
|
|
|
|
|
#include "sshchannelmanager_p.h"
|
|
|
|
|
#include "sshcryptofacility_p.h"
|
2012-06-19 13:03:48 +02:00
|
|
|
#include "sshdirecttcpiptunnel.h"
|
2016-03-31 18:57:03 +02:00
|
|
|
#include "sshtcpipforwardserver.h"
|
2010-07-12 09:33:22 +02:00
|
|
|
#include "sshexception_p.h"
|
2013-08-14 15:11:27 +02:00
|
|
|
#include "sshinit_p.h"
|
2010-07-12 09:33:22 +02:00
|
|
|
#include "sshkeyexchange_p.h"
|
2016-01-14 17:11:03 +01:00
|
|
|
#include "sshlogging_p.h"
|
2012-06-19 13:03:48 +02:00
|
|
|
#include "sshremoteprocess.h"
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2012-06-26 09:31:01 +02:00
|
|
|
#include <botan/botan.h>
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QFile>
|
|
|
|
|
#include <QMutex>
|
|
|
|
|
#include <QMutexLocker>
|
|
|
|
|
#include <QNetworkProxy>
|
2012-09-26 10:57:19 +02:00
|
|
|
#include <QRegExp>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QTcpSocket>
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2011-03-02 17:13:33 +01:00
|
|
|
/*!
|
2012-05-18 10:49:35 +02:00
|
|
|
\class QSsh::SshConnection
|
2011-03-02 17:13:33 +01:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The SshConnection class provides an SSH connection, implementing
|
|
|
|
|
protocol version 2.0.
|
2011-03-02 17:13:33 +01:00
|
|
|
|
|
|
|
|
It can spawn channels for remote execution and SFTP operations (version 3).
|
|
|
|
|
It operates asynchronously (non-blocking) and is not thread-safe.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
namespace QSsh {
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2013-08-14 15:11:27 +02:00
|
|
|
const QByteArray ClientId("SSH-2.0-QtCreator\r\n");
|
2010-08-24 10:51:31 +02:00
|
|
|
|
2012-03-05 12:37:32 +01:00
|
|
|
SshConnectionParameters::SshConnectionParameters() :
|
2014-11-12 16:50:04 +01:00
|
|
|
timeout(0), authenticationType(AuthenticationTypePublicKey), port(0),
|
|
|
|
|
hostKeyCheckingMode(SshHostKeyCheckingNone)
|
2010-08-24 10:51:31 +02:00
|
|
|
{
|
2012-10-11 15:34:33 +02:00
|
|
|
options |= SshIgnoreDefaultProxy;
|
|
|
|
|
options |= SshEnableStrictConformanceChecks;
|
2010-08-24 10:51:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool equals(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
|
|
|
|
|
{
|
2011-02-15 13:33:52 +01:00
|
|
|
return p1.host == p2.host && p1.userName == p2.userName
|
2011-02-28 17:01:53 +01:00
|
|
|
&& p1.authenticationType == p2.authenticationType
|
2013-06-18 18:12:34 +02:00
|
|
|
&& (p1.authenticationType == SshConnectionParameters::AuthenticationTypePassword ?
|
2011-02-15 13:33:52 +01:00
|
|
|
p1.password == p2.password : p1.privateKeyFile == p2.privateKeyFile)
|
2014-11-12 16:50:04 +01:00
|
|
|
&& p1.hostKeyCheckingMode == p2.hostKeyCheckingMode
|
2010-08-24 10:51:31 +02:00
|
|
|
&& p1.timeout == p2.timeout && p1.port == p2.port;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
|
2010-08-24 10:51:31 +02:00
|
|
|
{
|
|
|
|
|
return equals(p1, p2);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-18 10:49:35 +02:00
|
|
|
bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2)
|
2010-08-24 10:51:31 +02:00
|
|
|
{
|
|
|
|
|
return !equals(p1, p2);
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
|
|
|
|
|
2012-06-08 08:48:03 +02:00
|
|
|
SshConnection::SshConnection(const SshConnectionParameters &serverInfo, QObject *parent)
|
|
|
|
|
: QObject(parent)
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2013-08-14 15:11:27 +02:00
|
|
|
Internal::initSsh();
|
|
|
|
|
qRegisterMetaType<QSsh::SshError>("QSsh::SshError");
|
|
|
|
|
qRegisterMetaType<QSsh::SftpJobId>("QSsh::SftpJobId");
|
|
|
|
|
qRegisterMetaType<QSsh::SftpFileInfo>("QSsh::SftpFileInfo");
|
|
|
|
|
qRegisterMetaType<QList <QSsh::SftpFileInfo> >("QList<QSsh::SftpFileInfo>");
|
2012-06-05 15:18:55 +02:00
|
|
|
|
|
|
|
|
d = new Internal::SshConnectionPrivate(this, serverInfo);
|
2016-06-07 22:04:26 +03:00
|
|
|
connect(d, &Internal::SshConnectionPrivate::connected, this, &SshConnection::connected,
|
2010-07-12 09:33:22 +02:00
|
|
|
Qt::QueuedConnection);
|
2016-06-07 22:04:26 +03:00
|
|
|
connect(d, &Internal::SshConnectionPrivate::dataAvailable, this,
|
|
|
|
|
&SshConnection::dataAvailable, Qt::QueuedConnection);
|
|
|
|
|
connect(d, &Internal::SshConnectionPrivate::disconnected, this, &SshConnection::disconnected,
|
2010-07-12 09:33:22 +02:00
|
|
|
Qt::QueuedConnection);
|
2016-06-07 22:04:26 +03:00
|
|
|
connect(d, &Internal::SshConnectionPrivate::error, this,
|
|
|
|
|
&SshConnection::error, Qt::QueuedConnection);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2011-03-09 12:07:35 +01:00
|
|
|
void SshConnection::connectToHost()
|
2010-07-12 09:33:22 +02:00
|
|
|
{
|
2011-03-09 12:07:35 +01:00
|
|
|
d->connectToHost();
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnection::disconnectFromHost()
|
|
|
|
|
{
|
|
|
|
|
d->closeConnection(Internal::SSH_DISCONNECT_BY_APPLICATION, SshNoError, "",
|
|
|
|
|
QString());
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
SshConnection::State SshConnection::state() const
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
switch (d->state()) {
|
|
|
|
|
case Internal::SocketUnconnected:
|
|
|
|
|
return Unconnected;
|
|
|
|
|
case Internal::ConnectionEstablished:
|
|
|
|
|
return Connected;
|
|
|
|
|
default:
|
|
|
|
|
return Connecting;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
SshError SshConnection::errorState() const
|
|
|
|
|
{
|
2016-06-07 22:04:26 +03:00
|
|
|
return d->errorState();
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
QString SshConnection::errorString() const
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
return d->errorString();
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
SshConnectionParameters SshConnection::connectionParameters() const
|
|
|
|
|
{
|
|
|
|
|
return d->m_connParams;
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2012-02-10 10:39:48 +01:00
|
|
|
SshConnectionInfo SshConnection::connectionInfo() const
|
2011-10-04 14:21:37 +02:00
|
|
|
{
|
2012-05-18 10:49:35 +02:00
|
|
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshConnectionInfo());
|
2012-02-10 10:39:48 +01:00
|
|
|
|
|
|
|
|
return SshConnectionInfo(d->m_socket->localAddress(), d->m_socket->localPort(),
|
|
|
|
|
d->m_socket->peerAddress(), d->m_socket->peerPort());
|
2011-10-04 14:21:37 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
SshConnection::~SshConnection()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
disconnect();
|
|
|
|
|
disconnectFromHost();
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
QSharedPointer<SshRemoteProcess> SshConnection::createRemoteProcess(const QByteArray &command)
|
|
|
|
|
{
|
2012-05-18 10:49:35 +02:00
|
|
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer<SshRemoteProcess>());
|
2011-01-03 12:04:33 +01:00
|
|
|
return d->createRemoteProcess(command);
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2011-07-26 18:13:11 +02:00
|
|
|
QSharedPointer<SshRemoteProcess> SshConnection::createRemoteShell()
|
|
|
|
|
{
|
2012-05-18 10:49:35 +02:00
|
|
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer<SshRemoteProcess>());
|
2011-07-26 18:13:11 +02:00
|
|
|
return d->createRemoteShell();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
|
|
|
|
|
{
|
2012-05-18 10:49:35 +02:00
|
|
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, QSharedPointer<SftpChannel>());
|
2011-01-03 12:04:33 +01:00
|
|
|
return d->createSftpChannel();
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-05-05 10:06:31 +02:00
|
|
|
|
2016-03-31 18:57:03 +02:00
|
|
|
SshDirectTcpIpTunnel::Ptr SshConnection::createDirectTunnel(const QString &originatingHost,
|
2015-04-14 15:47:55 +02:00
|
|
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
2012-06-19 13:03:48 +02:00
|
|
|
{
|
|
|
|
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshDirectTcpIpTunnel::Ptr());
|
2016-03-31 18:57:03 +02:00
|
|
|
return d->createDirectTunnel(originatingHost, originatingPort, remoteHost, remotePort);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSharedPointer<SshTcpIpForwardServer> SshConnection::createForwardServer(const QString &remoteHost,
|
|
|
|
|
quint16 remotePort)
|
|
|
|
|
{
|
|
|
|
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshTcpIpForwardServer::Ptr());
|
|
|
|
|
return d->createForwardServer(remoteHost, remotePort);
|
2012-06-19 13:03:48 +02:00
|
|
|
}
|
|
|
|
|
|
2012-06-20 15:55:30 +02:00
|
|
|
int SshConnection::closeAllChannels()
|
|
|
|
|
{
|
|
|
|
|
try {
|
2012-08-17 17:33:06 +02:00
|
|
|
return d->m_channelManager->closeAllChannels(Internal::SshChannelManager::CloseAllRegular);
|
2017-05-05 09:55:01 +02:00
|
|
|
} catch (const std::exception &e) {
|
2016-01-14 17:11:03 +01:00
|
|
|
qCWarning(Internal::sshLog, "%s: %s", Q_FUNC_INFO, e.what());
|
2012-06-20 15:55:30 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2012-08-17 17:33:06 +02:00
|
|
|
int SshConnection::channelCount() const
|
|
|
|
|
{
|
|
|
|
|
return d->m_channelManager->channelCount();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
namespace Internal {
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2011-03-09 12:07:35 +01:00
|
|
|
SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn,
|
|
|
|
|
const SshConnectionParameters &serverInfo)
|
2010-07-12 09:33:22 +02:00
|
|
|
: m_socket(new QTcpSocket(this)), m_state(SocketUnconnected),
|
|
|
|
|
m_sendFacility(m_socket),
|
2010-08-16 22:10:34 +02:00
|
|
|
m_channelManager(new SshChannelManager(m_sendFacility, this)),
|
2011-03-09 12:07:35 +01:00
|
|
|
m_connParams(serverInfo), m_error(SshNoError), m_ignoreNextPacket(false),
|
|
|
|
|
m_conn(conn)
|
2010-07-12 09:33:22 +02:00
|
|
|
{
|
|
|
|
|
setupPacketHandlers();
|
2012-10-01 14:51:27 +02:00
|
|
|
m_socket->setProxy((m_connParams.options & SshIgnoreDefaultProxy)
|
|
|
|
|
? QNetworkProxy::NoProxy : QNetworkProxy::DefaultProxy);
|
2010-08-16 22:10:34 +02:00
|
|
|
m_timeoutTimer.setSingleShot(true);
|
2011-06-28 18:08:12 +02:00
|
|
|
m_timeoutTimer.setInterval(m_connParams.timeout * 1000);
|
2011-02-11 14:00:54 +01:00
|
|
|
m_keepAliveTimer.setSingleShot(true);
|
|
|
|
|
m_keepAliveTimer.setInterval(10000);
|
2016-06-07 22:04:26 +03:00
|
|
|
connect(m_channelManager, &SshChannelManager::timeout,
|
|
|
|
|
this, &SshConnectionPrivate::handleTimeout);
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
SshConnectionPrivate::~SshConnectionPrivate()
|
|
|
|
|
{
|
|
|
|
|
disconnect();
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::setupPacketHandlers()
|
|
|
|
|
{
|
|
|
|
|
typedef SshConnectionPrivate This;
|
|
|
|
|
|
2011-04-19 10:57:12 +02:00
|
|
|
setupPacketHandler(SSH_MSG_KEXINIT, StateList() << SocketConnected
|
|
|
|
|
<< ConnectionEstablished, &This::handleKeyExchangeInitPacket);
|
|
|
|
|
setupPacketHandler(SSH_MSG_KEXDH_REPLY, StateList() << SocketConnected
|
|
|
|
|
<< ConnectionEstablished, &This::handleKeyExchangeReplyPacket);
|
2010-07-12 09:33:22 +02:00
|
|
|
|
2011-04-19 10:57:12 +02:00
|
|
|
setupPacketHandler(SSH_MSG_NEWKEYS, StateList() << SocketConnected
|
|
|
|
|
<< ConnectionEstablished, &This::handleNewKeysPacket);
|
2010-07-12 09:33:22 +02:00
|
|
|
setupPacketHandler(SSH_MSG_SERVICE_ACCEPT,
|
|
|
|
|
StateList() << UserAuthServiceRequested,
|
|
|
|
|
&This::handleServiceAcceptPacket);
|
2013-06-18 18:12:34 +02:00
|
|
|
if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypePassword
|
|
|
|
|
|| m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods) {
|
|
|
|
|
setupPacketHandler(SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
|
|
|
|
|
StateList() << UserAuthRequested, &This::handlePasswordExpiredPacket);
|
|
|
|
|
}
|
2010-07-12 09:33:22 +02:00
|
|
|
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);
|
2013-06-18 18:12:34 +02:00
|
|
|
if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeKeyboardInteractive
|
|
|
|
|
|| m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods) {
|
|
|
|
|
setupPacketHandler(SSH_MSG_USERAUTH_INFO_REQUEST, authReqList,
|
|
|
|
|
&This::handleUserAuthInfoRequestPacket);
|
|
|
|
|
}
|
2016-07-20 18:04:56 +02:00
|
|
|
setupPacketHandler(SSH_MSG_USERAUTH_PK_OK, authReqList, &This::handleUserAuthKeyOkPacket);
|
2010-07-12 09:33:22 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2016-07-20 18:04:56 +02:00
|
|
|
setupPacketHandler(SSH_MSG_DISCONNECT, StateList() << SocketConnected << WaitingForAgentKeys
|
2010-07-12 09:33:22 +02:00
|
|
|
<< UserAuthServiceRequested << UserAuthRequested
|
|
|
|
|
<< ConnectionEstablished, &This::handleDisconnect);
|
2011-02-11 14:00:54 +01:00
|
|
|
|
|
|
|
|
setupPacketHandler(SSH_MSG_UNIMPLEMENTED,
|
|
|
|
|
StateList() << ConnectionEstablished, &This::handleUnimplementedPacket);
|
2016-03-31 18:57:03 +02:00
|
|
|
|
|
|
|
|
setupPacketHandler(SSH_MSG_REQUEST_SUCCESS, connectedList,
|
|
|
|
|
&This::handleRequestSuccess);
|
|
|
|
|
setupPacketHandler(SSH_MSG_REQUEST_FAILURE, connectedList,
|
|
|
|
|
&This::handleRequestFailure);
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::setupPacketHandler(SshPacketType type,
|
|
|
|
|
const SshConnectionPrivate::StateList &states,
|
|
|
|
|
SshConnectionPrivate::PacketHandler handler)
|
|
|
|
|
{
|
|
|
|
|
m_packetHandlers.insert(type, HandlerInStates(states, handler));
|
|
|
|
|
}
|
2010-05-05 10:06:31 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleSocketConnected()
|
2010-05-05 10:06:31 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_state = SocketConnected;
|
|
|
|
|
sendData(ClientId);
|
2010-05-05 10:06:31 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleIncomingData()
|
|
|
|
|
{
|
|
|
|
|
if (m_state == SocketUnconnected)
|
|
|
|
|
return; // For stuff queued in the event loop after we've called closeConnection();
|
|
|
|
|
|
|
|
|
|
try {
|
2010-08-16 12:40:55 +02:00
|
|
|
if (!canUseSocket())
|
|
|
|
|
return;
|
2010-07-12 09:33:22 +02:00
|
|
|
m_incomingData += m_socket->readAll();
|
2016-01-14 17:11:03 +01:00
|
|
|
qCDebug(sshLog, "state = %d, remote data size = %d", m_state, m_incomingData.count());
|
2012-09-26 10:57:19 +02:00
|
|
|
if (m_serverId.isEmpty())
|
2010-07-12 09:33:22 +02:00
|
|
|
handleServerId();
|
|
|
|
|
handlePackets();
|
2014-11-28 11:15:37 +01:00
|
|
|
} catch (const SshServerException &e) {
|
2010-07-12 09:33:22 +02:00
|
|
|
closeConnection(e.error, SshProtocolError, e.errorStringServer,
|
|
|
|
|
tr("SSH Protocol error: %1").arg(e.errorStringUser));
|
2014-11-28 11:15:37 +01:00
|
|
|
} catch (const SshClientException &e) {
|
2010-07-12 09:33:22 +02:00
|
|
|
closeConnection(SSH_DISCONNECT_BY_APPLICATION, e.error, "",
|
|
|
|
|
e.errorString);
|
2017-05-05 09:55:01 +02:00
|
|
|
} catch (const std::exception &e) {
|
2010-07-12 09:33:22 +02:00
|
|
|
closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshInternalError, "",
|
2012-09-21 13:54:38 +02:00
|
|
|
tr("Botan library exception: %1").arg(QString::fromLatin1(e.what())));
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-05-05 10:06:31 +02:00
|
|
|
|
2012-09-26 10:57:19 +02:00
|
|
|
// RFC 4253, 4.2.
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleServerId()
|
|
|
|
|
{
|
2016-01-14 17:11:03 +01:00
|
|
|
qCDebug(sshLog, "%s: incoming data size = %d, incoming data = '%s'",
|
2012-02-23 14:46:38 +01:00
|
|
|
Q_FUNC_INFO, m_incomingData.count(), m_incomingData.data());
|
2012-09-26 10:57:19 +02:00
|
|
|
const int newLinePos = m_incomingData.indexOf('\n');
|
|
|
|
|
if (newLinePos == -1)
|
|
|
|
|
return; // Not enough data yet.
|
|
|
|
|
|
|
|
|
|
// Lines not starting with "SSH-" are ignored.
|
|
|
|
|
if (!m_incomingData.startsWith("SSH-")) {
|
|
|
|
|
m_incomingData.remove(0, newLinePos + 1);
|
|
|
|
|
m_serverHasSentDataBeforeId = true;
|
2010-07-12 09:33:22 +02:00
|
|
|
return;
|
2012-09-26 10:57:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newLinePos > 255 - 1) {
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Identification string too long.",
|
2012-10-01 15:26:13 +02:00
|
|
|
tr("Server identification string is %n characters long, but the maximum "
|
|
|
|
|
"allowed length is 255.", 0, newLinePos + 1));
|
2012-09-26 10:57:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool hasCarriageReturn = m_incomingData.at(newLinePos - 1) == '\r';
|
|
|
|
|
m_serverId = m_incomingData.left(newLinePos);
|
|
|
|
|
if (hasCarriageReturn)
|
|
|
|
|
m_serverId.chop(1);
|
|
|
|
|
m_incomingData.remove(0, newLinePos + 1);
|
|
|
|
|
|
|
|
|
|
if (m_serverId.contains('\0')) {
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Identification string contains illegal NUL character.",
|
|
|
|
|
tr("Server identification string contains illegal NUL character."));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "printable US-ASCII characters, with the exception of whitespace characters
|
|
|
|
|
// and the minus sign"
|
|
|
|
|
QString legalString = QLatin1String("[]!\"#$!&'()*+,./0-9:;<=>?@A-Z[\\\\^_`a-z{|}~]+");
|
|
|
|
|
const QRegExp versionIdpattern(QString::fromLatin1("SSH-(%1)-%1(?: .+)?").arg(legalString));
|
|
|
|
|
if (!versionIdpattern.exactMatch(QString::fromLatin1(m_serverId))) {
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Identification string is invalid.",
|
2014-04-17 14:09:47 +02:00
|
|
|
tr("Server Identification string \"%1\" is invalid.")
|
2012-09-26 10:57:19 +02:00
|
|
|
.arg(QString::fromLatin1(m_serverId)));
|
|
|
|
|
}
|
|
|
|
|
const QString serverProtoVersion = versionIdpattern.cap(1);
|
|
|
|
|
if (serverProtoVersion != QLatin1String("2.0") && serverProtoVersion != QLatin1String("1.99")) {
|
2010-07-12 09:33:22 +02:00
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
|
|
|
|
|
"Invalid protocol version.",
|
2014-04-17 14:09:47 +02:00
|
|
|
tr("Server protocol version is \"%1\", but needs to be 2.0 or 1.99.")
|
2012-09-26 10:57:19 +02:00
|
|
|
.arg(serverProtoVersion));
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2012-09-26 10:57:19 +02:00
|
|
|
|
2012-10-11 15:34:33 +02:00
|
|
|
if (m_connParams.options & SshEnableStrictConformanceChecks) {
|
|
|
|
|
if (serverProtoVersion == QLatin1String("2.0") && !hasCarriageReturn) {
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Identification string is invalid.",
|
|
|
|
|
tr("Server identification string is invalid (missing carriage return)."));
|
|
|
|
|
}
|
2012-09-26 10:57:19 +02:00
|
|
|
|
2012-10-11 15:34:33 +02:00
|
|
|
if (serverProtoVersion == QLatin1String("1.99") && m_serverHasSentDataBeforeId) {
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"No extra data preceding identification string allowed for 1.99.",
|
|
|
|
|
tr("Server reports protocol version 1.99, but sends data "
|
|
|
|
|
"before the identification string, which is not allowed."));
|
|
|
|
|
}
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-05-05 10:06:31 +02:00
|
|
|
|
2014-11-12 16:50:04 +01:00
|
|
|
m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility));
|
2011-04-19 10:57:12 +02:00
|
|
|
m_keyExchange->sendKexInitPacket(m_serverId);
|
2011-04-19 14:39:32 +02:00
|
|
|
m_keyExchangeState = KexInitSent;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handlePackets()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_incomingPacket.consumeData(m_incomingData);
|
|
|
|
|
while (m_incomingPacket.isComplete()) {
|
|
|
|
|
handleCurrentPacket();
|
|
|
|
|
m_incomingPacket.clear();
|
|
|
|
|
m_incomingPacket.consumeData(m_incomingData);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleCurrentPacket()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
Q_ASSERT(m_incomingPacket.isComplete());
|
2011-04-19 14:39:32 +02:00
|
|
|
Q_ASSERT(m_keyExchangeState == DhInitSent || !m_ignoreNextPacket);
|
2010-05-20 16:02:58 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
if (m_ignoreNextPacket) {
|
|
|
|
|
m_ignoreNextPacket = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
QHash<SshPacketType, HandlerInStates>::ConstIterator it
|
2015-04-01 11:19:32 +02:00
|
|
|
= m_packetHandlers.constFind(m_incomingPacket.type());
|
2013-06-18 18:12:34 +02:00
|
|
|
if (it == m_packetHandlers.constEnd()) {
|
2010-07-12 09:33:22 +02:00
|
|
|
m_sendFacility.sendMsgUnimplementedPacket(m_incomingPacket.serverSeqNr());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!it.value().first.contains(m_state)) {
|
2013-06-18 18:12:34 +02:00
|
|
|
handleUnexpectedPacket();
|
|
|
|
|
return;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
|
|
|
|
(this->*it.value().second)();
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleKeyExchangeInitPacket()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2011-04-19 14:39:32 +02:00
|
|
|
if (m_keyExchangeState != NoKeyExchange
|
|
|
|
|
&& m_keyExchangeState != KexInitSent) {
|
2011-04-19 10:57:12 +02:00
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Unexpected packet.", tr("Unexpected packet of type %1.")
|
|
|
|
|
.arg(m_incomingPacket.type()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Server-initiated re-exchange.
|
2011-04-19 14:39:32 +02:00
|
|
|
if (m_keyExchangeState == NoKeyExchange) {
|
2014-11-12 16:50:04 +01:00
|
|
|
m_keyExchange.reset(new SshKeyExchange(m_connParams, m_sendFacility));
|
2011-04-19 10:57:12 +02:00
|
|
|
m_keyExchange->sendKexInitPacket(m_serverId);
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
// If the server sends a guessed packet, the guess must be wrong,
|
2011-04-19 14:20:25 +02:00
|
|
|
// because the algorithms we support require us to initiate the
|
2010-07-12 09:33:22 +02:00
|
|
|
// key exchange.
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (m_keyExchange->sendDhInitPacket(m_incomingPacket))
|
2010-07-12 09:33:22 +02:00
|
|
|
m_ignoreNextPacket = true;
|
2011-04-19 10:57:12 +02:00
|
|
|
|
2011-04-19 14:39:32 +02:00
|
|
|
m_keyExchangeState = DhInitSent;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleKeyExchangeReplyPacket()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2011-04-19 14:39:32 +02:00
|
|
|
if (m_keyExchangeState != DhInitSent) {
|
2011-04-19 10:57:12 +02:00
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Unexpected packet.", tr("Unexpected packet of type %1.")
|
|
|
|
|
.arg(m_incomingPacket.type()));
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
m_keyExchange->sendNewKeysPacket(m_incomingPacket,
|
|
|
|
|
ClientId.left(ClientId.size() - 2));
|
|
|
|
|
m_sendFacility.recreateKeys(*m_keyExchange);
|
2011-04-19 14:39:32 +02:00
|
|
|
m_keyExchangeState = NewKeysSent;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleNewKeysPacket()
|
2010-05-10 11:01:56 +02:00
|
|
|
{
|
2011-04-19 14:39:32 +02:00
|
|
|
if (m_keyExchangeState != NewKeysSent) {
|
2011-04-19 10:57:12 +02:00
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Unexpected packet.", tr("Unexpected packet of type %1.")
|
|
|
|
|
.arg(m_incomingPacket.type()));
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
m_incomingPacket.recreateKeys(*m_keyExchange);
|
|
|
|
|
m_keyExchange.reset();
|
2011-04-19 10:57:12 +02:00
|
|
|
m_keyExchangeState = NoKeyExchange;
|
|
|
|
|
|
|
|
|
|
if (m_state == SocketConnected) {
|
|
|
|
|
m_sendFacility.sendUserAuthServiceRequestPacket();
|
|
|
|
|
m_state = UserAuthServiceRequested;
|
|
|
|
|
}
|
2010-05-10 11:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleServiceAcceptPacket()
|
|
|
|
|
{
|
2013-06-18 18:12:34 +02:00
|
|
|
switch (m_connParams.authenticationType) {
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods:
|
|
|
|
|
m_triedAllPasswordBasedMethods = false;
|
|
|
|
|
// Fall-through.
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypePassword:
|
|
|
|
|
m_sendFacility.sendUserAuthByPasswordRequestPacket(m_connParams.userName.toUtf8(),
|
|
|
|
|
SshCapabilities::SshConnectionService, m_connParams.password.toUtf8());
|
|
|
|
|
break;
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypeKeyboardInteractive:
|
|
|
|
|
m_sendFacility.sendUserAuthByKeyboardInteractiveRequestPacket(m_connParams.userName.toUtf8(),
|
|
|
|
|
SshCapabilities::SshConnectionService);
|
|
|
|
|
break;
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypePublicKey:
|
2016-07-20 18:04:56 +02:00
|
|
|
authenticateWithPublicKey();
|
|
|
|
|
break;
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypeAgent:
|
|
|
|
|
if (SshAgent::publicKeys().isEmpty()) {
|
|
|
|
|
if (m_agentKeysUpToDate)
|
|
|
|
|
throw SshClientException(SshAuthenticationError, tr("ssh-agent has no keys."));
|
|
|
|
|
qCDebug(sshLog) << "agent has no keys yet, waiting";
|
|
|
|
|
m_state = WaitingForAgentKeys;
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
tryAllAgentKeys();
|
|
|
|
|
}
|
2013-06-18 18:12:34 +02:00
|
|
|
break;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
|
|
|
|
m_state = UserAuthRequested;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handlePasswordExpiredPacket()
|
2010-05-20 16:02:58 +02:00
|
|
|
{
|
2013-06-18 18:12:34 +02:00
|
|
|
if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
|
|
|
|
|
&& m_triedAllPasswordBasedMethods) {
|
|
|
|
|
// This means we just tried to authorize via "keyboard-interactive", in which case
|
|
|
|
|
// this type of packet is not allowed.
|
|
|
|
|
handleUnexpectedPacket();
|
|
|
|
|
return;
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
|
|
|
|
throw SshClientException(SshAuthenticationError, tr("Password expired."));
|
2010-05-20 16:02:58 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-18 18:12:34 +02:00
|
|
|
void SshConnectionPrivate::handleUserAuthInfoRequestPacket()
|
|
|
|
|
{
|
|
|
|
|
if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
|
|
|
|
|
&& !m_triedAllPasswordBasedMethods) {
|
|
|
|
|
// This means we just tried to authorize via "password", in which case
|
|
|
|
|
// this type of packet is not allowed.
|
|
|
|
|
handleUnexpectedPacket();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const SshUserAuthInfoRequestPacket requestPacket
|
|
|
|
|
= m_incomingPacket.extractUserAuthInfoRequest();
|
|
|
|
|
QStringList responses;
|
|
|
|
|
responses.reserve(requestPacket.prompts.count());
|
|
|
|
|
|
|
|
|
|
// Not very interactive, admittedly, but we don't want to be for now.
|
|
|
|
|
for (int i = 0; i < requestPacket.prompts.count(); ++i)
|
|
|
|
|
responses << m_connParams.password;
|
|
|
|
|
m_sendFacility.sendUserAuthInfoResponsePacket(responses);
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleUserAuthBannerPacket()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
emit dataAvailable(m_incomingPacket.extractUserAuthBanner().message);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-18 18:12:34 +02:00
|
|
|
void SshConnectionPrivate::handleUnexpectedPacket()
|
|
|
|
|
{
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
|
|
|
"Unexpected packet.", tr("Unexpected packet of type %1.")
|
|
|
|
|
.arg(m_incomingPacket.type()));
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleGlobalRequest()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_sendFacility.sendRequestFailurePacket();
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleUserAuthSuccessPacket()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_state = ConnectionEstablished;
|
|
|
|
|
m_timeoutTimer.stop();
|
|
|
|
|
emit connected();
|
2011-02-11 14:00:54 +01:00
|
|
|
m_lastInvalidMsgSeqNr = InvalidSeqNr;
|
2016-06-07 22:04:26 +03:00
|
|
|
connect(&m_keepAliveTimer, &QTimer::timeout, this, &SshConnectionPrivate::sendKeepAlivePacket);
|
2011-02-11 14:00:54 +01:00
|
|
|
m_keepAliveTimer.start();
|
2010-07-12 09:33:22 +02:00
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleUserAuthFailurePacket()
|
|
|
|
|
{
|
2016-07-20 18:04:56 +02:00
|
|
|
if (!m_pendingKeyChecks.isEmpty()) {
|
|
|
|
|
const QByteArray key = m_pendingKeyChecks.dequeue();
|
|
|
|
|
SshAgent::removeDataToSign(key, tokenForAgent());
|
|
|
|
|
qCDebug(sshLog) << "server rejected one of the keys supplied by the agent,"
|
|
|
|
|
<< m_pendingKeyChecks.count() << "keys remaining";
|
|
|
|
|
if (m_pendingKeyChecks.isEmpty() && m_agentKeyToUse.isEmpty()) {
|
|
|
|
|
throw SshClientException(SshAuthenticationError, tr("The server rejected all keys "
|
|
|
|
|
"known to the ssh-agent."));
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-18 18:12:34 +02:00
|
|
|
// TODO: Evaluate "authentications that can continue" field and act on it.
|
|
|
|
|
if (m_connParams.authenticationType
|
|
|
|
|
== SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods
|
|
|
|
|
&& !m_triedAllPasswordBasedMethods) {
|
|
|
|
|
m_triedAllPasswordBasedMethods = true;
|
|
|
|
|
m_sendFacility.sendUserAuthByKeyboardInteractiveRequestPacket(
|
|
|
|
|
m_connParams.userName.toUtf8(),
|
|
|
|
|
SshCapabilities::SshConnectionService);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-17 10:47:36 +02:00
|
|
|
m_timeoutTimer.stop();
|
2016-07-20 18:04:56 +02:00
|
|
|
QString errorMsg;
|
|
|
|
|
switch (m_connParams.authenticationType) {
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypePublicKey:
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypeAgent:
|
|
|
|
|
errorMsg = tr("Server rejected key.");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
errorMsg = tr("Server rejected password.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-07-12 09:33:22 +02:00
|
|
|
throw SshClientException(SshAuthenticationError, errorMsg);
|
|
|
|
|
}
|
2016-07-20 18:04:56 +02:00
|
|
|
|
|
|
|
|
void SshConnectionPrivate::handleUserAuthKeyOkPacket()
|
|
|
|
|
{
|
|
|
|
|
const SshUserAuthPkOkPacket &msg = m_incomingPacket.extractUserAuthPkOk();
|
|
|
|
|
qCDebug(sshLog) << "server accepted key of type" << msg.algoName;
|
|
|
|
|
|
|
|
|
|
if (m_pendingKeyChecks.isEmpty()) {
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected packet",
|
|
|
|
|
tr("Server sent unexpected SSH_MSG_USERAUTH_PK_OK packet."));
|
|
|
|
|
}
|
|
|
|
|
const QByteArray key = m_pendingKeyChecks.dequeue();
|
|
|
|
|
if (key != msg.keyBlob) {
|
|
|
|
|
// The server must answer the requests in the order we sent them.
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected packet content",
|
|
|
|
|
tr("Server sent unexpected key in SSH_MSG_USERAUTH_PK_OK packet."));
|
|
|
|
|
}
|
|
|
|
|
const uint token = tokenForAgent();
|
|
|
|
|
if (!m_agentKeyToUse.isEmpty()) {
|
|
|
|
|
qCDebug(sshLog) << "another key has already been accepted, ignoring this one";
|
|
|
|
|
SshAgent::removeDataToSign(key, token);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_agentKeyToUse = key;
|
|
|
|
|
qCDebug(sshLog) << "requesting signature from agent";
|
|
|
|
|
SshAgent::requestSignature(key, token);
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleDebugPacket()
|
|
|
|
|
{
|
|
|
|
|
const SshDebug &msg = m_incomingPacket.extractDebug();
|
|
|
|
|
if (msg.display)
|
|
|
|
|
emit dataAvailable(msg.message);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2011-02-11 14:00:54 +01:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelRequest()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_channelManager->handleChannelRequest(m_incomingPacket);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelOpen()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_channelManager->handleChannelOpen(m_incomingPacket);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelOpenFailure()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_channelManager->handleChannelOpenFailure(m_incomingPacket);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelOpenConfirmation()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleChannelOpenConfirmation(m_incomingPacket);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelSuccess()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_channelManager->handleChannelSuccess(m_incomingPacket);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelFailure()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleChannelFailure(m_incomingPacket);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelWindowAdjust()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleChannelWindowAdjust(m_incomingPacket);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelData()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_channelManager->handleChannelData(m_incomingPacket);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelExtendedData()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleChannelExtendedData(m_incomingPacket);
|
|
|
|
|
}
|
2010-04-26 11:43:25 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelEof()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleChannelEof(m_incomingPacket);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleChannelClose()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
m_channelManager->handleChannelClose(m_incomingPacket);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleDisconnect()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
const SshDisconnect msg = m_incomingPacket.extractDisconnect();
|
|
|
|
|
throw SshServerException(SSH_DISCONNECT_CONNECTION_LOST,
|
|
|
|
|
"", tr("Server closed connection: %1").arg(msg.description));
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:57:03 +02:00
|
|
|
void SshConnectionPrivate::handleRequestSuccess()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleRequestSuccess(m_incomingPacket);
|
|
|
|
|
}
|
2011-02-11 14:00:54 +01:00
|
|
|
|
2016-03-31 18:57:03 +02:00
|
|
|
void SshConnectionPrivate::handleRequestFailure()
|
|
|
|
|
{
|
|
|
|
|
m_channelManager->handleRequestFailure(m_incomingPacket);
|
|
|
|
|
}
|
2011-02-11 14:00:54 +01:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::sendData(const QByteArray &data)
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-08-16 12:40:55 +02:00
|
|
|
if (canUseSocket())
|
|
|
|
|
m_socket->write(data);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-20 18:04:56 +02:00
|
|
|
uint SshConnectionPrivate::tokenForAgent() const
|
|
|
|
|
{
|
|
|
|
|
return qHash(m_sendFacility.sessionId());
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleSocketDisconnected()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshClosedByServerError,
|
|
|
|
|
"Connection closed unexpectedly.",
|
|
|
|
|
tr("Connection closed unexpectedly."));
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleSocketError()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
if (m_error == SshNoError) {
|
|
|
|
|
closeConnection(SSH_DISCONNECT_CONNECTION_LOST, SshSocketError,
|
|
|
|
|
"Network error", m_socket->errorString());
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
void SshConnectionPrivate::handleTimeout()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2016-07-20 18:04:56 +02:00
|
|
|
const QString errorMessage = m_state == WaitingForAgentKeys
|
|
|
|
|
? tr("Timeout waiting for keys from ssh-agent.")
|
|
|
|
|
: tr("Timeout waiting for reply from server.");
|
|
|
|
|
closeConnection(SSH_DISCONNECT_BY_APPLICATION, SshTimeoutError, "", errorMessage);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2011-02-11 14:00:54 +01:00
|
|
|
void SshConnectionPrivate::sendKeepAlivePacket()
|
|
|
|
|
{
|
2011-04-28 11:12:34 +02:00
|
|
|
// This type of message is not allowed during key exchange.
|
|
|
|
|
if (m_keyExchangeState != NoKeyExchange) {
|
|
|
|
|
m_keepAliveTimer.start();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-11 14:00:54 +01:00
|
|
|
Q_ASSERT(m_lastInvalidMsgSeqNr == InvalidSeqNr);
|
|
|
|
|
m_lastInvalidMsgSeqNr = m_sendFacility.nextClientSeqNr();
|
|
|
|
|
m_sendFacility.sendInvalidPacket();
|
2011-06-28 18:08:12 +02:00
|
|
|
m_timeoutTimer.start();
|
2011-02-11 14:00:54 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-20 18:04:56 +02:00
|
|
|
void SshConnectionPrivate::handleAgentKeysUpdated()
|
|
|
|
|
{
|
|
|
|
|
m_agentKeysUpToDate = true;
|
|
|
|
|
if (m_state == WaitingForAgentKeys) {
|
|
|
|
|
m_state = UserAuthRequested;
|
|
|
|
|
tryAllAgentKeys();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SshConnectionPrivate::handleSignatureFromAgent(const QByteArray &key,
|
|
|
|
|
const QByteArray &signature, uint token)
|
|
|
|
|
{
|
|
|
|
|
if (token != tokenForAgent()) {
|
|
|
|
|
qCDebug(sshLog) << "signature is for different connection, ignoring";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QSSH_ASSERT(key == m_agentKeyToUse);
|
|
|
|
|
m_agentSignature = signature;
|
|
|
|
|
authenticateWithPublicKey();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SshConnectionPrivate::tryAllAgentKeys()
|
|
|
|
|
{
|
|
|
|
|
const QList<QByteArray> &keys = SshAgent::publicKeys();
|
|
|
|
|
if (keys.isEmpty())
|
|
|
|
|
throw SshClientException(SshAuthenticationError, tr("ssh-agent has no keys."));
|
|
|
|
|
qCDebug(sshLog) << "trying authentication with" << keys.count()
|
|
|
|
|
<< "public keys received from agent";
|
|
|
|
|
foreach (const QByteArray &key, keys) {
|
|
|
|
|
m_sendFacility.sendQueryPublicKeyPacket(m_connParams.userName.toUtf8(),
|
|
|
|
|
SshCapabilities::SshConnectionService, key);
|
|
|
|
|
m_pendingKeyChecks.enqueue(key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SshConnectionPrivate::authenticateWithPublicKey()
|
|
|
|
|
{
|
|
|
|
|
qCDebug(sshLog) << "sending actual authentication request";
|
|
|
|
|
|
|
|
|
|
QByteArray key;
|
|
|
|
|
QByteArray signature;
|
|
|
|
|
if (m_connParams.authenticationType == SshConnectionParameters::AuthenticationTypeAgent) {
|
|
|
|
|
// Agent is not needed anymore after this point.
|
|
|
|
|
disconnect(&SshAgent::instance(), 0, this, 0);
|
|
|
|
|
|
|
|
|
|
key = m_agentKeyToUse;
|
|
|
|
|
signature = m_agentSignature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_sendFacility.sendUserAuthByPublicKeyRequestPacket(m_connParams.userName.toUtf8(),
|
|
|
|
|
SshCapabilities::SshConnectionService, key, signature);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SshConnectionPrivate::setAgentError()
|
|
|
|
|
{
|
|
|
|
|
m_error = SshAgentError;
|
|
|
|
|
m_errorString = SshAgent::errorString();
|
|
|
|
|
emit error(m_error);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-09 12:07:35 +01:00
|
|
|
void SshConnectionPrivate::connectToHost()
|
2010-07-12 09:33:22 +02:00
|
|
|
{
|
2012-05-18 10:49:35 +02:00
|
|
|
QSSH_ASSERT_AND_RETURN(m_state == SocketUnconnected);
|
2011-07-05 18:01:58 +02:00
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
m_incomingData.clear();
|
|
|
|
|
m_incomingPacket.reset();
|
|
|
|
|
m_sendFacility.reset();
|
|
|
|
|
m_error = SshNoError;
|
|
|
|
|
m_ignoreNextPacket = false;
|
|
|
|
|
m_errorString.clear();
|
2012-09-26 10:57:19 +02:00
|
|
|
m_serverId.clear();
|
|
|
|
|
m_serverHasSentDataBeforeId = false;
|
2016-07-20 18:04:56 +02:00
|
|
|
m_agentSignature.clear();
|
|
|
|
|
m_agentKeysUpToDate = false;
|
|
|
|
|
m_pendingKeyChecks.clear();
|
|
|
|
|
m_agentKeyToUse.clear();
|
2011-12-02 11:24:39 +01:00
|
|
|
|
2016-07-20 18:04:56 +02:00
|
|
|
switch (m_connParams.authenticationType) {
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypePublicKey:
|
|
|
|
|
try {
|
2011-12-02 11:24:39 +01:00
|
|
|
createPrivateKey();
|
2016-07-20 18:04:56 +02:00
|
|
|
break;
|
|
|
|
|
} catch (const SshClientException &ex) {
|
|
|
|
|
m_error = ex.error;
|
|
|
|
|
m_errorString = ex.errorString;
|
|
|
|
|
emit error(m_error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case SshConnectionParameters::AuthenticationTypeAgent:
|
|
|
|
|
if (SshAgent::hasError()) {
|
|
|
|
|
setAgentError();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
connect(&SshAgent::instance(), &SshAgent::errorOccurred,
|
|
|
|
|
this, &SshConnectionPrivate::setAgentError);
|
|
|
|
|
connect(&SshAgent::instance(), &SshAgent::keysUpdated,
|
|
|
|
|
this, &SshConnectionPrivate::handleAgentKeysUpdated);
|
|
|
|
|
SshAgent::refreshKeys();
|
|
|
|
|
connect(&SshAgent::instance(), &SshAgent::signatureAvailable,
|
|
|
|
|
this, &SshConnectionPrivate::handleSignatureFromAgent);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2011-12-02 11:24:39 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 22:04:26 +03:00
|
|
|
connect(m_socket, &QAbstractSocket::connected,
|
|
|
|
|
this, &SshConnectionPrivate::handleSocketConnected);
|
|
|
|
|
connect(m_socket, &QIODevice::readyRead,
|
|
|
|
|
this, &SshConnectionPrivate::handleIncomingData);
|
|
|
|
|
connect(m_socket,
|
|
|
|
|
static_cast<void (QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
|
|
|
|
|
this, &SshConnectionPrivate::handleSocketError);
|
|
|
|
|
connect(m_socket, &QAbstractSocket::disconnected,
|
|
|
|
|
this, &SshConnectionPrivate::handleSocketDisconnected);
|
|
|
|
|
connect(&m_timeoutTimer, &QTimer::timeout, this, &SshConnectionPrivate::handleTimeout);
|
2010-07-12 09:33:22 +02:00
|
|
|
m_state = SocketConnecting;
|
2011-04-19 10:57:12 +02:00
|
|
|
m_keyExchangeState = NoKeyExchange;
|
2011-06-28 18:08:12 +02:00
|
|
|
m_timeoutTimer.start();
|
2011-03-09 12:07:35 +01:00
|
|
|
m_socket->connectToHost(m_connParams.host, m_connParams.port);
|
2010-05-20 16:02:58 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
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);
|
2010-08-16 22:10:34 +02:00
|
|
|
disconnect(&m_timeoutTimer, 0, this, 0);
|
2011-02-11 14:00:54 +01:00
|
|
|
m_keepAliveTimer.stop();
|
|
|
|
|
disconnect(&m_keepAliveTimer, 0, this, 0);
|
2010-07-12 09:33:22 +02:00
|
|
|
try {
|
2012-08-17 17:33:06 +02:00
|
|
|
m_channelManager->closeAllChannels(SshChannelManager::CloseAllAndReset);
|
2010-07-12 09:33:22 +02:00
|
|
|
m_sendFacility.sendDisconnectPacket(sshError, serverErrorString);
|
2017-02-22 12:36:11 +01:00
|
|
|
} catch (...) {} // Nothing sensible to be done here.
|
2010-07-12 09:33:22 +02:00
|
|
|
if (m_error != SshNoError)
|
|
|
|
|
emit error(userError);
|
|
|
|
|
if (m_state == ConnectionEstablished)
|
|
|
|
|
emit disconnected();
|
2010-08-16 12:40:55 +02:00
|
|
|
if (canUseSocket())
|
|
|
|
|
m_socket->disconnectFromHost();
|
2010-07-12 09:33:22 +02:00
|
|
|
m_state = SocketUnconnected;
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-16 12:40:55 +02:00
|
|
|
bool SshConnectionPrivate::canUseSocket() const
|
|
|
|
|
{
|
|
|
|
|
return m_socket->isValid()
|
2011-12-02 11:24:39 +01:00
|
|
|
&& m_socket->state() == QAbstractSocket::ConnectedState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SshConnectionPrivate::createPrivateKey()
|
|
|
|
|
{
|
|
|
|
|
if (m_connParams.privateKeyFile.isEmpty())
|
|
|
|
|
throw SshClientException(SshKeyFileError, tr("No private key file given."));
|
2012-05-18 10:49:35 +02:00
|
|
|
QFile keyFile(m_connParams.privateKeyFile);
|
|
|
|
|
if (!keyFile.open(QIODevice::ReadOnly)) {
|
2011-12-02 11:24:39 +01:00
|
|
|
throw SshClientException(SshKeyFileError,
|
2012-05-18 10:49:35 +02:00
|
|
|
tr("Private key file error: %1").arg(keyFile.errorString()));
|
|
|
|
|
}
|
|
|
|
|
m_sendFacility.createAuthenticationKey(keyFile.readAll());
|
2010-08-16 12:40:55 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
QSharedPointer<SshRemoteProcess> SshConnectionPrivate::createRemoteProcess(const QByteArray &command)
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
return m_channelManager->createRemoteProcess(command);
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2011-07-26 18:13:11 +02:00
|
|
|
QSharedPointer<SshRemoteProcess> SshConnectionPrivate::createRemoteShell()
|
|
|
|
|
{
|
|
|
|
|
return m_channelManager->createRemoteShell();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
|
2010-04-26 11:43:25 +02:00
|
|
|
{
|
2010-07-12 09:33:22 +02:00
|
|
|
return m_channelManager->createSftpChannel();
|
2010-04-26 11:43:25 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:57:03 +02:00
|
|
|
SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createDirectTunnel(const QString &originatingHost,
|
2015-04-14 15:47:55 +02:00
|
|
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
2012-06-19 13:03:48 +02:00
|
|
|
{
|
2016-03-31 18:57:03 +02:00
|
|
|
return m_channelManager->createDirectTunnel(originatingHost, originatingPort, remoteHost,
|
|
|
|
|
remotePort);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SshTcpIpForwardServer::Ptr SshConnectionPrivate::createForwardServer(const QString &bindAddress,
|
|
|
|
|
quint16 bindPort)
|
|
|
|
|
{
|
|
|
|
|
return m_channelManager->createForwardServer(bindAddress, bindPort);
|
2012-06-19 13:03:48 +02:00
|
|
|
}
|
|
|
|
|
|
2011-02-11 14:00:54 +01:00
|
|
|
const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);
|
|
|
|
|
|
2010-07-12 09:33:22 +02:00
|
|
|
} // namespace Internal
|
2012-05-18 10:49:35 +02:00
|
|
|
} // namespace QSsh
|