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 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011-2019 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <rfb/Exception.h>
  22. #include <rfb/Security.h>
  23. #include <rfb/msgTypes.h>
  24. #include <rfb/fenceTypes.h>
  25. #include <rfb/SMsgReader.h>
  26. #include <rfb/SMsgWriter.h>
  27. #include <rfb/SConnection.h>
  28. #include <rfb/ServerCore.h>
  29. #include <rfb/encodings.h>
  30. #include <rfb/EncodeManager.h>
  31. #include <rfb/SSecurity.h>
  32. #include <rfb/LogWriter.h>
  33. using namespace rfb;
  34. static LogWriter vlog("SConnection");
  35. // AccessRights values
  36. const SConnection::AccessRights SConnection::AccessView = 0x0001;
  37. const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
  38. const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
  39. const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
  40. const SConnection::AccessRights SConnection::AccessSetDesktopSize = 0x0010;
  41. const SConnection::AccessRights SConnection::AccessNonShared = 0x0020;
  42. const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
  43. const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
  44. const SConnection::AccessRights SConnection::AccessFull = 0xffff;
  45. SConnection::SConnection()
  46. : readyForSetColourMapEntries(false),
  47. is(0), os(0), reader_(0), writer_(0),
  48. ssecurity(0), state_(RFBSTATE_UNINITIALISED),
  49. preferredEncoding(encodingRaw),
  50. clientClipboard(NULL)
  51. {
  52. defaultMajorVersion = 3;
  53. defaultMinorVersion = 8;
  54. if (rfb::Server::protocol3_3)
  55. defaultMinorVersion = 3;
  56. client.setVersion(defaultMajorVersion, defaultMinorVersion);
  57. }
  58. SConnection::~SConnection()
  59. {
  60. if (ssecurity)
  61. delete ssecurity;
  62. delete reader_;
  63. reader_ = 0;
  64. delete writer_;
  65. writer_ = 0;
  66. strFree(clientClipboard);
  67. }
  68. void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  69. {
  70. is = is_;
  71. os = os_;
  72. }
  73. void SConnection::initialiseProtocol()
  74. {
  75. char str[13];
  76. sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion);
  77. os->writeBytes(str, 12);
  78. os->flush();
  79. state_ = RFBSTATE_PROTOCOL_VERSION;
  80. }
  81. void SConnection::processMsg()
  82. {
  83. switch (state_) {
  84. case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
  85. case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
  86. case RFBSTATE_SECURITY: processSecurityMsg(); break;
  87. case RFBSTATE_INITIALISATION: processInitMsg(); break;
  88. case RFBSTATE_NORMAL: reader_->readMsg(); break;
  89. case RFBSTATE_QUERYING:
  90. throw Exception("SConnection::processMsg: bogus data from client while "
  91. "querying");
  92. case RFBSTATE_UNINITIALISED:
  93. throw Exception("SConnection::processMsg: not initialised yet?");
  94. default:
  95. throw Exception("SConnection::processMsg: invalid state");
  96. }
  97. }
  98. void SConnection::processVersionMsg()
  99. {
  100. char verStr[13];
  101. int majorVersion;
  102. int minorVersion;
  103. vlog.debug("reading protocol version");
  104. if (!is->checkNoWait(12))
  105. return;
  106. is->readBytes(verStr, 12);
  107. verStr[12] = '\0';
  108. if (sscanf(verStr, "RFB %03d.%03d\n",
  109. &majorVersion, &minorVersion) != 2) {
  110. state_ = RFBSTATE_INVALID;
  111. throw Exception("reading version failed: not an RFB client?");
  112. }
  113. client.setVersion(majorVersion, minorVersion);
  114. vlog.info("Client needs protocol version %d.%d",
  115. client.majorVersion, client.minorVersion);
  116. if (client.majorVersion != 3) {
  117. // unknown protocol version
  118. throwConnFailedException("Client needs protocol version %d.%d, server has %d.%d",
  119. client.majorVersion, client.minorVersion,
  120. defaultMajorVersion, defaultMinorVersion);
  121. }
  122. if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) {
  123. vlog.error("Client uses unofficial protocol version %d.%d",
  124. client.majorVersion,client.minorVersion);
  125. if (client.minorVersion >= 8)
  126. client.minorVersion = 8;
  127. else if (client.minorVersion == 7)
  128. client.minorVersion = 7;
  129. else
  130. client.minorVersion = 3;
  131. vlog.error("Assuming compatibility with version %d.%d",
  132. client.majorVersion,client.minorVersion);
  133. }
  134. versionReceived();
  135. std::list<rdr::U8> secTypes;
  136. std::list<rdr::U8>::iterator i;
  137. secTypes = security.GetEnabledSecTypes();
  138. if (client.isVersion(3,3)) {
  139. // cope with legacy 3.3 client only if "no authentication" or "vnc
  140. // authentication" is supported.
  141. for (i=secTypes.begin(); i!=secTypes.end(); i++) {
  142. if (*i == secTypeNone || *i == secTypeVncAuth) break;
  143. }
  144. if (i == secTypes.end()) {
  145. throwConnFailedException("No supported security type for %d.%d client",
  146. client.majorVersion, client.minorVersion);
  147. }
  148. os->writeU32(*i);
  149. if (*i == secTypeNone) os->flush();
  150. state_ = RFBSTATE_SECURITY;
  151. ssecurity = security.GetSSecurity(this, *i);
  152. processSecurityMsg();
  153. return;
  154. }
  155. // list supported security types for >=3.7 clients
  156. if (secTypes.empty())
  157. throwConnFailedException("No supported security types");
  158. os->writeU8(secTypes.size());
  159. for (i=secTypes.begin(); i!=secTypes.end(); i++)
  160. os->writeU8(*i);
  161. os->flush();
  162. state_ = RFBSTATE_SECURITY_TYPE;
  163. }
  164. void SConnection::processSecurityTypeMsg()
  165. {
  166. vlog.debug("processing security type message");
  167. int secType = is->readU8();
  168. processSecurityType(secType);
  169. }
  170. void SConnection::processSecurityType(int secType)
  171. {
  172. // Verify that the requested security type should be offered
  173. std::list<rdr::U8> secTypes;
  174. std::list<rdr::U8>::iterator i;
  175. secTypes = security.GetEnabledSecTypes();
  176. for (i=secTypes.begin(); i!=secTypes.end(); i++)
  177. if (*i == secType) break;
  178. if (i == secTypes.end())
  179. throw Exception("Requested security type not available");
  180. vlog.info("Client requests security type %s(%d)",
  181. secTypeName(secType),secType);
  182. try {
  183. state_ = RFBSTATE_SECURITY;
  184. ssecurity = security.GetSSecurity(this, secType);
  185. } catch (rdr::Exception& e) {
  186. throwConnFailedException("%s", e.str());
  187. }
  188. processSecurityMsg();
  189. }
  190. void SConnection::processSecurityMsg()
  191. {
  192. vlog.debug("processing security message");
  193. try {
  194. bool done = ssecurity->processMsg();
  195. if (done) {
  196. state_ = RFBSTATE_QUERYING;
  197. setAccessRights(ssecurity->getAccessRights());
  198. queryConnection(ssecurity->getUserName());
  199. }
  200. } catch (AuthFailureException& e) {
  201. vlog.error("AuthFailureException: %s", e.str());
  202. state_ = RFBSTATE_SECURITY_FAILURE;
  203. authFailure(e.str());
  204. }
  205. }
  206. void SConnection::processInitMsg()
  207. {
  208. vlog.debug("reading client initialisation");
  209. reader_->readClientInit();
  210. }
  211. void SConnection::throwConnFailedException(const char* format, ...)
  212. {
  213. va_list ap;
  214. char str[256];
  215. va_start(ap, format);
  216. (void) vsnprintf(str, sizeof(str), format, ap);
  217. va_end(ap);
  218. vlog.info("Connection failed: %s", str);
  219. if (state_ == RFBSTATE_PROTOCOL_VERSION) {
  220. if (client.majorVersion == 3 && client.minorVersion == 3) {
  221. os->writeU32(0);
  222. os->writeString(str);
  223. os->flush();
  224. } else {
  225. os->writeU8(0);
  226. os->writeString(str);
  227. os->flush();
  228. }
  229. }
  230. state_ = RFBSTATE_INVALID;
  231. throw ConnFailedException(str);
  232. }
  233. void SConnection::setAccessRights(AccessRights ar)
  234. {
  235. accessRights = ar;
  236. }
  237. bool SConnection::accessCheck(AccessRights ar) const
  238. {
  239. return (accessRights & ar) == ar;
  240. }
  241. void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
  242. {
  243. int i;
  244. preferredEncoding = encodingRaw;
  245. for (i = 0;i < nEncodings;i++) {
  246. if (EncodeManager::supported(encodings[i])) {
  247. preferredEncoding = encodings[i];
  248. break;
  249. }
  250. }
  251. SMsgHandler::setEncodings(nEncodings, encodings);
  252. }
  253. void SConnection::clientCutText(const char* str)
  254. {
  255. strFree(clientClipboard);
  256. clientClipboard = NULL;
  257. clientClipboard = latin1ToUTF8(str);
  258. handleClipboardAnnounce(true);
  259. }
  260. void SConnection::supportsQEMUKeyEvent()
  261. {
  262. writer()->writeQEMUKeyEvent();
  263. }
  264. void SConnection::versionReceived()
  265. {
  266. }
  267. void SConnection::authSuccess()
  268. {
  269. }
  270. void SConnection::authFailure(const char* reason)
  271. {
  272. if (state_ != RFBSTATE_SECURITY_FAILURE)
  273. throw Exception("SConnection::authFailure: invalid state");
  274. os->writeU32(secResultFailed);
  275. if (!client.beforeVersion(3,8)) // 3.8 onwards have failure message
  276. os->writeString(reason);
  277. os->flush();
  278. throw AuthFailureException(reason);
  279. }
  280. void SConnection::queryConnection(const char* userName)
  281. {
  282. approveConnection(true);
  283. }
  284. void SConnection::approveConnection(bool accept, const char* reason)
  285. {
  286. if (state_ != RFBSTATE_QUERYING)
  287. throw Exception("SConnection::approveConnection: invalid state");
  288. if (!client.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
  289. if (accept) {
  290. os->writeU32(secResultOK);
  291. } else {
  292. os->writeU32(secResultFailed);
  293. if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message
  294. if (reason)
  295. os->writeString(reason);
  296. else
  297. os->writeString("Authentication failure");
  298. }
  299. }
  300. os->flush();
  301. }
  302. if (accept) {
  303. state_ = RFBSTATE_INITIALISATION;
  304. reader_ = new SMsgReader(this, is);
  305. writer_ = new SMsgWriter(&client, os);
  306. authSuccess();
  307. } else {
  308. state_ = RFBSTATE_INVALID;
  309. if (reason)
  310. throw AuthFailureException(reason);
  311. else
  312. throw AuthFailureException();
  313. }
  314. }
  315. void SConnection::clientInit(bool shared)
  316. {
  317. writer_->writeServerInit(client.width(), client.height(),
  318. client.pf(), client.name());
  319. state_ = RFBSTATE_NORMAL;
  320. }
  321. void SConnection::close(const char* reason)
  322. {
  323. state_ = RFBSTATE_CLOSING;
  324. }
  325. void SConnection::setPixelFormat(const PixelFormat& pf)
  326. {
  327. SMsgHandler::setPixelFormat(pf);
  328. readyForSetColourMapEntries = true;
  329. if (!pf.trueColour)
  330. writeFakeColourMap();
  331. }
  332. void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
  333. {
  334. if (!readyForSetColourMapEntries) {
  335. readyForSetColourMapEntries = true;
  336. if (!client.pf().trueColour) {
  337. writeFakeColourMap();
  338. }
  339. }
  340. }
  341. void SConnection::fence(rdr::U32 flags, unsigned len, const char data[])
  342. {
  343. if (!(flags & fenceFlagRequest))
  344. return;
  345. // We cannot guarantee any synchronisation at this level
  346. flags = 0;
  347. writer()->writeFence(flags, len, data);
  348. }
  349. void SConnection::enableContinuousUpdates(bool enable,
  350. int x, int y, int w, int h)
  351. {
  352. }
  353. void SConnection::handleClipboardRequest()
  354. {
  355. }
  356. void SConnection::handleClipboardAnnounce(bool available)
  357. {
  358. }
  359. void SConnection::handleClipboardData(const char* data)
  360. {
  361. }
  362. void SConnection::requestClipboard()
  363. {
  364. if (clientClipboard != NULL) {
  365. handleClipboardData(clientClipboard);
  366. return;
  367. }
  368. }
  369. void SConnection::announceClipboard(bool available)
  370. {
  371. if (available)
  372. handleClipboardRequest();
  373. }
  374. void SConnection::sendClipboardData(const char* data)
  375. {
  376. CharArray latin1(utf8ToLatin1(data));
  377. writer()->writeServerCutText(latin1.buf);
  378. }
  379. void SConnection::writeFakeColourMap(void)
  380. {
  381. int i;
  382. rdr::U16 red[256], green[256], blue[256];
  383. for (i = 0;i < 256;i++)
  384. client.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);
  385. writer()->writeSetColourMapEntries(0, 256, red, green, blue);
  386. }