File indexing completed on 2024-04-21 04:58:41

0001 /*
0002     Copyright (C) 2009-2010 Collabora Ltd <info@collabora.co.uk>
0003       @author George Goldberg <george.goldberg@collabora.co.uk>
0004       @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
0005     Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
0006 
0007     This program is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU General Public
0009     License as published by the Free Software Foundation; either
0010     version 2 of the License, or (at your option) any later version.
0011 
0012     This program is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015     GNU General Public License for more details.
0016 
0017     You should have received a copy of the GNU Lesser General Public License
0018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 #include "rfbclient.h"
0021 #include "connectiondialog.h"
0022 #include "krfbconfig.h"
0023 #include "sockethelpers.h"
0024 #include "eventsmanager.h"
0025 #include <QSocketNotifier>
0026 #include <poll.h>
0027 #include <strings.h> //for bzero()
0028 #include "krfbdebug.h"
0029 
0030 struct RfbClient::Private
0031 {
0032     Private(rfbClientPtr client) :
0033         controlEnabled(KrfbConfig::allowDesktopControl()),
0034         client(client)
0035     {}
0036 
0037     bool controlEnabled;
0038     rfbClientPtr client;
0039     QSocketNotifier *notifier;
0040     QSharedPointer<EventHandler> eventHandler;
0041     QString remoteAddressString;
0042 };
0043 
0044 RfbClient::RfbClient(rfbClientPtr client, QObject* parent)
0045     : QObject(parent), d(new Private(client))
0046 {
0047     d->remoteAddressString = peerAddress(d->client->sock) + QLatin1Char(':') +
0048                              QString::number(peerPort(d->client->sock));
0049 
0050     d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this);
0051     d->notifier->setEnabled(false);
0052     connect(d->notifier, &QSocketNotifier::activated, this, &RfbClient::onSocketActivated);
0053 
0054     d->eventHandler = EventsManager::instance()->eventHandler();
0055 }
0056 
0057 RfbClient::~RfbClient()
0058 {
0059     //qDebug();
0060     delete d;
0061 }
0062 
0063 QString RfbClient::name() const
0064 {
0065     return d->remoteAddressString;
0066 }
0067 
0068 //static
0069 bool RfbClient::controlCanBeEnabled()
0070 {
0071     return KrfbConfig::allowDesktopControl();
0072 }
0073 
0074 bool RfbClient::controlEnabled() const
0075 {
0076     return d->controlEnabled;
0077 }
0078 
0079 void RfbClient::setControlEnabled(bool enabled)
0080 {
0081     if (controlCanBeEnabled() && d->controlEnabled != enabled) {
0082         d->controlEnabled = enabled;
0083         Q_EMIT controlEnabledChanged(enabled);
0084     }
0085 }
0086 
0087 bool RfbClient::isOnHold() const
0088 {
0089     return d->client->onHold ? true : false;
0090 }
0091 
0092 void RfbClient::setOnHold(bool onHold)
0093 {
0094     if (isOnHold() != onHold) {
0095         d->client->onHold = onHold;
0096         d->notifier->setEnabled(!onHold);
0097         Q_EMIT holdStatusChanged(onHold);
0098     }
0099 }
0100 
0101 void RfbClient::closeConnection()
0102 {
0103     d->notifier->setEnabled(false);
0104     rfbCloseClient(d->client);
0105     rfbClientConnectionGone(d->client);
0106 }
0107 
0108 rfbClientPtr RfbClient::getRfbClientPtr()
0109 {
0110     return d->client;
0111 }
0112 
0113 void RfbClient::handleKeyboardEvent(bool down, rfbKeySym keySym)
0114 {
0115     if (d->controlEnabled) {
0116         d->eventHandler->handleKeyboard(down, keySym);
0117     }
0118 }
0119 
0120 void RfbClient::handleMouseEvent(int buttonMask, int x, int y)
0121 {
0122     if (d->controlEnabled) {
0123         d->eventHandler->handlePointer(buttonMask, x, y);
0124     }
0125 }
0126 
0127 void RfbClient::onSocketActivated()
0128 {
0129     //Process not only one, but all pending messages.
0130     //poll() idea/code copied from vino:
0131     // Copyright (C) 2003 Sun Microsystems, Inc.
0132     // License: GPL v2 or later
0133     struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 };
0134 
0135     while(poll(&pollfd, 1, 0) == 1) {
0136         rfbProcessClientMessage(d->client);
0137 
0138         //This is how we handle disconnection.
0139         //if rfbProcessClientMessage() finds out that it can't read the socket,
0140         //it closes it and sets it to -1. So, we just have to check this here
0141         //and call rfbClientConnectionGone() if necessary. This will call
0142         //the clientGoneHook which in turn will remove this RfbClient instance
0143         //from the server manager and will call deleteLater() to delete it
0144         if (d->client->sock == -1) {
0145             //qDebug() << "disconnected from socket signal";
0146             d->notifier->setEnabled(false);
0147             rfbClientConnectionGone(d->client);
0148             break;
0149         }
0150     }
0151 }
0152 
0153 void RfbClient::update()
0154 {
0155     rfbUpdateClient(d->client);
0156 
0157     //This is how we handle disconnection.
0158     //if rfbUpdateClient() finds out that it can't write to the socket,
0159     //it closes it and sets it to -1. So, we just have to check this here
0160     //and call rfbClientConnectionGone() if necessary. This will call
0161     //the clientGoneHook which in turn will remove this RfbClient instance
0162     //from the server manager and will call deleteLater() to delete it
0163     if (d->client->sock == -1) {
0164         //qDebug() << "disconnected during update";
0165         d->notifier->setEnabled(false);
0166         rfbClientConnectionGone(d->client);
0167     }
0168 }
0169 
0170 //*************
0171 
0172 PendingRfbClient::PendingRfbClient(rfbClientPtr client, QObject *parent)
0173     : QObject(parent), m_rfbClient(client)
0174     , m_notifier(new QSocketNotifier(client->sock, QSocketNotifier::Read, this))
0175 {
0176     m_rfbClient->clientData = this;
0177 
0178     m_notifier->setEnabled(true);
0179     connect(m_notifier, &QSocketNotifier::activated,
0180             this, &PendingRfbClient::onSocketActivated);
0181 }
0182 
0183 PendingRfbClient::~PendingRfbClient()
0184 {}
0185 
0186 void PendingRfbClient::accept(RfbClient *newClient)
0187 {
0188     //qDebug() << "accepted connection";
0189 
0190     m_rfbClient->clientData = newClient;
0191     newClient->setOnHold(false);
0192 
0193     Q_EMIT finished(newClient);
0194     deleteLater();
0195 }
0196 
0197 static void clientGoneHookNoop(rfbClientPtr cl) { Q_UNUSED(cl); }
0198 
0199 void PendingRfbClient::reject()
0200 {
0201     //qDebug() << "refused connection";
0202 
0203     //override the clientGoneHook that was previously set by RfbServer
0204     m_rfbClient->clientGoneHook = clientGoneHookNoop;
0205     rfbCloseClient(m_rfbClient);
0206     rfbClientConnectionGone(m_rfbClient);
0207 
0208     Q_EMIT finished(nullptr);
0209     deleteLater();
0210 }
0211 
0212 bool PendingRfbClient::checkPassword(const QByteArray & encryptedPassword)
0213 {
0214     Q_UNUSED(encryptedPassword);
0215 
0216     return m_rfbClient->screen->authPasswdData == (void*)nullptr;
0217 }
0218 
0219 bool PendingRfbClient::vncAuthCheckPassword(const QByteArray& password, const QByteArray& encryptedPassword) const
0220 {
0221     if (password.isEmpty() && encryptedPassword.isEmpty()) {
0222         return true;
0223     }
0224 
0225     char passwd[MAXPWLEN+1]; // +1 to make sure there's a nullptr at the end
0226     unsigned char challenge[CHALLENGESIZE];
0227 
0228     memcpy(challenge, m_rfbClient->authChallenge, CHALLENGESIZE);
0229     memset(passwd, 0, sizeof(passwd));
0230 
0231     if (!password.isEmpty()) {
0232         strncpy(passwd, password.constData(),
0233                 (MAXPWLEN <= password.size()) ? MAXPWLEN : password.size());
0234     }
0235 
0236     rfbEncryptBytes(challenge, passwd);
0237     return memcmp(challenge, encryptedPassword.constData(), encryptedPassword.size()) == 0;
0238 }
0239 
0240 void PendingRfbClient::onSocketActivated()
0241 {
0242     //Process not only one, but all pending messages.
0243     //poll() idea/code copied from vino:
0244     // Copyright (C) 2003 Sun Microsystems, Inc.
0245     // License: GPL v2 or later
0246     struct pollfd pollfd = { m_rfbClient->sock, POLLIN|POLLPRI, 0 };
0247 
0248     while(poll(&pollfd, 1, 0) == 1) {
0249         if(m_rfbClient->state == rfbClientRec::RFB_INITIALISATION) {
0250             m_notifier->setEnabled(false);
0251             //Client is Authenticated
0252             processNewClient();
0253             break;
0254         }
0255         rfbProcessClientMessage(m_rfbClient);
0256 
0257         //This is how we handle disconnection.
0258         //if rfbProcessClientMessage() finds out that it can't read the socket,
0259         //it closes it and sets it to -1. So, we just have to check this here
0260         //and call rfbClientConnectionGone() if necessary. This will call
0261         //the clientGoneHook which in turn will remove this RfbClient instance
0262         //from the server manager and will call deleteLater() to delete it
0263         if (m_rfbClient->sock == -1) {
0264             qCDebug(KRFB) << "disconnected from socket signal";
0265             m_notifier->setEnabled(false);
0266             rfbClientConnectionGone(m_rfbClient);
0267             break;
0268         }
0269     }
0270 }