blob: e969ed8c54fd769f056bd3b06fefa3de8e5c88b4 [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 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/SSecurity.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
44SConnection::SConnection()
45 : readyForSetColourMapEntries(false),
46 is(0), os(0), reader_(0), writer_(0),
47 nSecTypes(0), security(0), state_(RFBSTATE_UNINITIALISED)
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::addSecType(rdr::U8 secType)
78{
79 if (nSecTypes == maxSecTypes)
80 throw Exception("too many security types");
81 secTypes[nSecTypes++] = secType;
82 vlog.debug("Offering security type %s(%d)",
83 secTypeName(secType),secType);
84}
85
86void SConnection::initialiseProtocol()
87{
88 cp.writeVersion(os);
89 state_ = RFBSTATE_PROTOCOL_VERSION;
90}
91
92void SConnection::processMsg()
93{
94 switch (state_) {
95 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
96 case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
97 case RFBSTATE_SECURITY: processSecurityMsg(); break;
98 case RFBSTATE_INITIALISATION: processInitMsg(); break;
99 case RFBSTATE_NORMAL: reader_->readMsg(); break;
100 case RFBSTATE_QUERYING:
101 throw Exception("SConnection::processMsg: bogus data from client while "
102 "querying");
103 case RFBSTATE_UNINITIALISED:
104 throw Exception("SConnection::processMsg: not initialised yet?");
105 default:
106 throw Exception("SConnection::processMsg: invalid state");
107 }
108}
109
110void SConnection::processVersionMsg()
111{
112 vlog.debug("reading protocol version");
113 bool done;
114 if (!cp.readVersion(is, &done)) {
115 state_ = RFBSTATE_INVALID;
116 throw Exception("reading version failed: not an RFB client?");
117 }
118 if (!done) return;
119
120 vlog.info("Client needs protocol version %d.%d",
121 cp.majorVersion, cp.minorVersion);
122
123 if (cp.majorVersion != 3) {
124 // unknown protocol version
125 char msg[256];
126 sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
127 cp.majorVersion, cp.minorVersion,
128 defaultMajorVersion, defaultMinorVersion);
129 throwConnFailedException(msg);
130 }
131
132 if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
133 vlog.error("Client uses unofficial protocol version %d.%d",
134 cp.majorVersion,cp.minorVersion);
135 if (cp.minorVersion >= 8)
136 cp.minorVersion = 8;
137 else if (cp.minorVersion == 7)
138 cp.minorVersion = 7;
139 else
140 cp.minorVersion = 3;
141 vlog.error("Assuming compatibility with version %d.%d",
142 cp.majorVersion,cp.minorVersion);
143 }
144
145 versionReceived();
146
147 if (cp.isVersion(3,3)) {
148
149 // cope with legacy 3.3 client only if "no authentication" or "vnc
150 // authentication" is supported.
151
152 int i;
153 for (i = 0; i < nSecTypes; i++) {
154 if (secTypes[i] == secTypeNone || secTypes[i] == secTypeVncAuth) break;
155 }
156 if (i == nSecTypes) {
157 char msg[256];
158 sprintf(msg,"No supported security type for %d.%d client",
159 cp.majorVersion, cp.minorVersion);
160 throwConnFailedException(msg);
161 }
162
163 os->writeU32(secTypes[i]);
164 if (secTypes[i] == secTypeNone) os->flush();
165 state_ = RFBSTATE_SECURITY;
166 security = getSSecurity(secTypes[i]);
167 processSecurityMsg();
168 return;
169 }
170
171 // list supported security types for >=3.7 clients
172
173 if (nSecTypes == 0)
174 throwConnFailedException("No supported security types");
175
176 os->writeU8(nSecTypes);
177 os->writeBytes(secTypes, nSecTypes);
178 os->flush();
179 state_ = RFBSTATE_SECURITY_TYPE;
180}
181
182
183void SConnection::processSecurityTypeMsg()
184{
185 vlog.debug("processing security type message");
186 int secType = is->readU8();
187 vlog.info("Client requests security type %s(%d)",
188 secTypeName(secType),secType);
189 int i;
190 for (i = 0; i < nSecTypes; i++) {
191 if (secType == secTypes[i]) break;
192 }
193 if (i == nSecTypes) {
194 char msg[256];
195 sprintf(msg,"Security type %s(%d) from client not supported",
196 secTypeName(secType),secType);
197 throwConnFailedException(msg);
198 }
199 state_ = RFBSTATE_SECURITY;
200 security = getSSecurity(secType);
201 processSecurityMsg();
202}
203
204void SConnection::processSecurityMsg()
205{
206 vlog.debug("processing security message");
207 bool done;
208 bool ok = security->processMsg(this, &done);
209 if (done) {
210 state_ = RFBSTATE_QUERYING;
211 if (ok) {
212 queryConnection(security->getUserName());
213 } else {
214 const char* failureMsg = security->failureMessage();
215 if (!failureMsg) failureMsg = "Authentication failure";
216 approveConnection(false, failureMsg);
217 }
218 }
219 if (!ok) {
220 state_ = RFBSTATE_INVALID;
221 authFailure();
222 throw AuthFailureException();
223 }
224}
225
226void SConnection::processInitMsg()
227{
228 vlog.debug("reading client initialisation");
229 reader_->readClientInit();
230}
231
232void SConnection::throwConnFailedException(const char* msg)
233{
234 vlog.info(msg);
235 if (state_ == RFBSTATE_PROTOCOL_VERSION) {
236 if (cp.majorVersion == 3 && cp.minorVersion == 3) {
237 os->writeU32(0);
238 os->writeString(msg);
239 os->flush();
240 } else {
241 os->writeU8(0);
242 os->writeString(msg);
243 os->flush();
244 }
245 }
246 state_ = RFBSTATE_INVALID;
247 throw ConnFailedException(msg);
248}
249
250void SConnection::writeConnFailedFromScratch(const char* msg,
251 rdr::OutStream* os)
252{
253 os->writeBytes("RFB 003.003\n", 12);
254 os->writeU32(0);
255 os->writeString(msg);
256 os->flush();
257}
258
259void SConnection::versionReceived()
260{
261}
262
263void SConnection::authSuccess()
264{
265}
266
267void SConnection::authFailure()
268{
269}
270
271void SConnection::queryConnection(const char* userName)
272{
273 approveConnection(true);
274}
275
276void SConnection::approveConnection(bool accept, const char* reason)
277{
278 if (state_ != RFBSTATE_QUERYING)
279 throw Exception("SConnection::approveConnection: invalid state");
280
281 if (!reason) reason = "Authentication failure";
282
283 if (!cp.beforeVersion(3,8) || security->getType() != secTypeNone) {
284 if (accept) {
285 os->writeU32(secResultOK);
286 } else {
287 os->writeU32(secResultFailed);
288 if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
289 os->writeString(reason);
290 }
291 os->flush();
292 }
293
294 if (accept) {
295 state_ = RFBSTATE_INITIALISATION;
296 reader_ = new SMsgReaderV3(this, is);
297 writer_ = new SMsgWriterV3(&cp, os);
298 authSuccess();
299 } else {
300 state_ = RFBSTATE_INVALID;
301 authFailure();
302 throw AuthFailureException(reason);
303 }
304}
305
306void SConnection::setInitialColourMap()
307{
308}
309
310void SConnection::clientInit(bool shared)
311{
312 writer_->writeServerInit();
313 state_ = RFBSTATE_NORMAL;
314}
315
316void SConnection::setPixelFormat(const PixelFormat& pf)
317{
318 SMsgHandler::setPixelFormat(pf);
319 readyForSetColourMapEntries = true;
320}
321
322void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
323{
324 if (!readyForSetColourMapEntries) {
325 readyForSetColourMapEntries = true;
326 if (!cp.pf().trueColour) {
327 setInitialColourMap();
328 }
329 }
330}