blob: 1422b5469169709c89464f9e3b150f4848545614 [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
182 // Verify that the requested security type should be offered
183 std::list<rdr::U8> secTypes;
184 std::list<rdr::U8>::iterator i;
185 securityFactory->getSecTypes(&secTypes, reverseConnection);
186 for (i=secTypes.begin(); i!=secTypes.end(); i++)
187 if (*i == secType) break;
188 if (i == secTypes.end())
189 throw Exception("Requested security type not available");
190
191 vlog.info("Client requests security type %s(%d)",
192 secTypeName(secType),secType);
193
194 try {
195 state_ = RFBSTATE_SECURITY;
196 security = securityFactory->getSSecurity(secType, reverseConnection);
197 } catch (rdr::Exception& e) {
198 throwConnFailedException(e.str());
199 }
200
201 processSecurityMsg();
202}
203
204void SConnection::processSecurityMsg()
205{
206 vlog.debug("processing security message");
207 try {
208 bool done = security->processMsg(this);
209 if (done) {
210 state_ = RFBSTATE_QUERYING;
211 queryConnection(security->getUserName());
212 }
213 } catch (AuthFailureException& e) {
214 vlog.error("AuthFailureException: %s", e.str());
215 os->writeU32(secResultFailed);
216 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
217 os->writeString(e.str());
218 os->flush();
219 throw;
220 }
221}
222
223void SConnection::processInitMsg()
224{
225 vlog.debug("reading client initialisation");
226 reader_->readClientInit();
227}
228
229void SConnection::throwConnFailedException(const char* msg)
230{
231 vlog.info(msg);
232 if (state_ == RFBSTATE_PROTOCOL_VERSION) {
233 if (cp.majorVersion == 3 && cp.minorVersion == 3) {
234 os->writeU32(0);
235 os->writeString(msg);
236 os->flush();
237 } else {
238 os->writeU8(0);
239 os->writeString(msg);
240 os->flush();
241 }
242 }
243 state_ = RFBSTATE_INVALID;
244 throw ConnFailedException(msg);
245}
246
247void SConnection::writeConnFailedFromScratch(const char* msg,
248 rdr::OutStream* os)
249{
250 os->writeBytes("RFB 003.003\n", 12);
251 os->writeU32(0);
252 os->writeString(msg);
253 os->flush();
254}
255
256void SConnection::versionReceived()
257{
258}
259
260void SConnection::authSuccess()
261{
262}
263
264void SConnection::queryConnection(const char* userName)
265{
266 approveConnection(true);
267}
268
269void SConnection::approveConnection(bool accept, const char* reason)
270{
271 if (state_ != RFBSTATE_QUERYING)
272 throw Exception("SConnection::approveConnection: invalid state");
273
274 if (!reason) reason = "Authentication failure";
275
276 if (!cp.beforeVersion(3,8) || security->getType() != secTypeNone) {
277 if (accept) {
278 os->writeU32(secResultOK);
279 } else {
280 os->writeU32(secResultFailed);
281 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
282 os->writeString(reason);
283 }
284 os->flush();
285 }
286
287 if (accept) {
288 state_ = RFBSTATE_INITIALISATION;
289 reader_ = new SMsgReaderV3(this, is);
290 writer_ = new SMsgWriterV3(&cp, os);
291 authSuccess();
292 } else {
293 state_ = RFBSTATE_INVALID;
294 throw AuthFailureException(reason);
295 }
296}
297
298void SConnection::setInitialColourMap()
299{
300}
301
302void SConnection::clientInit(bool shared)
303{
304 writer_->writeServerInit();
305 state_ = RFBSTATE_NORMAL;
306}
307
308void SConnection::setPixelFormat(const PixelFormat& pf)
309{
310 SMsgHandler::setPixelFormat(pf);
311 readyForSetColourMapEntries = true;
312}
313
314void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
315{
316 if (!readyForSetColourMapEntries) {
317 readyForSetColourMapEntries = true;
318 if (!cp.pf().trueColour) {
319 setInitialColourMap();
320 }
321 }
322}