1 /*
2 Copyright (C) 2009-2010 Collabora Ltd <info@collabora.co.uk>
3 @author George Goldberg <george.goldberg@collabora.co.uk>
4 @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
5 Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #include "rfbclient.h"
21 #include "connectiondialog.h"
22 #include "krfbconfig.h"
23 #include "sockethelpers.h"
24 #include "eventsmanager.h"
25 #include <QSocketNotifier>
26 #include <poll.h>
27 #include <strings.h> //for bzero()
28 #include "krfbdebug.h"
29
30 struct RfbClient::Private
31 {
PrivateRfbClient::Private32 Private(rfbClientPtr client) :
33 controlEnabled(KrfbConfig::allowDesktopControl()),
34 client(client)
35 {}
36
37 bool controlEnabled;
38 rfbClientPtr client;
39 QSocketNotifier *notifier;
40 QSharedPointer<EventHandler> eventHandler;
41 QString remoteAddressString;
42 };
43
RfbClient(rfbClientPtr client,QObject * parent)44 RfbClient::RfbClient(rfbClientPtr client, QObject* parent)
45 : QObject(parent), d(new Private(client))
46 {
47 d->remoteAddressString = peerAddress(d->client->sock) + QLatin1Char(':') +
48 QString::number(peerPort(d->client->sock));
49
50 d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this);
51 d->notifier->setEnabled(false);
52 connect(d->notifier, &QSocketNotifier::activated, this, &RfbClient::onSocketActivated);
53
54 d->eventHandler = EventsManager::instance()->eventHandler();
55 }
56
~RfbClient()57 RfbClient::~RfbClient()
58 {
59 //qDebug();
60 delete d;
61 }
62
name() const63 QString RfbClient::name() const
64 {
65 return d->remoteAddressString;
66 }
67
68 //static
controlCanBeEnabled()69 bool RfbClient::controlCanBeEnabled()
70 {
71 return KrfbConfig::allowDesktopControl();
72 }
73
controlEnabled() const74 bool RfbClient::controlEnabled() const
75 {
76 return d->controlEnabled;
77 }
78
setControlEnabled(bool enabled)79 void RfbClient::setControlEnabled(bool enabled)
80 {
81 if (controlCanBeEnabled() && d->controlEnabled != enabled) {
82 d->controlEnabled = enabled;
83 Q_EMIT controlEnabledChanged(enabled);
84 }
85 }
86
isOnHold() const87 bool RfbClient::isOnHold() const
88 {
89 return d->client->onHold ? true : false;
90 }
91
setOnHold(bool onHold)92 void RfbClient::setOnHold(bool onHold)
93 {
94 if (isOnHold() != onHold) {
95 d->client->onHold = onHold;
96 d->notifier->setEnabled(!onHold);
97 Q_EMIT holdStatusChanged(onHold);
98 }
99 }
100
closeConnection()101 void RfbClient::closeConnection()
102 {
103 d->notifier->setEnabled(false);
104 rfbCloseClient(d->client);
105 rfbClientConnectionGone(d->client);
106 }
107
getRfbClientPtr()108 rfbClientPtr RfbClient::getRfbClientPtr()
109 {
110 return d->client;
111 }
112
handleKeyboardEvent(bool down,rfbKeySym keySym)113 void RfbClient::handleKeyboardEvent(bool down, rfbKeySym keySym)
114 {
115 if (d->controlEnabled) {
116 d->eventHandler->handleKeyboard(down, keySym);
117 }
118 }
119
handleMouseEvent(int buttonMask,int x,int y)120 void RfbClient::handleMouseEvent(int buttonMask, int x, int y)
121 {
122 if (d->controlEnabled) {
123 d->eventHandler->handlePointer(buttonMask, x, y);
124 }
125 }
126
onSocketActivated()127 void RfbClient::onSocketActivated()
128 {
129 //Process not only one, but all pending messages.
130 //poll() idea/code copied from vino:
131 // Copyright (C) 2003 Sun Microsystems, Inc.
132 // License: GPL v2 or later
133 struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 };
134
135 while(poll(&pollfd, 1, 0) == 1) {
136 rfbProcessClientMessage(d->client);
137
138 //This is how we handle disconnection.
139 //if rfbProcessClientMessage() finds out that it can't read the socket,
140 //it closes it and sets it to -1. So, we just have to check this here
141 //and call rfbClientConnectionGone() if necessary. This will call
142 //the clientGoneHook which in turn will remove this RfbClient instance
143 //from the server manager and will call deleteLater() to delete it
144 if (d->client->sock == -1) {
145 //qDebug() << "disconnected from socket signal";
146 d->notifier->setEnabled(false);
147 rfbClientConnectionGone(d->client);
148 break;
149 }
150 }
151 }
152
update()153 void RfbClient::update()
154 {
155 rfbUpdateClient(d->client);
156
157 //This is how we handle disconnection.
158 //if rfbUpdateClient() finds out that it can't write to the socket,
159 //it closes it and sets it to -1. So, we just have to check this here
160 //and call rfbClientConnectionGone() if necessary. This will call
161 //the clientGoneHook which in turn will remove this RfbClient instance
162 //from the server manager and will call deleteLater() to delete it
163 if (d->client->sock == -1) {
164 //qDebug() << "disconnected during update";
165 d->notifier->setEnabled(false);
166 rfbClientConnectionGone(d->client);
167 }
168 }
169
170 //*************
171
PendingRfbClient(rfbClientPtr client,QObject * parent)172 PendingRfbClient::PendingRfbClient(rfbClientPtr client, QObject *parent)
173 : QObject(parent), m_rfbClient(client)
174 , m_notifier(new QSocketNotifier(client->sock, QSocketNotifier::Read, this))
175 {
176 m_rfbClient->clientData = this;
177
178 m_notifier->setEnabled(true);
179 connect(m_notifier, &QSocketNotifier::activated,
180 this, &PendingRfbClient::onSocketActivated);
181 }
182
~PendingRfbClient()183 PendingRfbClient::~PendingRfbClient()
184 {}
185
accept(RfbClient * newClient)186 void PendingRfbClient::accept(RfbClient *newClient)
187 {
188 //qDebug() << "accepted connection";
189
190 m_rfbClient->clientData = newClient;
191 newClient->setOnHold(false);
192
193 Q_EMIT finished(newClient);
194 deleteLater();
195 }
196
clientGoneHookNoop(rfbClientPtr cl)197 static void clientGoneHookNoop(rfbClientPtr cl) { Q_UNUSED(cl); }
198
reject()199 void PendingRfbClient::reject()
200 {
201 //qDebug() << "refused connection";
202
203 //override the clientGoneHook that was previously set by RfbServer
204 m_rfbClient->clientGoneHook = clientGoneHookNoop;
205 rfbCloseClient(m_rfbClient);
206 rfbClientConnectionGone(m_rfbClient);
207
208 Q_EMIT finished(nullptr);
209 deleteLater();
210 }
211
checkPassword(const QByteArray & encryptedPassword)212 bool PendingRfbClient::checkPassword(const QByteArray & encryptedPassword)
213 {
214 Q_UNUSED(encryptedPassword);
215
216 return m_rfbClient->screen->authPasswdData == (void*)nullptr;
217 }
218
vncAuthCheckPassword(const QByteArray & password,const QByteArray & encryptedPassword) const219 bool PendingRfbClient::vncAuthCheckPassword(const QByteArray& password, const QByteArray& encryptedPassword) const
220 {
221 if (password.isEmpty() && encryptedPassword.isEmpty()) {
222 return true;
223 }
224
225 char passwd[MAXPWLEN+1]; // +1 to make sure there's a nullptr at the end
226 unsigned char challenge[CHALLENGESIZE];
227
228 memcpy(challenge, m_rfbClient->authChallenge, CHALLENGESIZE);
229 memset(passwd, 0, sizeof(passwd));
230
231 if (!password.isEmpty()) {
232 strncpy(passwd, password.constData(),
233 (MAXPWLEN <= password.size()) ? MAXPWLEN : password.size());
234 }
235
236 rfbEncryptBytes(challenge, passwd);
237 return memcmp(challenge, encryptedPassword.constData(), encryptedPassword.size()) == 0;
238 }
239
onSocketActivated()240 void PendingRfbClient::onSocketActivated()
241 {
242 //Process not only one, but all pending messages.
243 //poll() idea/code copied from vino:
244 // Copyright (C) 2003 Sun Microsystems, Inc.
245 // License: GPL v2 or later
246 struct pollfd pollfd = { m_rfbClient->sock, POLLIN|POLLPRI, 0 };
247
248 while(poll(&pollfd, 1, 0) == 1) {
249 if(m_rfbClient->state == rfbClientRec::RFB_INITIALISATION) {
250 m_notifier->setEnabled(false);
251 //Client is Authenticated
252 processNewClient();
253 break;
254 }
255 rfbProcessClientMessage(m_rfbClient);
256
257 //This is how we handle disconnection.
258 //if rfbProcessClientMessage() finds out that it can't read the socket,
259 //it closes it and sets it to -1. So, we just have to check this here
260 //and call rfbClientConnectionGone() if necessary. This will call
261 //the clientGoneHook which in turn will remove this RfbClient instance
262 //from the server manager and will call deleteLater() to delete it
263 if (m_rfbClient->sock == -1) {
264 qCDebug(KRFB) << "disconnected from socket signal";
265 m_notifier->setEnabled(false);
266 rfbClientConnectionGone(m_rfbClient);
267 break;
268 }
269 }
270 }
271