blob: 3901a81190970eb865df329818c2ce6df35b5f51 [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>
21#include <rfb/secTypes.h>
22#include <rfb/SMsgReaderV3.h>
23#include <rfb/SMsgWriterV3.h>
24#include <rfb/SConnection.h>
25#include <rfb/ServerCore.h>
26
27#include <rfb/LogWriter.h>
28
29using namespace rfb;
30
31static LogWriter vlog("SConnection");
32
33// AccessRights values
34const SConnection::AccessRights SConnection::AccessView = 0x0001;
35const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
36const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
37const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
38const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
39const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
40const SConnection::AccessRights SConnection::AccessFull = 0xffff;
41
42
43SConnection::SConnection(SSecurityFactory* secFact, bool reverseConnection_)
44 : readyForSetColourMapEntries(false),
45 is(0), os(0), reader_(0), writer_(0),
46 security(0), securityFactory(secFact), state_(RFBSTATE_UNINITIALISED),
47 reverseConnection(reverseConnection_)
48{
49 defaultMajorVersion = 3;
50 defaultMinorVersion = 8;
51 if (rfb::Server::protocol3_3)
52 defaultMinorVersion = 3;
53
54 cp.setVersion(defaultMajorVersion, defaultMinorVersion);
55}
56
57SConnection::~SConnection()
58{
59 if (security) security->destroy();
60 deleteReaderAndWriter();
61}
62
63void SConnection::deleteReaderAndWriter()
64{
65 delete reader_;
66 reader_ = 0;
67 delete writer_;
68 writer_ = 0;
69}
70
71void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
72{
73 is = is_;
74 os = os_;
75}
76
77void SConnection::initialiseProtocol()
78{
79 cp.writeVersion(os);
80 state_ = RFBSTATE_PROTOCOL_VERSION;
81}
82
83void SConnection::processMsg()
84{
85 switch (state_) {
86 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
87 case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
88 case RFBSTATE_SECURITY: processSecurityMsg(); break;
89 case RFBSTATE_INITIALISATION: processInitMsg(); break;
90 case RFBSTATE_NORMAL: reader_->readMsg(); break;
91 case RFBSTATE_QUERYING:
92 throw Exception("SConnection::processMsg: bogus data from client while "
93 "querying");
94 case RFBSTATE_UNINITIALISED:
95 throw Exception("SConnection::processMsg: not initialised yet?");
96 default:
97 throw Exception("SConnection::processMsg: invalid state");
98 }
99}
100
101void SConnection::processVersionMsg()
102{
103 vlog.debug("reading protocol version");
104 bool done;
105 if (!cp.readVersion(is, &done)) {
106 state_ = RFBSTATE_INVALID;
107 throw Exception("reading version failed: not an RFB client?");
108 }
109 if (!done) return;
110
111 vlog.info("Client needs protocol version %d.%d",
112 cp.majorVersion, cp.minorVersion);
113
114 if (cp.majorVersion != 3) {
115 // unknown protocol version
116 char msg[256];
117 sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
118 cp.majorVersion, cp.minorVersion,
119 defaultMajorVersion, defaultMinorVersion);
120 throwConnFailedException(msg);
121 }
122
123 if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
124 vlog.error("Client uses unofficial protocol version %d.%d",
125 cp.majorVersion,cp.minorVersion);
126 if (cp.minorVersion >= 8)
127 cp.minorVersion = 8;
128 else if (cp.minorVersion == 7)
129 cp.minorVersion = 7;
130 else
131 cp.minorVersion = 3;
132 vlog.error("Assuming compatibility with version %d.%d",
133 cp.majorVersion,cp.minorVersion);
134 }
135
136 versionReceived();
137
138 std::list<rdr::U8> secTypes;
139 std::list<rdr::U8>::iterator i;
140 securityFactory->getSecTypes(&secTypes, reverseConnection);
141
142 if (cp.isVersion(3,3)) {
143
144 // cope with legacy 3.3 client only if "no authentication" or "vnc
145 // authentication" is supported.
146 for (i=secTypes.begin(); i!=secTypes.end(); i++) {
147 if (*i == secTypeNone || *i == secTypeVncAuth) break;
148 }
149 if (i == secTypes.end()) {
150 char msg[256];
151 sprintf(msg,"No supported security type for %d.%d client",
152 cp.majorVersion, cp.minorVersion);
153 throwConnFailedException(msg);
154 }
155
156 os->writeU32(*i);
157 if (*i == secTypeNone) os->flush();
158 state_ = RFBSTATE_SECURITY;
159 security = securityFactory->getSSecurity(*i, reverseConnection);
160 processSecurityMsg();
161 return;
162 }
163
164 // list supported security types for >=3.7 clients
165
166 if (secTypes.empty())
167 throwConnFailedException("No supported security types");
168
169 os->writeU8(secTypes.size());
170 for (i=secTypes.begin(); i!=secTypes.end(); i++)
171 os->writeU8(*i);
172 os->flush();
173 state_ = RFBSTATE_SECURITY_TYPE;
174}
175
176
177void SConnection::processSecurityTypeMsg()
178{
179 vlog.debug("processing security type message");
180 int secType = is->readU8();
181
Constantin Kaplinsky5fa9d222006-09-06 10:32:06 +0000182 processSecurityType(secType);
183}
184
185void SConnection::processSecurityType(int secType)
186{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000187 // Verify that the requested security type should be offered
188 std::list<rdr::U8> secTypes;
189 std::list<rdr::U8>::iterator i;
190 securityFactory->getSecTypes(&secTypes, reverseConnection);
191 for (i=secTypes.begin(); i!=secTypes.end(); i++)
192 if (*i == secType) break;
193 if (i == secTypes.end())
194 throw Exception("Requested security type not available");
195
196 vlog.info("Client requests security type %s(%d)",
197 secTypeName(secType),secType);
198
199 try {
200 state_ = RFBSTATE_SECURITY;
201 security = securityFactory->getSSecurity(secType, reverseConnection);
202 } catch (rdr::Exception& e) {
203 throwConnFailedException(e.str());
204 }
205
206 processSecurityMsg();
207}
208
209void SConnection::processSecurityMsg()
210{
211 vlog.debug("processing security message");
212 try {
213 bool done = security->processMsg(this);
214 if (done) {
215 state_ = RFBSTATE_QUERYING;
216 queryConnection(security->getUserName());
217 }
218 } catch (AuthFailureException& e) {
219 vlog.error("AuthFailureException: %s", e.str());
220 os->writeU32(secResultFailed);
221 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
222 os->writeString(e.str());
223 os->flush();
224 throw;
225 }
226}
227
228void SConnection::processInitMsg()
229{
230 vlog.debug("reading client initialisation");
231 reader_->readClientInit();
232}
233
234void SConnection::throwConnFailedException(const char* msg)
235{
236 vlog.info(msg);
237 if (state_ == RFBSTATE_PROTOCOL_VERSION) {
238 if (cp.majorVersion == 3 && cp.minorVersion == 3) {
239 os->writeU32(0);
240 os->writeString(msg);
241 os->flush();
242 } else {
243 os->writeU8(0);
244 os->writeString(msg);
245 os->flush();
246 }
247 }
248 state_ = RFBSTATE_INVALID;
249 throw ConnFailedException(msg);
250}
251
252void SConnection::writeConnFailedFromScratch(const char* msg,
253 rdr::OutStream* os)
254{
255 os->writeBytes("RFB 003.003\n", 12);
256 os->writeU32(0);
257 os->writeString(msg);
258 os->flush();
259}
260
261void SConnection::versionReceived()
262{
263}
264
265void SConnection::authSuccess()
266{
267}
268
269void SConnection::queryConnection(const char* userName)
270{
271 approveConnection(true);
272}
273
274void SConnection::approveConnection(bool accept, const char* reason)
275{
276 if (state_ != RFBSTATE_QUERYING)
277 throw Exception("SConnection::approveConnection: invalid state");
278
279 if (!reason) reason = "Authentication failure";
280
281 if (!cp.beforeVersion(3,8) || security->getType() != secTypeNone) {
282 if (accept) {
283 os->writeU32(secResultOK);
284 } else {
285 os->writeU32(secResultFailed);
286 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
287 os->writeString(reason);
288 }
289 os->flush();
290 }
291
292 if (accept) {
293 state_ = RFBSTATE_INITIALISATION;
294 reader_ = new SMsgReaderV3(this, is);
295 writer_ = new SMsgWriterV3(&cp, os);
296 authSuccess();
297 } else {
298 state_ = RFBSTATE_INVALID;
299 throw AuthFailureException(reason);
300 }
301}
302
303void SConnection::setInitialColourMap()
304{
305}
306
307void SConnection::clientInit(bool shared)
308{
309 writer_->writeServerInit();
310 state_ = RFBSTATE_NORMAL;
311}
312
313void SConnection::setPixelFormat(const PixelFormat& pf)
314{
315 SMsgHandler::setPixelFormat(pf);
316 readyForSetColourMapEntries = true;
317}
318
319void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
320{
321 if (!readyForSetColourMapEntries) {
322 readyForSetColourMapEntries = true;
323 if (!cp.pf().trueColour) {
324 setInitialColourMap();
325 }
326 }
327}