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.

CConnection.cxx 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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/fenceTypes.h>
  22. #include <rfb/CMsgReader.h>
  23. #include <rfb/CMsgWriter.h>
  24. #include <rfb/CSecurity.h>
  25. #include <rfb/Security.h>
  26. #include <rfb/CConnection.h>
  27. #include <rfb/util.h>
  28. #include <rfb/LogWriter.h>
  29. using namespace rfb;
  30. static LogWriter vlog("CConnection");
  31. CConnection::CConnection()
  32. : csecurity(0), is(0), os(0), reader_(0), writer_(0),
  33. shared(false),
  34. state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false)
  35. {
  36. security = new SecurityClient();
  37. }
  38. CConnection::~CConnection()
  39. {
  40. if (csecurity) csecurity->destroy();
  41. delete reader_;
  42. reader_ = 0;
  43. delete writer_;
  44. writer_ = 0;
  45. }
  46. void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  47. {
  48. is = is_;
  49. os = os_;
  50. }
  51. void CConnection::initialiseProtocol()
  52. {
  53. state_ = RFBSTATE_PROTOCOL_VERSION;
  54. }
  55. void CConnection::processMsg()
  56. {
  57. switch (state_) {
  58. case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
  59. case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
  60. case RFBSTATE_SECURITY: processSecurityMsg(); break;
  61. case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
  62. case RFBSTATE_INITIALISATION: processInitMsg(); break;
  63. case RFBSTATE_NORMAL: reader_->readMsg(); break;
  64. case RFBSTATE_UNINITIALISED:
  65. throw Exception("CConnection::processMsg: not initialised yet?");
  66. default:
  67. throw Exception("CConnection::processMsg: invalid state");
  68. }
  69. }
  70. void CConnection::processVersionMsg()
  71. {
  72. vlog.debug("reading protocol version");
  73. bool done;
  74. if (!cp.readVersion(is, &done)) {
  75. state_ = RFBSTATE_INVALID;
  76. throw Exception("reading version failed: not an RFB server?");
  77. }
  78. if (!done) return;
  79. vlog.info("Server supports RFB protocol version %d.%d",
  80. cp.majorVersion, cp.minorVersion);
  81. // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
  82. if (cp.beforeVersion(3,3)) {
  83. vlog.error("Server gave unsupported RFB protocol version %d.%d",
  84. cp.majorVersion, cp.minorVersion);
  85. state_ = RFBSTATE_INVALID;
  86. throw Exception("Server gave unsupported RFB protocol version %d.%d",
  87. cp.majorVersion, cp.minorVersion);
  88. } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
  89. cp.setVersion(3,3);
  90. } else if (cp.afterVersion(3,8)) {
  91. cp.setVersion(3,8);
  92. }
  93. cp.writeVersion(os);
  94. state_ = RFBSTATE_SECURITY_TYPES;
  95. vlog.info("Using RFB protocol version %d.%d",
  96. cp.majorVersion, cp.minorVersion);
  97. }
  98. void CConnection::processSecurityTypesMsg()
  99. {
  100. vlog.debug("processing security types message");
  101. int secType = secTypeInvalid;
  102. std::list<rdr::U8> secTypes;
  103. secTypes = security->GetEnabledSecTypes();
  104. if (cp.isVersion(3,3)) {
  105. // legacy 3.3 server may only offer "vnc authentication" or "none"
  106. secType = is->readU32();
  107. if (secType == secTypeInvalid) {
  108. throwConnFailedException();
  109. } else if (secType == secTypeNone || secType == secTypeVncAuth) {
  110. std::list<rdr::U8>::iterator i;
  111. for (i = secTypes.begin(); i != secTypes.end(); i++)
  112. if (*i == secType) {
  113. secType = *i;
  114. break;
  115. }
  116. if (i == secTypes.end())
  117. secType = secTypeInvalid;
  118. } else {
  119. vlog.error("Unknown 3.3 security type %d", secType);
  120. throw Exception("Unknown 3.3 security type");
  121. }
  122. } else {
  123. // >=3.7 server will offer us a list
  124. int nServerSecTypes = is->readU8();
  125. if (nServerSecTypes == 0)
  126. throwConnFailedException();
  127. std::list<rdr::U8>::iterator j;
  128. for (int i = 0; i < nServerSecTypes; i++) {
  129. rdr::U8 serverSecType = is->readU8();
  130. vlog.debug("Server offers security type %s(%d)",
  131. secTypeName(serverSecType), serverSecType);
  132. /*
  133. * Use the first type sent by server which matches client's type.
  134. * It means server's order specifies priority.
  135. */
  136. if (secType == secTypeInvalid) {
  137. for (j = secTypes.begin(); j != secTypes.end(); j++)
  138. if (*j == serverSecType) {
  139. secType = *j;
  140. break;
  141. }
  142. }
  143. }
  144. // Inform the server of our decision
  145. if (secType != secTypeInvalid) {
  146. os->writeU8(secType);
  147. os->flush();
  148. vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
  149. }
  150. }
  151. if (secType == secTypeInvalid) {
  152. state_ = RFBSTATE_INVALID;
  153. vlog.error("No matching security types");
  154. throw Exception("No matching security types");
  155. }
  156. state_ = RFBSTATE_SECURITY;
  157. csecurity = security->GetCSecurity(secType);
  158. processSecurityMsg();
  159. }
  160. void CConnection::processSecurityMsg()
  161. {
  162. vlog.debug("processing security message");
  163. if (csecurity->processMsg(this)) {
  164. state_ = RFBSTATE_SECURITY_RESULT;
  165. processSecurityResultMsg();
  166. }
  167. }
  168. void CConnection::processSecurityResultMsg()
  169. {
  170. vlog.debug("processing security result message");
  171. int result;
  172. if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
  173. result = secResultOK;
  174. } else {
  175. if (!is->checkNoWait(1)) return;
  176. result = is->readU32();
  177. }
  178. switch (result) {
  179. case secResultOK:
  180. securityCompleted();
  181. return;
  182. case secResultFailed:
  183. vlog.debug("auth failed");
  184. break;
  185. case secResultTooMany:
  186. vlog.debug("auth failed - too many tries");
  187. break;
  188. default:
  189. throw Exception("Unknown security result from server");
  190. }
  191. CharArray reason;
  192. if (cp.beforeVersion(3,8))
  193. reason.buf = strDup("Authentication failure");
  194. else
  195. reason.buf = is->readString();
  196. state_ = RFBSTATE_INVALID;
  197. throw AuthFailureException(reason.buf);
  198. }
  199. void CConnection::processInitMsg()
  200. {
  201. vlog.debug("reading server initialisation");
  202. reader_->readServerInit();
  203. }
  204. void CConnection::throwConnFailedException()
  205. {
  206. state_ = RFBSTATE_INVALID;
  207. CharArray reason;
  208. reason.buf = is->readString();
  209. throw ConnFailedException(reason.buf);
  210. }
  211. void CConnection::securityCompleted()
  212. {
  213. state_ = RFBSTATE_INITIALISATION;
  214. reader_ = new CMsgReader(this, is);
  215. writer_ = new CMsgWriter(&cp, os);
  216. vlog.debug("Authentication success!");
  217. authSuccess();
  218. writer_->writeClientInit(shared);
  219. }
  220. void CConnection::authSuccess()
  221. {
  222. }
  223. void CConnection::serverInit()
  224. {
  225. state_ = RFBSTATE_NORMAL;
  226. vlog.debug("initialisation done");
  227. }
  228. void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
  229. {
  230. CMsgHandler::fence(flags, len, data);
  231. if (!(flags & fenceFlagRequest))
  232. return;
  233. // We cannot guarantee any synchronisation at this level
  234. flags = 0;
  235. writer()->writeFence(flags, len, data);
  236. }