You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SConnection.cxx 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /* 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/Security.h>
  22. #include <rfb/msgTypes.h>
  23. #include <rfb/CapsList.h>
  24. #include <rfb/SMsgReaderV3.h>
  25. #include <rfb/SMsgWriterV3.h>
  26. #include <rfb/SConnection.h>
  27. #include <rfb/ServerCore.h>
  28. #include <rfb/LogWriter.h>
  29. using namespace rfb;
  30. static LogWriter vlog("SConnection");
  31. // AccessRights values
  32. const SConnection::AccessRights SConnection::AccessView = 0x0001;
  33. const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
  34. const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
  35. const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
  36. const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
  37. const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
  38. const SConnection::AccessRights SConnection::AccessFull = 0xffff;
  39. SConnection::SConnection(bool reverseConnection_)
  40. : readyForSetColourMapEntries(false),
  41. is(0), os(0), reader_(0), writer_(0),
  42. security(0), ssecurity(0), state_(RFBSTATE_UNINITIALISED),
  43. reverseConnection(reverseConnection_)
  44. {
  45. defaultMajorVersion = 3;
  46. defaultMinorVersion = 8;
  47. if (rfb::Server::protocol3_3)
  48. defaultMinorVersion = 3;
  49. cp.setVersion(defaultMajorVersion, defaultMinorVersion);
  50. security = new Security(SecurityServer);
  51. }
  52. SConnection::~SConnection()
  53. {
  54. if (ssecurity) ssecurity->destroy();
  55. deleteReaderAndWriter();
  56. }
  57. void SConnection::deleteReaderAndWriter()
  58. {
  59. delete reader_;
  60. reader_ = 0;
  61. delete writer_;
  62. writer_ = 0;
  63. }
  64. void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  65. {
  66. is = is_;
  67. os = os_;
  68. }
  69. void SConnection::initialiseProtocol()
  70. {
  71. cp.writeVersion(os);
  72. state_ = RFBSTATE_PROTOCOL_VERSION;
  73. }
  74. void SConnection::processMsg()
  75. {
  76. switch (state_) {
  77. case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
  78. case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
  79. case RFBSTATE_TIGHT_TUNN_TYPE: processTunnelTypeMsg(); break;
  80. case RFBSTATE_TIGHT_AUTH_TYPE: processAuthTypeMsg(); break;
  81. case RFBSTATE_SECURITY: processSecurityMsg(); break;
  82. case RFBSTATE_INITIALISATION: processInitMsg(); break;
  83. case RFBSTATE_NORMAL: reader_->readMsg(); break;
  84. case RFBSTATE_QUERYING:
  85. throw Exception("SConnection::processMsg: bogus data from client while "
  86. "querying");
  87. case RFBSTATE_UNINITIALISED:
  88. throw Exception("SConnection::processMsg: not initialised yet?");
  89. default:
  90. throw Exception("SConnection::processMsg: invalid state");
  91. }
  92. }
  93. void SConnection::processVersionMsg()
  94. {
  95. vlog.debug("reading protocol version");
  96. bool done;
  97. if (!cp.readVersion(is, &done)) {
  98. state_ = RFBSTATE_INVALID;
  99. throw Exception("reading version failed: not an RFB client?");
  100. }
  101. if (!done) return;
  102. vlog.info("Client needs protocol version %d.%d",
  103. cp.majorVersion, cp.minorVersion);
  104. if (cp.majorVersion != 3) {
  105. // unknown protocol version
  106. char msg[256];
  107. sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
  108. cp.majorVersion, cp.minorVersion,
  109. defaultMajorVersion, defaultMinorVersion);
  110. throwConnFailedException(msg);
  111. }
  112. if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
  113. vlog.error("Client uses unofficial protocol version %d.%d",
  114. cp.majorVersion,cp.minorVersion);
  115. if (cp.minorVersion >= 8)
  116. cp.minorVersion = 8;
  117. else if (cp.minorVersion == 7)
  118. cp.minorVersion = 7;
  119. else
  120. cp.minorVersion = 3;
  121. vlog.error("Assuming compatibility with version %d.%d",
  122. cp.majorVersion,cp.minorVersion);
  123. }
  124. versionReceived();
  125. std::list<rdr::U8> secTypes;
  126. std::list<rdr::U8>::iterator i;
  127. secTypes = security->GetEnabledSecTypes();
  128. if (cp.isVersion(3,3)) {
  129. // cope with legacy 3.3 client only if "no authentication" or "vnc
  130. // authentication" is supported.
  131. for (i=secTypes.begin(); i!=secTypes.end(); i++) {
  132. if (*i == secTypeNone || *i == secTypeVncAuth) break;
  133. }
  134. if (i == secTypes.end()) {
  135. char msg[256];
  136. sprintf(msg,"No supported security type for %d.%d client",
  137. cp.majorVersion, cp.minorVersion);
  138. throwConnFailedException(msg);
  139. }
  140. os->writeU32(*i);
  141. if (*i == secTypeNone) os->flush();
  142. state_ = RFBSTATE_SECURITY;
  143. ssecurity = security->GetSSecurity(*i);
  144. processSecurityMsg();
  145. return;
  146. }
  147. // Add a special security type to advertise TightVNC protocol extensions.
  148. secTypes.push_back(secTypeTight);
  149. // list supported security types for >=3.7 clients
  150. if (secTypes.empty())
  151. throwConnFailedException("No supported security types");
  152. os->writeU8(secTypes.size());
  153. for (i=secTypes.begin(); i!=secTypes.end(); i++)
  154. os->writeU8(*i);
  155. os->flush();
  156. state_ = RFBSTATE_SECURITY_TYPE;
  157. }
  158. void SConnection::processSecurityTypeMsg()
  159. {
  160. vlog.debug("processing security type message");
  161. int secType = is->readU8();
  162. if (secType == secTypeTight) {
  163. vlog.info("Enabling TightVNC protocol extensions");
  164. cp.tightExtensionsEnabled = true;
  165. offerTunneling();
  166. } else {
  167. processSecurityType(secType);
  168. }
  169. }
  170. //
  171. // TightVNC-specific protocol initialization (tunneling, authentication)
  172. //
  173. void SConnection::offerTunneling()
  174. {
  175. vlog.debug("offering list of tunneling methods");
  176. int nTypes = 0;
  177. // Advertise our tunneling capabilities (currently, nothing to advertise).
  178. os->writeU32(nTypes);
  179. os->flush();
  180. if (nTypes) {
  181. // NOTE: Never executed in current version.
  182. state_ = RFBSTATE_TIGHT_TUNN_TYPE;
  183. } else {
  184. offerAuthentication();
  185. }
  186. }
  187. // NOTE: This function is never called in current version.
  188. void SConnection::processTunnelTypeMsg()
  189. {
  190. vlog.debug("processing tunneling type message (TightVNC extension)");
  191. int tunnelType = is->readU32();
  192. vlog.error("unsupported tunneling type %d requested, ignoring", tunnelType);
  193. offerAuthentication();
  194. }
  195. void SConnection::offerAuthentication()
  196. {
  197. vlog.debug("offering list of authentication methods");
  198. // See processVersionMsg(), the code below is similar.
  199. std::list<rdr::U8> secTypes;
  200. std::list<rdr::U8>::iterator i;
  201. // NOTE: In addition to standard security types, we might want to offer
  202. // TightVNC-specific authentication types. But currently we support
  203. // only the standard security types: secTypeNone and secTypeVncAuth.
  204. secTypes = security->GetEnabledSecTypes();
  205. CapsList caps;
  206. for (i = secTypes.begin(); i != secTypes.end(); i++) {
  207. // FIXME: Capability info should be provided by SSecurity objects.
  208. switch (*i) {
  209. case secTypeNone: caps.addStandard(*i, "NOAUTH__"); break;
  210. case secTypeVncAuth: caps.addStandard(*i, "VNCAUTH_"); break;
  211. default:
  212. // This should not ever happen.
  213. vlog.error("not offering unknown security type %d", (int)*i);
  214. }
  215. }
  216. if (caps.getSize() < 1)
  217. throwConnFailedException("No supported security types");
  218. if (caps.includesOnly(secTypeNone)) {
  219. // Special case - if caps includes nothing else than secTypeNone, we send
  220. // an empty capability list and do not expect security type selection from
  221. // the client. Then, continue the protocol like if the client has selected
  222. // secTypeNone (starting at base protocol version 3.8, "security result"
  223. // will follow).
  224. os->writeU32(0);
  225. os->flush();
  226. processSecurityType(secTypeNone);
  227. } else {
  228. // Normal case - sending the list of authentication capabilities.
  229. os->writeU32(caps.getSize());
  230. caps.write(os);
  231. os->flush();
  232. state_ = RFBSTATE_TIGHT_AUTH_TYPE;
  233. }
  234. }
  235. void SConnection::processAuthTypeMsg()
  236. {
  237. vlog.debug("processing authentication type message (TightVNC extension)");
  238. // NOTE: Currently, we support only the standard security types, so we
  239. // just pass TightVNC authentication type for standard processing,
  240. // just as it was usual RFB security type.
  241. int secType = is->readU32();
  242. processSecurityType(secType);
  243. }
  244. //
  245. // End of TightVNC-specific code
  246. //
  247. void SConnection::processSecurityType(int secType)
  248. {
  249. // Verify that the requested security type should be offered
  250. std::list<rdr::U8> secTypes;
  251. std::list<rdr::U8>::iterator i;
  252. secTypes = security->GetEnabledSecTypes();
  253. for (i=secTypes.begin(); i!=secTypes.end(); i++)
  254. if (*i == secType) break;
  255. if (i == secTypes.end())
  256. throw Exception("Requested security type not available");
  257. vlog.info("Client requests security type %s(%d)",
  258. secTypeName(secType),secType);
  259. try {
  260. state_ = RFBSTATE_SECURITY;
  261. ssecurity = security->GetSSecurity(secType);
  262. } catch (rdr::Exception& e) {
  263. throwConnFailedException(e.str());
  264. }
  265. processSecurityMsg();
  266. }
  267. void SConnection::processSecurityMsg()
  268. {
  269. vlog.debug("processing security message");
  270. try {
  271. bool done = ssecurity->processMsg(this);
  272. if (done) {
  273. state_ = RFBSTATE_QUERYING;
  274. queryConnection(ssecurity->getUserName());
  275. }
  276. } catch (AuthFailureException& e) {
  277. vlog.error("AuthFailureException: %s", e.str());
  278. os->writeU32(secResultFailed);
  279. if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
  280. os->writeString(e.str());
  281. os->flush();
  282. throw;
  283. }
  284. }
  285. void SConnection::processInitMsg()
  286. {
  287. vlog.debug("reading client initialisation");
  288. reader_->readClientInit();
  289. }
  290. void SConnection::throwConnFailedException(const char* msg)
  291. {
  292. vlog.info(msg);
  293. if (state_ == RFBSTATE_PROTOCOL_VERSION) {
  294. if (cp.majorVersion == 3 && cp.minorVersion == 3) {
  295. os->writeU32(0);
  296. os->writeString(msg);
  297. os->flush();
  298. } else {
  299. os->writeU8(0);
  300. os->writeString(msg);
  301. os->flush();
  302. }
  303. }
  304. state_ = RFBSTATE_INVALID;
  305. throw ConnFailedException(msg);
  306. }
  307. void SConnection::writeConnFailedFromScratch(const char* msg,
  308. rdr::OutStream* os)
  309. {
  310. os->writeBytes("RFB 003.003\n", 12);
  311. os->writeU32(0);
  312. os->writeString(msg);
  313. os->flush();
  314. }
  315. void SConnection::versionReceived()
  316. {
  317. }
  318. void SConnection::authSuccess()
  319. {
  320. }
  321. void SConnection::queryConnection(const char* userName)
  322. {
  323. approveConnection(true);
  324. }
  325. void SConnection::approveConnection(bool accept, const char* reason)
  326. {
  327. if (state_ != RFBSTATE_QUERYING)
  328. throw Exception("SConnection::approveConnection: invalid state");
  329. if (!reason) reason = "Authentication failure";
  330. if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
  331. if (accept) {
  332. os->writeU32(secResultOK);
  333. } else {
  334. os->writeU32(secResultFailed);
  335. if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
  336. os->writeString(reason);
  337. }
  338. os->flush();
  339. }
  340. if (accept) {
  341. state_ = RFBSTATE_INITIALISATION;
  342. reader_ = new SMsgReaderV3(this, is);
  343. writer_ = new SMsgWriterV3(&cp, os);
  344. authSuccess();
  345. } else {
  346. state_ = RFBSTATE_INVALID;
  347. throw AuthFailureException(reason);
  348. }
  349. }
  350. void SConnection::setInitialColourMap()
  351. {
  352. }
  353. void SConnection::clientInit(bool shared)
  354. {
  355. writer_->writeServerInit();
  356. // FIXME: Send interaction capabilities via writer_?
  357. if (cp.tightExtensionsEnabled)
  358. sendInteractionCaps();
  359. state_ = RFBSTATE_NORMAL;
  360. }
  361. // FIXME: Move sendInteractionCaps() to a class derived from SMsgWriterV3?
  362. void SConnection::sendInteractionCaps()
  363. {
  364. //
  365. // Advertise support for non-standard server-to-client messages
  366. //
  367. CapsList scaps;
  368. //
  369. // Advertise support for non-standard client-to-server messages
  370. //
  371. CapsList ccaps;
  372. //
  373. // Advertise all supported encoding types (except raw encoding).
  374. //
  375. CapsList ecaps;
  376. // First, add true encodings.
  377. for (int i = 1; i <= encodingMax; i++) {
  378. if (Encoder::supported(i)) {
  379. // FIXME: Capability info should be provided by Encoder objects.
  380. switch (i) {
  381. case encodingRRE: ecaps.addStandard(i, "RRE_____"); break;
  382. case encodingCoRRE: ecaps.addStandard(i, "CORRE___"); break;
  383. case encodingHextile: ecaps.addStandard(i, "HEXTILE_"); break;
  384. case encodingZRLE: ecaps.addStandard(i, "ZRLE____"); break;
  385. case encodingTight: ecaps.addTightExt(i, "TIGHT___"); break;
  386. default:
  387. // This should not ever happen.
  388. vlog.error("not advertising unknown encoding type %d", (int)i);
  389. }
  390. }
  391. }
  392. // CopyRect is special - Encoder::supported() returns 0 for it,
  393. // that's why we add it here explicitly.
  394. ecaps.addStandard(encodingCopyRect, "COPYRECT");
  395. // Add supported pseudo encodings as well.
  396. ecaps.addTightExt(pseudoEncodingCompressLevel0, "COMPRLVL");
  397. ecaps.addTightExt(pseudoEncodingQualityLevel0, "JPEGQLVL");
  398. ecaps.addTightExt(pseudoEncodingXCursor, "X11CURSR");
  399. ecaps.addTightExt(pseudoEncodingCursor, "RCHCURSR");
  400. ecaps.addTightExt(pseudoEncodingLastRect, "LASTRECT");
  401. ecaps.addStandard(pseudoEncodingDesktopSize, "NEWFBSIZ");
  402. os->writeU16(scaps.getSize());
  403. os->writeU16(ccaps.getSize());
  404. os->writeU16(ecaps.getSize());
  405. os->writeU16(0);
  406. if (scaps.getSize())
  407. scaps.write(os);
  408. if (ccaps.getSize())
  409. ccaps.write(os);
  410. if (ecaps.getSize())
  411. ecaps.write(os);
  412. os->flush();
  413. }
  414. void SConnection::setPixelFormat(const PixelFormat& pf)
  415. {
  416. SMsgHandler::setPixelFormat(pf);
  417. readyForSetColourMapEntries = true;
  418. }
  419. void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
  420. {
  421. if (!readyForSetColourMapEntries) {
  422. readyForSetColourMapEntries = true;
  423. if (!cp.pf().trueColour) {
  424. setInitialColourMap();
  425. }
  426. }
  427. }