blob: eeaeafe46190be3beb1bd68ed1c2115897784603 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossmanc754cce2011-11-14 15:44:11 +00002 * Copyright 2011 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19#include <stdio.h>
20#include <string.h>
21#include <rfb/Exception.h>
Adam Tkac5a0caed2010-04-23 13:58:10 +000022#include <rfb/Security.h>
Constantin Kaplinskydafbb012007-04-05 08:43:25 +000023#include <rfb/msgTypes.h>
Pierre Ossmanc754cce2011-11-14 15:44:11 +000024#include <rfb/fenceTypes.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010025#include <rfb/SMsgReader.h>
26#include <rfb/SMsgWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027#include <rfb/SConnection.h>
28#include <rfb/ServerCore.h>
Pierre Ossman48700812014-09-17 17:11:56 +020029#include <rfb/encodings.h>
30#include <rfb/EncodeManager.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000031
32#include <rfb/LogWriter.h>
33
34using namespace rfb;
35
36static LogWriter vlog("SConnection");
37
38// AccessRights values
39const SConnection::AccessRights SConnection::AccessView = 0x0001;
40const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
41const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
42const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
43const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
44const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
45const SConnection::AccessRights SConnection::AccessFull = 0xffff;
46
47
Adam Tkaca6578bf2010-04-23 14:07:41 +000048SConnection::SConnection(bool reverseConnection_)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049 : readyForSetColourMapEntries(false),
50 is(0), os(0), reader_(0), writer_(0),
Adam Tkaca6578bf2010-04-23 14:07:41 +000051 security(0), ssecurity(0), state_(RFBSTATE_UNINITIALISED),
Pierre Ossman48700812014-09-17 17:11:56 +020052 reverseConnection(reverseConnection_),
53 preferredEncoding(encodingRaw)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000054{
55 defaultMajorVersion = 3;
56 defaultMinorVersion = 8;
57 if (rfb::Server::protocol3_3)
58 defaultMinorVersion = 3;
59
60 cp.setVersion(defaultMajorVersion, defaultMinorVersion);
Adam Tkaca6578bf2010-04-23 14:07:41 +000061
Adam Tkacbfd66c12010-10-01 08:33:29 +000062 security = new SecurityServer();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000063}
64
65SConnection::~SConnection()
66{
Adam Tkaca6578bf2010-04-23 14:07:41 +000067 if (ssecurity) ssecurity->destroy();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000068 deleteReaderAndWriter();
69}
70
71void SConnection::deleteReaderAndWriter()
72{
73 delete reader_;
74 reader_ = 0;
75 delete writer_;
76 writer_ = 0;
77}
78
79void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
80{
81 is = is_;
82 os = os_;
83}
84
85void SConnection::initialiseProtocol()
86{
87 cp.writeVersion(os);
88 state_ = RFBSTATE_PROTOCOL_VERSION;
89}
90
91void SConnection::processMsg()
92{
93 switch (state_) {
94 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
95 case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
96 case RFBSTATE_SECURITY: processSecurityMsg(); break;
97 case RFBSTATE_INITIALISATION: processInitMsg(); break;
98 case RFBSTATE_NORMAL: reader_->readMsg(); break;
99 case RFBSTATE_QUERYING:
100 throw Exception("SConnection::processMsg: bogus data from client while "
101 "querying");
102 case RFBSTATE_UNINITIALISED:
103 throw Exception("SConnection::processMsg: not initialised yet?");
104 default:
105 throw Exception("SConnection::processMsg: invalid state");
106 }
107}
108
109void SConnection::processVersionMsg()
110{
111 vlog.debug("reading protocol version");
112 bool done;
113 if (!cp.readVersion(is, &done)) {
114 state_ = RFBSTATE_INVALID;
115 throw Exception("reading version failed: not an RFB client?");
116 }
117 if (!done) return;
118
119 vlog.info("Client needs protocol version %d.%d",
120 cp.majorVersion, cp.minorVersion);
121
122 if (cp.majorVersion != 3) {
123 // unknown protocol version
124 char msg[256];
125 sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
126 cp.majorVersion, cp.minorVersion,
127 defaultMajorVersion, defaultMinorVersion);
128 throwConnFailedException(msg);
129 }
130
131 if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
132 vlog.error("Client uses unofficial protocol version %d.%d",
133 cp.majorVersion,cp.minorVersion);
134 if (cp.minorVersion >= 8)
135 cp.minorVersion = 8;
136 else if (cp.minorVersion == 7)
137 cp.minorVersion = 7;
138 else
139 cp.minorVersion = 3;
140 vlog.error("Assuming compatibility with version %d.%d",
141 cp.majorVersion,cp.minorVersion);
142 }
143
144 versionReceived();
145
146 std::list<rdr::U8> secTypes;
147 std::list<rdr::U8>::iterator i;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000148 secTypes = security->GetEnabledSecTypes();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000149
150 if (cp.isVersion(3,3)) {
151
152 // cope with legacy 3.3 client only if "no authentication" or "vnc
153 // authentication" is supported.
154 for (i=secTypes.begin(); i!=secTypes.end(); i++) {
155 if (*i == secTypeNone || *i == secTypeVncAuth) break;
156 }
157 if (i == secTypes.end()) {
158 char msg[256];
159 sprintf(msg,"No supported security type for %d.%d client",
160 cp.majorVersion, cp.minorVersion);
161 throwConnFailedException(msg);
162 }
163
164 os->writeU32(*i);
165 if (*i == secTypeNone) os->flush();
166 state_ = RFBSTATE_SECURITY;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000167 ssecurity = security->GetSSecurity(*i);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000168 processSecurityMsg();
169 return;
170 }
171
172 // list supported security types for >=3.7 clients
173
174 if (secTypes.empty())
175 throwConnFailedException("No supported security types");
176
177 os->writeU8(secTypes.size());
178 for (i=secTypes.begin(); i!=secTypes.end(); i++)
179 os->writeU8(*i);
180 os->flush();
181 state_ = RFBSTATE_SECURITY_TYPE;
182}
183
184
185void SConnection::processSecurityTypeMsg()
186{
187 vlog.debug("processing security type message");
188 int secType = is->readU8();
189
Constantin Kaplinsky5fa9d222006-09-06 10:32:06 +0000190 processSecurityType(secType);
191}
192
193void SConnection::processSecurityType(int secType)
194{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000195 // Verify that the requested security type should be offered
196 std::list<rdr::U8> secTypes;
197 std::list<rdr::U8>::iterator i;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000198
199 secTypes = security->GetEnabledSecTypes();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000200 for (i=secTypes.begin(); i!=secTypes.end(); i++)
201 if (*i == secType) break;
202 if (i == secTypes.end())
203 throw Exception("Requested security type not available");
204
205 vlog.info("Client requests security type %s(%d)",
206 secTypeName(secType),secType);
207
208 try {
209 state_ = RFBSTATE_SECURITY;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000210 ssecurity = security->GetSSecurity(secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000211 } catch (rdr::Exception& e) {
212 throwConnFailedException(e.str());
213 }
214
215 processSecurityMsg();
216}
217
218void SConnection::processSecurityMsg()
219{
220 vlog.debug("processing security message");
221 try {
Adam Tkaca6578bf2010-04-23 14:07:41 +0000222 bool done = ssecurity->processMsg(this);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000223 if (done) {
224 state_ = RFBSTATE_QUERYING;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000225 queryConnection(ssecurity->getUserName());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000226 }
227 } catch (AuthFailureException& e) {
228 vlog.error("AuthFailureException: %s", e.str());
229 os->writeU32(secResultFailed);
230 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
231 os->writeString(e.str());
232 os->flush();
233 throw;
234 }
235}
236
237void SConnection::processInitMsg()
238{
239 vlog.debug("reading client initialisation");
240 reader_->readClientInit();
241}
242
243void SConnection::throwConnFailedException(const char* msg)
244{
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000245 vlog.info("%s", msg);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000246 if (state_ == RFBSTATE_PROTOCOL_VERSION) {
247 if (cp.majorVersion == 3 && cp.minorVersion == 3) {
248 os->writeU32(0);
249 os->writeString(msg);
250 os->flush();
251 } else {
252 os->writeU8(0);
253 os->writeString(msg);
254 os->flush();
255 }
256 }
257 state_ = RFBSTATE_INVALID;
258 throw ConnFailedException(msg);
259}
260
261void SConnection::writeConnFailedFromScratch(const char* msg,
262 rdr::OutStream* os)
263{
264 os->writeBytes("RFB 003.003\n", 12);
265 os->writeU32(0);
266 os->writeString(msg);
267 os->flush();
268}
269
Pierre Ossman48700812014-09-17 17:11:56 +0200270void SConnection::setEncodings(int nEncodings, rdr::S32* encodings)
271{
272 int i;
273
274 preferredEncoding = encodingRaw;
275 for (i = 0;i < nEncodings;i++) {
276 if (EncodeManager::supported(encodings[i])) {
277 preferredEncoding = encodings[i];
278 break;
279 }
280 }
281
282 SMsgHandler::setEncodings(nEncodings, encodings);
283}
284
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000285void SConnection::versionReceived()
286{
287}
288
289void SConnection::authSuccess()
290{
291}
292
293void SConnection::queryConnection(const char* userName)
294{
295 approveConnection(true);
296}
297
298void SConnection::approveConnection(bool accept, const char* reason)
299{
300 if (state_ != RFBSTATE_QUERYING)
301 throw Exception("SConnection::approveConnection: invalid state");
302
303 if (!reason) reason = "Authentication failure";
304
Adam Tkaca6578bf2010-04-23 14:07:41 +0000305 if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000306 if (accept) {
307 os->writeU32(secResultOK);
308 } else {
309 os->writeU32(secResultFailed);
310 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
311 os->writeString(reason);
312 }
313 os->flush();
314 }
315
316 if (accept) {
317 state_ = RFBSTATE_INITIALISATION;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100318 reader_ = new SMsgReader(this, is);
319 writer_ = new SMsgWriter(&cp, os);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000320 authSuccess();
321 } else {
322 state_ = RFBSTATE_INVALID;
323 throw AuthFailureException(reason);
324 }
325}
326
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000327void SConnection::clientInit(bool shared)
328{
329 writer_->writeServerInit();
330 state_ = RFBSTATE_NORMAL;
331}
332
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000333void SConnection::setPixelFormat(const PixelFormat& pf)
334{
335 SMsgHandler::setPixelFormat(pf);
336 readyForSetColourMapEntries = true;
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100337 if (!pf.trueColour)
338 writeFakeColourMap();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000339}
340
341void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
342{
343 if (!readyForSetColourMapEntries) {
344 readyForSetColourMapEntries = true;
345 if (!cp.pf().trueColour) {
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100346 writeFakeColourMap();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000347 }
348 }
349}
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000350
351void SConnection::fence(rdr::U32 flags, unsigned len, const char data[])
352{
353 if (!(flags & fenceFlagRequest))
354 return;
355
356 // We cannot guarantee any synchronisation at this level
357 flags = 0;
358
359 writer()->writeFence(flags, len, data);
360}
Pierre Ossmanc898d9a2011-11-14 16:22:23 +0000361
362void SConnection::enableContinuousUpdates(bool enable,
363 int x, int y, int w, int h)
364{
365}
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100366
367void SConnection::writeFakeColourMap(void)
368{
369 int i;
370 rdr::U16 red[256], green[256], blue[256];
371
372 for (i = 0;i < 256;i++)
373 cp.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);
374
375 writer()->writeSetColourMapEntries(0, 256, red, green, blue);
376}