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 }