選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

SConnection.cxx 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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/clipboardTypes.h>
  24. #include <rfb/msgTypes.h>
  25. #include <rfb/fenceTypes.h>
  26. #include <rfb/SMsgReader.h>
  27. #include <rfb/SMsgWriter.h>
  28. #include <rfb/SConnection.h>
  29. #include <rfb/ServerCore.h>
  30. #include <rfb/encodings.h>
  31. #include <rfb/EncodeManager.h>
  32. #include <rfb/SSecurity.h>
  33. #include <rfb/LogWriter.h>
  34. using namespace rfb;
  35. static LogWriter vlog("SConnection");
  36. // AccessRights values
  37. const SConnection::AccessRights SConnection::AccessView = 0x0001;
  38. const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
  39. const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
  40. const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
  41. const SConnection::AccessRights SConnection::AccessSetDesktopSize = 0x0010;
  42. const SConnection::AccessRights SConnection::AccessNonShared = 0x0020;
  43. const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
  44. const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
  45. const SConnection::AccessRights SConnection::AccessFull = 0xffff;
  46. SConnection::SConnection()
  47. : readyForSetColourMapEntries(false),
  48. is(0), os(0), reader_(0), writer_(0), ssecurity(0),
  49. authFailureTimer(this, &SConnection::handleAuthFailureTimeout),
  50. state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw),
  51. clientClipboard(NULL), hasLocalClipboard(false)
  52. {
  53. defaultMajorVersion = 3;
  54. defaultMinorVersion = 8;
  55. if (rfb::Server::protocol3_3)
  56. defaultMinorVersion = 3;
  57. client.setVersion(defaultMajorVersion, defaultMinorVersion);
  58. }
  59. SConnection::~SConnection()
  60. {
  61. cleanup();
  62. }
  63. void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  64. {
  65. is = is_;
  66. os = os_;
  67. }
  68. void SConnection::initialiseProtocol()
  69. {
  70. char str[13];
  71. sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion);
  72. os->writeBytes(str, 12);
  73. os->flush();
  74. state_ = RFBSTATE_PROTOCOL_VERSION;
  75. }
  76. bool SConnection::processMsg()
  77. {
  78. switch (state_) {
  79. case RFBSTATE_PROTOCOL_VERSION: return processVersionMsg(); break;
  80. case RFBSTATE_SECURITY_TYPE: return processSecurityTypeMsg(); break;
  81. case RFBSTATE_SECURITY: return processSecurityMsg(); break;
  82. case RFBSTATE_SECURITY_FAILURE: return processSecurityFailure(); break;
  83. case RFBSTATE_INITIALISATION: return processInitMsg(); break;
  84. case RFBSTATE_NORMAL: return reader_->readMsg(); break;
  85. case RFBSTATE_QUERYING:
  86. throw Exception("SConnection::processMsg: bogus data from client while "
  87. "querying");
  88. case RFBSTATE_CLOSING:
  89. throw Exception("SConnection::processMsg: called while closing");
  90. case RFBSTATE_UNINITIALISED:
  91. throw Exception("SConnection::processMsg: not initialised yet?");
  92. default:
  93. throw Exception("SConnection::processMsg: invalid state");
  94. }
  95. }
  96. bool SConnection::processVersionMsg()
  97. {
  98. char verStr[13];
  99. int majorVersion;
  100. int minorVersion;
  101. vlog.debug("reading protocol version");
  102. if (!is->hasData(12))
  103. return false;
  104. is->readBytes(verStr, 12);
  105. verStr[12] = '\0';
  106. if (sscanf(verStr, "RFB %03d.%03d\n",
  107. &majorVersion, &minorVersion) != 2) {
  108. state_ = RFBSTATE_INVALID;
  109. throw Exception("reading version failed: not an RFB client?");
  110. }
  111. client.setVersion(majorVersion, minorVersion);
  112. vlog.info("Client needs protocol version %d.%d",
  113. client.majorVersion, client.minorVersion);
  114. if (client.majorVersion != 3) {
  115. // unknown protocol version
  116. throwConnFailedException("Client needs protocol version %d.%d, server has %d.%d",
  117. client.majorVersion, client.minorVersion,
  118. defaultMajorVersion, defaultMinorVersion);
  119. }
  120. if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) {
  121. vlog.error("Client uses unofficial protocol version %d.%d",
  122. client.majorVersion,client.minorVersion);
  123. if (client.minorVersion >= 8)
  124. client.minorVersion = 8;
  125. else if (client.minorVersion == 7)
  126. client.minorVersion = 7;
  127. else
  128. client.minorVersion = 3;
  129. vlog.error("Assuming compatibility with version %d.%d",
  130. client.majorVersion,client.minorVersion);
  131. }
  132. versionReceived();
  133. std::list<rdr::U8> secTypes;
  134. std::list<rdr::U8>::iterator i;
  135. secTypes = security.GetEnabledSecTypes();
  136. if (client.isVersion(3,3)) {
  137. // cope with legacy 3.3 client only if "no authentication" or "vnc
  138. // authentication" is supported.
  139. for (i=secTypes.begin(); i!=secTypes.end(); i++) {
  140. if (*i == secTypeNone || *i == secTypeVncAuth) break;
  141. }
  142. if (i == secTypes.end()) {
  143. throwConnFailedException("No supported security type for %d.%d client",
  144. client.majorVersion, client.minorVersion);
  145. }
  146. os->writeU32(*i);
  147. if (*i == secTypeNone) os->flush();
  148. state_ = RFBSTATE_SECURITY;
  149. ssecurity = security.GetSSecurity(this, *i);
  150. return true;
  151. }
  152. // list supported security types for >=3.7 clients
  153. if (secTypes.empty())
  154. throwConnFailedException("No supported security types");
  155. os->writeU8(secTypes.size());
  156. for (i=secTypes.begin(); i!=secTypes.end(); i++)
  157. os->writeU8(*i);
  158. os->flush();
  159. state_ = RFBSTATE_SECURITY_TYPE;
  160. return true;
  161. }
  162. bool SConnection::processSecurityTypeMsg()
  163. {
  164. vlog.debug("processing security type message");
  165. if (!is->hasData(1))
  166. return false;
  167. int secType = is->readU8();
  168. processSecurityType(secType);
  169. return true;
  170. }
  171. void SConnection::processSecurityType(int secType)
  172. {
  173. // Verify that the requested security type should be offered
  174. std::list<rdr::U8> secTypes;
  175. std::list<rdr::U8>::iterator i;
  176. secTypes = security.GetEnabledSecTypes();
  177. for (i=secTypes.begin(); i!=secTypes.end(); i++)
  178. if (*i == secType) break;
  179. if (i == secTypes.end())
  180. throw Exception("Requested security type not available");
  181. vlog.info("Client requests security type %s(%d)",
  182. secTypeName(secType),secType);
  183. try {
  184. state_ = RFBSTATE_SECURITY;
  185. ssecurity = security.GetSSecurity(this, secType);
  186. } catch (rdr::Exception& e) {
  187. throwConnFailedException("%s", e.str());
  188. }
  189. }
  190. bool SConnection::processSecurityMsg()
  191. {
  192. vlog.debug("processing security message");
  193. try {
  194. if (!ssecurity->processMsg())
  195. return false;
  196. } catch (AuthFailureException& e) {
  197. vlog.error("AuthFailureException: %s", e.str());
  198. state_ = RFBSTATE_SECURITY_FAILURE;
  199. // Introduce a slight delay of the authentication failure response
  200. // to make it difficult to brute force a password
  201. authFailureMsg.replaceBuf(strDup(e.str()));
  202. authFailureTimer.start(100);
  203. return true;
  204. }
  205. state_ = RFBSTATE_QUERYING;
  206. setAccessRights(ssecurity->getAccessRights());
  207. queryConnection(ssecurity->getUserName());
  208. // If the connection got approved right away then we can continue
  209. if (state_ == RFBSTATE_INITIALISATION)
  210. return true;
  211. // Otherwise we need to wait for the result
  212. // (or give up if if was rejected)
  213. return false;
  214. }
  215. bool SConnection::processSecurityFailure()
  216. {
  217. // Silently drop any data if we are currently delaying an
  218. // authentication failure response as otherwise we would close
  219. // the connection on unexpected data, and an attacker could use
  220. // that to detect our delayed state.
  221. if (!is->hasData(1))
  222. return false;
  223. is->skip(is->avail());
  224. return true;
  225. }
  226. bool SConnection::processInitMsg()
  227. {
  228. vlog.debug("reading client initialisation");
  229. return reader_->readClientInit();
  230. }
  231. bool SConnection::handleAuthFailureTimeout(Timer* t)
  232. {
  233. if (state_ != RFBSTATE_SECURITY_FAILURE) {
  234. close("SConnection::handleAuthFailureTimeout: invalid state");
  235. return false;
  236. }
  237. try {
  238. os->writeU32(secResultFailed);
  239. if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message
  240. const char* reason = authFailureMsg.buf;
  241. os->writeU32(strlen(reason));
  242. os->writeBytes(reason, strlen(reason));
  243. }
  244. os->flush();
  245. } catch (rdr::Exception& e) {
  246. close(e.str());
  247. return false;
  248. }
  249. close(authFailureMsg.buf);
  250. return false;
  251. }
  252. void SConnection::throwConnFailedException(const char* format, ...)
  253. {
  254. va_list ap;
  255. char str[256];
  256. va_start(ap, format);
  257. (void) vsnprintf(str, sizeof(str), format, ap);
  258. va_end(ap);
  259. vlog.info("Connection failed: %s", str);
  260. if (state_ == RFBSTATE_PROTOCOL_VERSION) {
  261. if (client.majorVersion == 3 && client.minorVersion == 3) {
  262. os->writeU32(0);
  263. os->writeU32(strlen(str));
  264. os->writeBytes(str, strlen(str));
  265. os->flush();
  266. } else {
  267. os->writeU8(0);
  268. os->writeU32(strlen(str));
  269. os->writeBytes(str, strlen(str));
  270. os->flush();
  271. }
  272. }
  273. state_ = RFBSTATE_INVALID;
  274. throw ConnFailedException(str);
  275. }
  276. void SConnection::setAccessRights(AccessRights ar)
  277. {
  278. accessRights = ar;
  279. }
  280. bool SConnection::accessCheck(AccessRights ar) const
  281. {
  282. return (accessRights & ar) == ar;
  283. }
  284. void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
  285. {
  286. int i;
  287. preferredEncoding = encodingRaw;
  288. for (i = 0;i < nEncodings;i++) {
  289. if (EncodeManager::supported(encodings[i])) {
  290. preferredEncoding = encodings[i];
  291. break;
  292. }
  293. }
  294. SMsgHandler::setEncodings(nEncodings, encodings);
  295. if (client.supportsEncoding(pseudoEncodingExtendedClipboard)) {
  296. rdr::U32 sizes[] = { 0 };
  297. writer()->writeClipboardCaps(rfb::clipboardUTF8 |
  298. rfb::clipboardRequest |
  299. rfb::clipboardPeek |
  300. rfb::clipboardNotify |
  301. rfb::clipboardProvide,
  302. sizes);
  303. }
  304. }
  305. void SConnection::clientCutText(const char* str)
  306. {
  307. strFree(clientClipboard);
  308. clientClipboard = NULL;
  309. clientClipboard = latin1ToUTF8(str);
  310. handleClipboardAnnounce(true);
  311. }
  312. void SConnection::handleClipboardRequest(rdr::U32 flags)
  313. {
  314. if (!(flags & rfb::clipboardUTF8))
  315. return;
  316. if (!hasLocalClipboard)
  317. return;
  318. handleClipboardRequest();
  319. }
  320. void SConnection::handleClipboardPeek(rdr::U32 flags)
  321. {
  322. if (!hasLocalClipboard)
  323. return;
  324. if (client.clipboardFlags() & rfb::clipboardNotify)
  325. writer()->writeClipboardNotify(rfb::clipboardUTF8);
  326. }
  327. void SConnection::handleClipboardNotify(rdr::U32 flags)
  328. {
  329. strFree(clientClipboard);
  330. clientClipboard = NULL;
  331. if (flags & rfb::clipboardUTF8)
  332. handleClipboardAnnounce(true);
  333. else
  334. handleClipboardAnnounce(false);
  335. }
  336. void SConnection::handleClipboardProvide(rdr::U32 flags,
  337. const size_t* lengths,
  338. const rdr::U8* const* data)
  339. {
  340. if (!(flags & rfb::clipboardUTF8))
  341. return;
  342. strFree(clientClipboard);
  343. clientClipboard = NULL;
  344. clientClipboard = convertLF((const char*)data[0], lengths[0]);
  345. handleClipboardData(clientClipboard);
  346. }
  347. void SConnection::supportsQEMUKeyEvent()
  348. {
  349. writer()->writeQEMUKeyEvent();
  350. }
  351. void SConnection::versionReceived()
  352. {
  353. }
  354. void SConnection::authSuccess()
  355. {
  356. }
  357. void SConnection::queryConnection(const char* userName)
  358. {
  359. approveConnection(true);
  360. }
  361. void SConnection::approveConnection(bool accept, const char* reason)
  362. {
  363. if (state_ != RFBSTATE_QUERYING)
  364. throw Exception("SConnection::approveConnection: invalid state");
  365. if (!client.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
  366. if (accept) {
  367. os->writeU32(secResultOK);
  368. } else {
  369. os->writeU32(secResultFailed);
  370. if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message
  371. if (!reason)
  372. reason = "Authentication failure";
  373. os->writeU32(strlen(reason));
  374. os->writeBytes(reason, strlen(reason));
  375. }
  376. }
  377. os->flush();
  378. }
  379. if (accept) {
  380. state_ = RFBSTATE_INITIALISATION;
  381. reader_ = new SMsgReader(this, is);
  382. writer_ = new SMsgWriter(&client, os);
  383. authSuccess();
  384. } else {
  385. state_ = RFBSTATE_INVALID;
  386. if (reason)
  387. throw AuthFailureException(reason);
  388. else
  389. throw AuthFailureException();
  390. }
  391. }
  392. void SConnection::clientInit(bool shared)
  393. {
  394. writer_->writeServerInit(client.width(), client.height(),
  395. client.pf(), client.name());
  396. state_ = RFBSTATE_NORMAL;
  397. }
  398. void SConnection::close(const char* reason)
  399. {
  400. state_ = RFBSTATE_CLOSING;
  401. cleanup();
  402. }
  403. void SConnection::setPixelFormat(const PixelFormat& pf)
  404. {
  405. SMsgHandler::setPixelFormat(pf);
  406. readyForSetColourMapEntries = true;
  407. if (!pf.trueColour)
  408. writeFakeColourMap();
  409. }
  410. void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
  411. {
  412. if (!readyForSetColourMapEntries) {
  413. readyForSetColourMapEntries = true;
  414. if (!client.pf().trueColour) {
  415. writeFakeColourMap();
  416. }
  417. }
  418. }
  419. void SConnection::fence(rdr::U32 flags, unsigned len, const char data[])
  420. {
  421. if (!(flags & fenceFlagRequest))
  422. return;
  423. // We cannot guarantee any synchronisation at this level
  424. flags = 0;
  425. writer()->writeFence(flags, len, data);
  426. }
  427. void SConnection::enableContinuousUpdates(bool enable,
  428. int x, int y, int w, int h)
  429. {
  430. }
  431. void SConnection::handleClipboardRequest()
  432. {
  433. }
  434. void SConnection::handleClipboardAnnounce(bool available)
  435. {
  436. }
  437. void SConnection::handleClipboardData(const char* data)
  438. {
  439. }
  440. void SConnection::requestClipboard()
  441. {
  442. if (clientClipboard != NULL) {
  443. handleClipboardData(clientClipboard);
  444. return;
  445. }
  446. if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
  447. (client.clipboardFlags() & rfb::clipboardRequest))
  448. writer()->writeClipboardRequest(rfb::clipboardUTF8);
  449. }
  450. void SConnection::announceClipboard(bool available)
  451. {
  452. hasLocalClipboard = available;
  453. if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
  454. (client.clipboardFlags() & rfb::clipboardNotify))
  455. writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
  456. else {
  457. if (available)
  458. handleClipboardRequest();
  459. }
  460. }
  461. void SConnection::sendClipboardData(const char* data)
  462. {
  463. if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
  464. (client.clipboardFlags() & rfb::clipboardProvide)) {
  465. CharArray filtered(convertCRLF(data));
  466. size_t sizes[1] = { strlen(filtered.buf) + 1 };
  467. const rdr::U8* data[1] = { (const rdr::U8*)filtered.buf };
  468. writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
  469. } else {
  470. CharArray latin1(utf8ToLatin1(data));
  471. writer()->writeServerCutText(latin1.buf);
  472. }
  473. }
  474. void SConnection::cleanup()
  475. {
  476. delete ssecurity;
  477. ssecurity = NULL;
  478. delete reader_;
  479. reader_ = NULL;
  480. delete writer_;
  481. writer_ = NULL;
  482. strFree(clientClipboard);
  483. clientClipboard = NULL;
  484. }
  485. void SConnection::writeFakeColourMap(void)
  486. {
  487. int i;
  488. rdr::U16 red[256], green[256], blue[256];
  489. for (i = 0;i < 256;i++)
  490. client.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);
  491. writer()->writeSetColourMapEntries(0, 256, red, green, blue);
  492. }