blob: 3762fbb06d6a84521ad5cf3d46fad9550b8c9697 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18#include <stdio.h>
19#include <string.h>
20#include <rfb/Exception.h>
Adam Tkac5a0caed2010-04-23 13:58:10 +000021#include <rfb/Security.h>
Constantin Kaplinskydafbb012007-04-05 08:43:25 +000022#include <rfb/msgTypes.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <rfb/SMsgReaderV3.h>
24#include <rfb/SMsgWriterV3.h>
25#include <rfb/SConnection.h>
26#include <rfb/ServerCore.h>
27
28#include <rfb/LogWriter.h>
29
30using namespace rfb;
31
32static LogWriter vlog("SConnection");
33
34// AccessRights values
35const SConnection::AccessRights SConnection::AccessView = 0x0001;
36const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
37const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
38const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
39const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
40const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
41const SConnection::AccessRights SConnection::AccessFull = 0xffff;
42
43
Adam Tkaca6578bf2010-04-23 14:07:41 +000044SConnection::SConnection(bool reverseConnection_)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000045 : readyForSetColourMapEntries(false),
46 is(0), os(0), reader_(0), writer_(0),
Adam Tkaca6578bf2010-04-23 14:07:41 +000047 security(0), ssecurity(0), state_(RFBSTATE_UNINITIALISED),
Pierre Ossman02e43d72009-03-05 11:57:11 +000048 reverseConnection(reverseConnection_)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049{
50 defaultMajorVersion = 3;
51 defaultMinorVersion = 8;
52 if (rfb::Server::protocol3_3)
53 defaultMinorVersion = 3;
54
55 cp.setVersion(defaultMajorVersion, defaultMinorVersion);
Adam Tkaca6578bf2010-04-23 14:07:41 +000056
Adam Tkacbfd66c12010-10-01 08:33:29 +000057 security = new SecurityServer();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000058}
59
60SConnection::~SConnection()
61{
Adam Tkaca6578bf2010-04-23 14:07:41 +000062 if (ssecurity) ssecurity->destroy();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000063 deleteReaderAndWriter();
64}
65
66void SConnection::deleteReaderAndWriter()
67{
68 delete reader_;
69 reader_ = 0;
70 delete writer_;
71 writer_ = 0;
72}
73
74void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
75{
76 is = is_;
77 os = os_;
78}
79
80void SConnection::initialiseProtocol()
81{
82 cp.writeVersion(os);
83 state_ = RFBSTATE_PROTOCOL_VERSION;
84}
85
86void SConnection::processMsg()
87{
88 switch (state_) {
89 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
90 case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
91 case RFBSTATE_SECURITY: processSecurityMsg(); break;
92 case RFBSTATE_INITIALISATION: processInitMsg(); break;
93 case RFBSTATE_NORMAL: reader_->readMsg(); break;
94 case RFBSTATE_QUERYING:
95 throw Exception("SConnection::processMsg: bogus data from client while "
96 "querying");
97 case RFBSTATE_UNINITIALISED:
98 throw Exception("SConnection::processMsg: not initialised yet?");
99 default:
100 throw Exception("SConnection::processMsg: invalid state");
101 }
102}
103
104void SConnection::processVersionMsg()
105{
106 vlog.debug("reading protocol version");
107 bool done;
108 if (!cp.readVersion(is, &done)) {
109 state_ = RFBSTATE_INVALID;
110 throw Exception("reading version failed: not an RFB client?");
111 }
112 if (!done) return;
113
114 vlog.info("Client needs protocol version %d.%d",
115 cp.majorVersion, cp.minorVersion);
116
117 if (cp.majorVersion != 3) {
118 // unknown protocol version
119 char msg[256];
120 sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
121 cp.majorVersion, cp.minorVersion,
122 defaultMajorVersion, defaultMinorVersion);
123 throwConnFailedException(msg);
124 }
125
126 if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
127 vlog.error("Client uses unofficial protocol version %d.%d",
128 cp.majorVersion,cp.minorVersion);
129 if (cp.minorVersion >= 8)
130 cp.minorVersion = 8;
131 else if (cp.minorVersion == 7)
132 cp.minorVersion = 7;
133 else
134 cp.minorVersion = 3;
135 vlog.error("Assuming compatibility with version %d.%d",
136 cp.majorVersion,cp.minorVersion);
137 }
138
139 versionReceived();
140
141 std::list<rdr::U8> secTypes;
142 std::list<rdr::U8>::iterator i;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000143 secTypes = security->GetEnabledSecTypes();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000144
145 if (cp.isVersion(3,3)) {
146
147 // cope with legacy 3.3 client only if "no authentication" or "vnc
148 // authentication" is supported.
149 for (i=secTypes.begin(); i!=secTypes.end(); i++) {
150 if (*i == secTypeNone || *i == secTypeVncAuth) break;
151 }
152 if (i == secTypes.end()) {
153 char msg[256];
154 sprintf(msg,"No supported security type for %d.%d client",
155 cp.majorVersion, cp.minorVersion);
156 throwConnFailedException(msg);
157 }
158
159 os->writeU32(*i);
160 if (*i == secTypeNone) os->flush();
161 state_ = RFBSTATE_SECURITY;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000162 ssecurity = security->GetSSecurity(*i);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000163 processSecurityMsg();
164 return;
165 }
166
167 // list supported security types for >=3.7 clients
168
169 if (secTypes.empty())
170 throwConnFailedException("No supported security types");
171
172 os->writeU8(secTypes.size());
173 for (i=secTypes.begin(); i!=secTypes.end(); i++)
174 os->writeU8(*i);
175 os->flush();
176 state_ = RFBSTATE_SECURITY_TYPE;
177}
178
179
180void SConnection::processSecurityTypeMsg()
181{
182 vlog.debug("processing security type message");
183 int secType = is->readU8();
184
Constantin Kaplinsky5fa9d222006-09-06 10:32:06 +0000185 processSecurityType(secType);
186}
187
188void SConnection::processSecurityType(int secType)
189{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000190 // Verify that the requested security type should be offered
191 std::list<rdr::U8> secTypes;
192 std::list<rdr::U8>::iterator i;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000193
194 secTypes = security->GetEnabledSecTypes();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000195 for (i=secTypes.begin(); i!=secTypes.end(); i++)
196 if (*i == secType) break;
197 if (i == secTypes.end())
198 throw Exception("Requested security type not available");
199
200 vlog.info("Client requests security type %s(%d)",
201 secTypeName(secType),secType);
202
203 try {
204 state_ = RFBSTATE_SECURITY;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000205 ssecurity = security->GetSSecurity(secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000206 } catch (rdr::Exception& e) {
207 throwConnFailedException(e.str());
208 }
209
210 processSecurityMsg();
211}
212
213void SConnection::processSecurityMsg()
214{
215 vlog.debug("processing security message");
216 try {
Adam Tkaca6578bf2010-04-23 14:07:41 +0000217 bool done = ssecurity->processMsg(this);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000218 if (done) {
219 state_ = RFBSTATE_QUERYING;
Adam Tkaca6578bf2010-04-23 14:07:41 +0000220 queryConnection(ssecurity->getUserName());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000221 }
222 } catch (AuthFailureException& e) {
223 vlog.error("AuthFailureException: %s", e.str());
224 os->writeU32(secResultFailed);
225 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
226 os->writeString(e.str());
227 os->flush();
228 throw;
229 }
230}
231
232void SConnection::processInitMsg()
233{
234 vlog.debug("reading client initialisation");
235 reader_->readClientInit();
236}
237
238void SConnection::throwConnFailedException(const char* msg)
239{
240 vlog.info(msg);
241 if (state_ == RFBSTATE_PROTOCOL_VERSION) {
242 if (cp.majorVersion == 3 && cp.minorVersion == 3) {
243 os->writeU32(0);
244 os->writeString(msg);
245 os->flush();
246 } else {
247 os->writeU8(0);
248 os->writeString(msg);
249 os->flush();
250 }
251 }
252 state_ = RFBSTATE_INVALID;
253 throw ConnFailedException(msg);
254}
255
256void SConnection::writeConnFailedFromScratch(const char* msg,
257 rdr::OutStream* os)
258{
259 os->writeBytes("RFB 003.003\n", 12);
260 os->writeU32(0);
261 os->writeString(msg);
262 os->flush();
263}
264
265void SConnection::versionReceived()
266{
267}
268
269void SConnection::authSuccess()
270{
271}
272
273void SConnection::queryConnection(const char* userName)
274{
275 approveConnection(true);
276}
277
278void SConnection::approveConnection(bool accept, const char* reason)
279{
280 if (state_ != RFBSTATE_QUERYING)
281 throw Exception("SConnection::approveConnection: invalid state");
282
283 if (!reason) reason = "Authentication failure";
284
Adam Tkaca6578bf2010-04-23 14:07:41 +0000285 if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000286 if (accept) {
287 os->writeU32(secResultOK);
288 } else {
289 os->writeU32(secResultFailed);
290 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
291 os->writeString(reason);
292 }
293 os->flush();
294 }
295
296 if (accept) {
297 state_ = RFBSTATE_INITIALISATION;
298 reader_ = new SMsgReaderV3(this, is);
299 writer_ = new SMsgWriterV3(&cp, os);
300 authSuccess();
301 } else {
302 state_ = RFBSTATE_INVALID;
303 throw AuthFailureException(reason);
304 }
305}
306
307void SConnection::setInitialColourMap()
308{
309}
310
311void SConnection::clientInit(bool shared)
312{
313 writer_->writeServerInit();
314 state_ = RFBSTATE_NORMAL;
315}
316
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000317void SConnection::setPixelFormat(const PixelFormat& pf)
318{
319 SMsgHandler::setPixelFormat(pf);
320 readyForSetColourMapEntries = true;
321}
322
323void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
324{
325 if (!readyForSetColourMapEntries) {
326 readyForSetColourMapEntries = true;
327 if (!cp.pf().trueColour) {
328 setInitialColourMap();
329 }
330 }
331}